| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 /** | |
| 6 * Abstract visitor for dart objects that can be passed as messages between any | |
| 7 * isolates. | |
| 8 */ | |
| 9 class MessageTraverser { | |
| 10 static bool isPrimitive(x) { | |
| 11 return (x === null) || (x is String) || (x is num) || (x is bool); | |
| 12 } | |
| 13 | |
| 14 MessageTraverser(); | |
| 15 | |
| 16 /** Visitor's entry point. */ | |
| 17 traverse(var x) { | |
| 18 if (isPrimitive(x)) return visitPrimitive(x); | |
| 19 _taggedObjects = new List(); | |
| 20 var result; | |
| 21 try { | |
| 22 result = _dispatch(x); | |
| 23 } finally { | |
| 24 _cleanup(); | |
| 25 } | |
| 26 return result; | |
| 27 } | |
| 28 | |
| 29 /** Remove all information injected in the native objects by this visitor. */ | |
| 30 void _cleanup() { | |
| 31 int len = _taggedObjects.length; | |
| 32 for (int i = 0; i < len; i++) { | |
| 33 _clearAttachedInfo(_taggedObjects[i]); | |
| 34 } | |
| 35 _taggedObjects = null; | |
| 36 } | |
| 37 | |
| 38 /** Injects into the native object some information used by the visitor. */ | |
| 39 void _attachInfo(var o, var info) { | |
| 40 _taggedObjects.add(o); | |
| 41 _setAttachedInfo(o, info); | |
| 42 } | |
| 43 | |
| 44 /** Retrieves any information stored in the native object [o]. */ | |
| 45 _getInfo(var o) { | |
| 46 return _getAttachedInfo(o); | |
| 47 } | |
| 48 | |
| 49 _dispatch(var x) { | |
| 50 if (isPrimitive(x)) return visitPrimitive(x); | |
| 51 if (x is List) return visitList(x); | |
| 52 if (x is Map) return visitMap(x); | |
| 53 if (x is NativeJsSendPort) return visitNativeJsSendPort(x); | |
| 54 if (x is WorkerSendPort) return visitWorkerSendPort(x); | |
| 55 if (x is BufferingSendPort) return visitBufferingSendPort(x); | |
| 56 if (x is ReceivePortImpl) return visitReceivePort(x); | |
| 57 if (x is ReceivePortSingleShotImpl) return visitReceivePortSingleShot(x); | |
| 58 // TODO(floitsch): make this a real exception. (which one)? | |
| 59 throw "Message serialization: Illegal value $x passed"; | |
| 60 } | |
| 61 | |
| 62 abstract visitPrimitive(x); | |
| 63 abstract visitList(List x); | |
| 64 abstract visitMap(Map x); | |
| 65 abstract visitNativeJsSendPort(NativeJsSendPort x); | |
| 66 abstract visitWorkerSendPort(WorkerSendPort x); | |
| 67 abstract visitBufferingSendPort(BufferingSendPort x); | |
| 68 abstract visitReceivePort(ReceivePortImpl x); | |
| 69 abstract visitReceivePortSingleShot(ReceivePortSingleShotImpl x); | |
| 70 | |
| 71 List _taggedObjects; | |
| 72 | |
| 73 _clearAttachedInfo(var o) native | |
| 74 "o['__MessageTraverser__attached_info__'] = (void 0);"; | |
| 75 | |
| 76 _setAttachedInfo(var o, var info) native | |
| 77 "o['__MessageTraverser__attached_info__'] = info;"; | |
| 78 | |
| 79 _getAttachedInfo(var o) native | |
| 80 "return o['__MessageTraverser__attached_info__'];"; | |
| 81 | |
| 82 _visitNativeOrWorkerPort(SendPort p) { | |
| 83 if (p is NativeJsSendPort) return visitNativeJsSendPort(p); | |
| 84 if (p is WorkerSendPort) return visitWorkerSendPort(p); | |
| 85 throw "Illegal underlying port $p"; | |
| 86 } | |
| 87 } | |
| 88 | |
| 89 /** A visitor that recursively copies a message. */ | |
| 90 class Copier extends MessageTraverser { | |
| 91 Copier() : super(); | |
| 92 | |
| 93 visitPrimitive(x) => x; | |
| 94 | |
| 95 List visitList(List list) { | |
| 96 List copy = _getInfo(list); | |
| 97 if (copy !== null) return copy; | |
| 98 | |
| 99 int len = list.length; | |
| 100 | |
| 101 // TODO(floitsch): we loose the generic type of the List. | |
| 102 copy = new List(len); | |
| 103 _attachInfo(list, copy); | |
| 104 for (int i = 0; i < len; i++) { | |
| 105 copy[i] = _dispatch(list[i]); | |
| 106 } | |
| 107 return copy; | |
| 108 } | |
| 109 | |
| 110 Map visitMap(Map map) { | |
| 111 Map copy = _getInfo(map); | |
| 112 if (copy !== null) return copy; | |
| 113 | |
| 114 // TODO(floitsch): we loose the generic type of the map. | |
| 115 copy = new Map(); | |
| 116 _attachInfo(map, copy); | |
| 117 map.forEach((key, val) { | |
| 118 copy[_dispatch(key)] = _dispatch(val); | |
| 119 }); | |
| 120 return copy; | |
| 121 } | |
| 122 | |
| 123 SendPort visitNativeJsSendPort(NativeJsSendPort port) { | |
| 124 return new NativeJsSendPort(port._receivePort, port._isolateId); | |
| 125 } | |
| 126 | |
| 127 SendPort visitWorkerSendPort(WorkerSendPort port) { | |
| 128 return new WorkerSendPort( | |
| 129 port._workerId, port._isolateId, port._receivePortId); | |
| 130 } | |
| 131 | |
| 132 SendPort visitBufferingSendPort(BufferingSendPort port) { | |
| 133 if (port._port != null) { | |
| 134 return _visitNativeOrWorkerPort(port._port); | |
| 135 } else { | |
| 136 // TODO(floitsch): Use real exception (which one?). | |
| 137 throw "internal error: must call _waitForPendingPorts to ensure all" | |
| 138 + " ports are resolved at this point."; | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 SendPort visitReceivePort(ReceivePortImpl port) { | |
| 143 return port.toSendPort(); | |
| 144 } | |
| 145 | |
| 146 SendPort visitReceivePortSingleShot(ReceivePortSingleShotImpl port) { | |
| 147 return port.toSendPort(); | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 /** Visitor that serializes a message as a JSON array. */ | |
| 152 class Serializer extends MessageTraverser { | |
| 153 Serializer() : super(); | |
| 154 | |
| 155 visitPrimitive(x) => x; | |
| 156 | |
| 157 visitList(List list) { | |
| 158 int copyId = _getInfo(list); | |
| 159 if (copyId !== null) return ['ref', copyId]; | |
| 160 | |
| 161 int id = _nextFreeRefId++; | |
| 162 _attachInfo(list, id); | |
| 163 var jsArray = _serializeList(list); | |
| 164 // TODO(floitsch): we are losing the generic type. | |
| 165 return ['list', id, jsArray]; | |
| 166 } | |
| 167 | |
| 168 visitMap(Map map) { | |
| 169 int copyId = _getInfo(map); | |
| 170 if (copyId !== null) return ['ref', copyId]; | |
| 171 | |
| 172 int id = _nextFreeRefId++; | |
| 173 _attachInfo(map, id); | |
| 174 var keys = _serializeList(map.getKeys()); | |
| 175 var values = _serializeList(map.getValues()); | |
| 176 // TODO(floitsch): we are losing the generic type. | |
| 177 return ['map', id, keys, values]; | |
| 178 } | |
| 179 | |
| 180 visitNativeJsSendPort(NativeJsSendPort port) { | |
| 181 return ['sendport', _globalState.currentWorkerId, | |
| 182 port._isolateId, port._receivePort._id]; | |
| 183 } | |
| 184 | |
| 185 visitWorkerSendPort(WorkerSendPort port) { | |
| 186 return ['sendport', port._workerId, port._isolateId, port._receivePortId]; | |
| 187 } | |
| 188 | |
| 189 visitBufferingSendPort(BufferingSendPort port) { | |
| 190 if (port._port != null) { | |
| 191 return _visitNativeOrWorkerPort(port._port); | |
| 192 } else { | |
| 193 // TODO(floitsch): Use real exception (which one?). | |
| 194 throw "internal error: must call _waitForPendingPorts to ensure all" | |
| 195 + " ports are resolved at this point."; | |
| 196 } | |
| 197 } | |
| 198 | |
| 199 visitReceivePort(ReceivePortImpl port) { | |
| 200 return visitNativeJsSendPort(port.toSendPort());; | |
| 201 } | |
| 202 | |
| 203 visitReceivePortSingleShot(ReceivePortSingleShotImpl port) { | |
| 204 return visitNativeJsSendPort(port.toSendPort()); | |
| 205 } | |
| 206 | |
| 207 _serializeList(List list) { | |
| 208 int len = list.length; | |
| 209 var result = new List(len); | |
| 210 for (int i = 0; i < len; i++) { | |
| 211 result[i] = _dispatch(list[i]); | |
| 212 } | |
| 213 return result; | |
| 214 } | |
| 215 | |
| 216 int _nextFreeRefId = 0; | |
| 217 } | |
| 218 | |
| 219 /** Visitor that finds all unresolved [SendPort]s in a message. */ | |
| 220 class PendingSendPortFinder extends MessageTraverser { | |
| 221 List<Future<SendPort>> ports; | |
| 222 PendingSendPortFinder() : super(), ports = []; | |
| 223 | |
| 224 visitPrimitive(x) {} | |
| 225 visitNativeJsSendPort(NativeJsSendPort port) {} | |
| 226 visitWorkerSendPort(WorkerSendPort port) {} | |
| 227 visitReceivePort(ReceivePortImpl port) {} | |
| 228 visitReceivePortSingleShot(ReceivePortSingleShotImpl port) {} | |
| 229 | |
| 230 visitList(List list) { | |
| 231 final visited = _getInfo(list); | |
| 232 if (visited !== null) return; | |
| 233 _attachInfo(list, true); | |
| 234 // TODO(sigmund): replace with the following: (bug #1660) | |
| 235 // list.forEach(_dispatch); | |
| 236 list.forEach((e) => _dispatch(e)); | |
| 237 } | |
| 238 | |
| 239 visitMap(Map map) { | |
| 240 final visited = _getInfo(map); | |
| 241 if (visited !== null) return; | |
| 242 | |
| 243 _attachInfo(map, true); | |
| 244 // TODO(sigmund): replace with the following: (bug #1660) | |
| 245 // map.getValues().forEach(_dispatch); | |
| 246 map.getValues().forEach((e) => _dispatch(e)); | |
| 247 } | |
| 248 | |
| 249 visitBufferingSendPort(BufferingSendPort port) { | |
| 250 if (port._port == null) { | |
| 251 ports.add(port._futurePort); | |
| 252 } | |
| 253 } | |
| 254 } | |
| 255 | |
| 256 | |
| 257 /** Deserializes arrays created with [Serializer]. */ | |
| 258 class Deserializer { | |
| 259 Deserializer(); | |
| 260 | |
| 261 static bool isPrimitive(x) { | |
| 262 return (x === null) || (x is String) || (x is num) || (x is bool); | |
| 263 } | |
| 264 | |
| 265 deserialize(x) { | |
| 266 if (isPrimitive(x)) return x; | |
| 267 // TODO(floitsch): this should be new HashMap<int, var|Dynamic>() | |
| 268 _deserialized = new HashMap(); | |
| 269 return _deserializeHelper(x); | |
| 270 } | |
| 271 | |
| 272 _deserializeHelper(x) { | |
| 273 if (isPrimitive(x)) return x; | |
| 274 assert(x is List); | |
| 275 switch (x[0]) { | |
| 276 case 'ref': return _deserializeRef(x); | |
| 277 case 'list': return _deserializeList(x); | |
| 278 case 'map': return _deserializeMap(x); | |
| 279 case 'sendport': return _deserializeSendPort(x); | |
| 280 // TODO(floitsch): Use real exception (which one?). | |
| 281 default: throw "Unexpected serialized object"; | |
| 282 } | |
| 283 } | |
| 284 | |
| 285 _deserializeRef(List x) { | |
| 286 int id = x[1]; | |
| 287 var result = _deserialized[id]; | |
| 288 assert(result !== null); | |
| 289 return result; | |
| 290 } | |
| 291 | |
| 292 List _deserializeList(List x) { | |
| 293 int id = x[1]; | |
| 294 // We rely on the fact that Dart-lists are directly mapped to Js-arrays. | |
| 295 List dartList = x[2]; | |
| 296 _deserialized[id] = dartList; | |
| 297 int len = dartList.length; | |
| 298 for (int i = 0; i < len; i++) { | |
| 299 dartList[i] = _deserializeHelper(dartList[i]); | |
| 300 } | |
| 301 return dartList; | |
| 302 } | |
| 303 | |
| 304 Map _deserializeMap(List x) { | |
| 305 Map result = new Map(); | |
| 306 int id = x[1]; | |
| 307 _deserialized[id] = result; | |
| 308 List keys = x[2]; | |
| 309 List values = x[3]; | |
| 310 int len = keys.length; | |
| 311 assert(len == values.length); | |
| 312 for (int i = 0; i < len; i++) { | |
| 313 var key = _deserializeHelper(keys[i]); | |
| 314 var value = _deserializeHelper(values[i]); | |
| 315 result[key] = value; | |
| 316 } | |
| 317 return result; | |
| 318 } | |
| 319 | |
| 320 SendPort _deserializeSendPort(List x) { | |
| 321 int workerId = x[1]; | |
| 322 int isolateId = x[2]; | |
| 323 int receivePortId = x[3]; | |
| 324 // If two isolates are in the same worker, we use NativeJsSendPorts to | |
| 325 // deliver messages directly without using postMessage. | |
| 326 if (workerId == _globalState.currentWorkerId) { | |
| 327 var isolate = _globalState.isolates[isolateId]; | |
| 328 if (isolate == null) return null; // Isolate has been closed. | |
| 329 var receivePort = isolate.lookup(receivePortId); | |
| 330 return new NativeJsSendPort(receivePort, isolateId); | |
| 331 } else { | |
| 332 return new WorkerSendPort(workerId, isolateId, receivePortId); | |
| 333 } | |
| 334 } | |
| 335 | |
| 336 Map<int, Dynamic> _deserialized; | |
| 337 } | |
| OLD | NEW |