Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | |
| 6 * Abstract visitor for dart objects that can be passed as messages between any | |
| 7 * isolates. | |
|
Jennifer Messerly
2011/11/08 05:04:35
I'd add a TODO: we should get rid of a lot of this
jimhug
2011/11/08 15:39:01
+1 - But I'm also a little concerned about how we
| |
| 8 */ | |
| 5 class MessageTraverser { | 9 class MessageTraverser { |
| 6 static bool isPrimitive(x) { | 10 static bool isPrimitive(x) { |
| 7 return (x === null) || (x is String) || (x is num) || (x is bool); | 11 return (x === null) || (x is String) || (x is num) || (x is bool); |
| 8 } | 12 } |
| 9 | 13 |
| 10 MessageTraverser(); | 14 MessageTraverser(); |
| 11 | 15 |
| 16 /** Visitor's entry point. */ | |
| 12 traverse(var x) { | 17 traverse(var x) { |
| 13 if (isPrimitive(x)) return visitPrimitive(x); | 18 if (isPrimitive(x)) return visitPrimitive(x); |
| 14 _taggedObjects = new List(); | 19 _taggedObjects = new List(); |
| 15 var result; | 20 var result; |
| 16 try { | 21 try { |
| 17 result = _dispatch(x); | 22 result = _dispatch(x); |
| 18 } finally { | 23 } finally { |
| 19 _cleanup(); | 24 _cleanup(); |
| 20 } | 25 } |
| 21 return result; | 26 return result; |
| 22 } | 27 } |
| 23 | 28 |
| 29 /** Remove all information injected in the native objects by this visitor. */ | |
| 24 void _cleanup() { | 30 void _cleanup() { |
| 25 int len = _taggedObjects.length; | 31 int len = _taggedObjects.length; |
| 26 for (int i = 0; i < len; i++) { | 32 for (int i = 0; i < len; i++) { |
| 27 _clearAttachedInfo(_taggedObjects[i]); | 33 _clearAttachedInfo(_taggedObjects[i]); |
| 28 } | 34 } |
| 29 _taggedObjects = null; | 35 _taggedObjects = null; |
| 30 } | 36 } |
| 31 | 37 |
| 38 /** Injects into the native object some information used by the visitor. */ | |
| 32 void _attachInfo(var o, var info) { | 39 void _attachInfo(var o, var info) { |
| 33 _taggedObjects.add(o); | 40 _taggedObjects.add(o); |
| 34 _setAttachedInfo(o, info); | 41 _setAttachedInfo(o, info); |
| 35 } | 42 } |
| 36 | 43 |
| 44 /** Retrieves any information stored in the native object [o]. */ | |
| 37 _getInfo(var o) { | 45 _getInfo(var o) { |
| 38 return _getAttachedInfo(o); | 46 return _getAttachedInfo(o); |
| 39 } | 47 } |
| 40 | 48 |
| 41 _dispatch(var x) { | 49 _dispatch(var x) { |
| 42 if (isPrimitive(x)) return visitPrimitive(x); | 50 if (isPrimitive(x)) return visitPrimitive(x); |
| 43 if (x is List) return visitList(x); | 51 if (x is List) return visitList(x); |
| 44 if (x is Map) return visitMap(x); | 52 if (x is Map) return visitMap(x); |
| 45 if (x is SendPortImpl) return visitSendPort(x); | 53 if (x is SendPortImpl) return visitSendPort(x); |
| 46 if (x is ReceivePortImpl) return visitReceivePort(x); | 54 if (x is ReceivePortImpl) return visitReceivePort(x); |
| 47 if (x is ReceivePortSingleShotImpl) return visitReceivePortSingleShot(x); | 55 if (x is ReceivePortSingleShotImpl) return visitReceivePortSingleShot(x); |
| 48 // TODO(floitsch): make this a real exception. (which one)? | 56 // TODO(floitsch): make this a real exception. (which one)? |
| 49 throw "Message serialization: Illegal value $x passed"; | 57 throw "Message serialization: Illegal value $x passed"; |
| 50 } | 58 } |
| 51 | 59 |
| 52 abstract visitPrimitive(x); | 60 abstract visitPrimitive(x); |
| 53 abstract visitList(List x); | 61 abstract visitList(List x); |
| 54 abstract visitMap(Map x); | 62 abstract visitMap(Map x); |
| 55 abstract visitSendPort(SendPortImpl x); | 63 abstract visitSendPort(SendPortImpl x); |
| 56 abstract visitReceivePort(ReceivePortImpl x); | 64 abstract visitReceivePort(ReceivePortImpl x); |
| 57 abstract visitReceivePortSingleShot(ReceivePortSingleShotImpl x); | 65 abstract visitReceivePortSingleShot(ReceivePortSingleShotImpl x); |
| 58 | 66 |
| 59 List _taggedObjects; | 67 List _taggedObjects; |
| 60 | 68 |
| 61 _clearAttachedInfo(var obj) native; | 69 _clearAttachedInfo(var o) native |
| 62 _setAttachedInfo(var o, var info) native; | 70 "o['__MessageTraverser__attached_info__'] = (void 0);"; |
|
jimhug
2011/11/08 15:39:01
I'm going to have to get you to explain (void 0) t
Siggi Cherem (dart-lang)
2011/11/08 17:56:42
void is an operator that produces the side effects
| |
| 63 _getAttachedInfo(var o) native; | 71 |
| 72 _setAttachedInfo(var o, var info) native | |
| 73 "o['__MessageTraverser__attached_info__'] = info;"; | |
| 74 | |
| 75 _getAttachedInfo(var o) native | |
| 76 "return o['__MessageTraverser__attached_info__'];"; | |
| 64 } | 77 } |
| 65 | 78 |
| 79 /** A visitor that recursively copies a message. */ | |
| 66 class Copier extends MessageTraverser { | 80 class Copier extends MessageTraverser { |
| 67 Copier() : super(); | 81 Copier() : super(); |
| 68 | 82 |
| 69 visitPrimitive(x) => x; | 83 visitPrimitive(x) => x; |
| 70 | 84 |
| 71 List visitList(List list) { | 85 List visitList(List list) { |
| 72 List copy = _getInfo(list); | 86 List copy = _getInfo(list); |
| 73 if (copy !== null) return copy; | 87 if (copy !== null) return copy; |
| 74 | 88 |
| 75 int len = list.length; | 89 int len = list.length; |
| 90 | |
| 76 // TODO(floitsch): we loose the generic type of the List. | 91 // TODO(floitsch): we loose the generic type of the List. |
| 77 copy = new List(len); | 92 copy = new List(len); |
| 78 _attachInfo(list, copy); | 93 _attachInfo(list, copy); |
| 79 for (int i = 0; i < len; i++) { | 94 for (int i = 0; i < len; i++) { |
| 80 copy[i] = _dispatch(list[i]); | 95 copy[i] = _dispatch(list[i]); |
| 81 } | 96 } |
| 82 return copy; | 97 return copy; |
| 83 } | 98 } |
| 84 | 99 |
| 85 Map visitMap(Map map) { | 100 Map visitMap(Map map) { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 103 | 118 |
| 104 SendPort visitReceivePort(ReceivePortImpl port) { | 119 SendPort visitReceivePort(ReceivePortImpl port) { |
| 105 return port._toNewSendPort(); | 120 return port._toNewSendPort(); |
| 106 } | 121 } |
| 107 | 122 |
| 108 SendPort visitReceivePortSingleShot(ReceivePortSingleShotImpl port) { | 123 SendPort visitReceivePortSingleShot(ReceivePortSingleShotImpl port) { |
| 109 return port._toNewSendPort(); | 124 return port._toNewSendPort(); |
| 110 } | 125 } |
| 111 } | 126 } |
| 112 | 127 |
| 128 /** Visitor that serializes a message as a JSON array. */ | |
| 113 class Serializer extends MessageTraverser { | 129 class Serializer extends MessageTraverser { |
| 114 Serializer() : super(); | 130 Serializer() : super(); |
| 115 | 131 |
| 116 visitPrimitive(x) => x; | 132 visitPrimitive(x) => x; |
| 117 | 133 |
| 118 visitList(List list) { | 134 visitList(List list) { |
| 119 int copyId = _getInfo(list); | 135 int copyId = _getInfo(list); |
| 120 if (copyId !== null) return _makeRef(copyId); | 136 if (copyId !== null) return ['ref', copyId]; |
| 121 | 137 |
| 122 int id = _nextFreeRefId++; | 138 int id = _nextFreeRefId++; |
| 123 _attachInfo(list, id); | 139 _attachInfo(list, id); |
| 124 var jsArray = _serializeDartListIntoNewJsArray(list); | 140 var jsArray = _serializeList(list); |
| 125 // TODO(floitsch): we are losing the generic type. | 141 // TODO(floitsch): we are losing the generic type. |
| 126 return _dartListToJsArrayNoCopy(['list', id, jsArray]); | 142 return ['list', id, jsArray]; |
| 127 } | 143 } |
| 128 | 144 |
| 129 visitMap(Map map) { | 145 visitMap(Map map) { |
| 130 int copyId = _getInfo(map); | 146 int copyId = _getInfo(map); |
| 131 if (copyId !== null) return _makeRef(copyId); | 147 if (copyId !== null) return ['ref', copyId]; |
| 132 | 148 |
| 133 int id = _nextFreeRefId++; | 149 int id = _nextFreeRefId++; |
| 134 _attachInfo(map, id); | 150 _attachInfo(map, id); |
| 135 var keys = _serializeDartListIntoNewJsArray(map.getKeys()); | 151 var keys = _serializeList(map.getKeys()); |
| 136 var values = _serializeDartListIntoNewJsArray(map.getValues()); | 152 var values = _serializeList(map.getValues()); |
| 137 // TODO(floitsch): we are losing the generic type. | 153 // TODO(floitsch): we are losing the generic type. |
| 138 return _dartListToJsArrayNoCopy(['map', id, keys, values]); | 154 return ['map', id, keys, values]; |
| 139 } | 155 } |
| 140 | 156 |
| 141 visitSendPort(SendPortImpl port) { | 157 visitSendPort(SendPortImpl port) { |
| 142 return _dartListToJsArrayNoCopy(['sendport', | 158 return ['sendport', port._workerId, port._isolateId, port._receivePortId]; |
| 143 port._workerId, | |
| 144 port._isolateId, | |
| 145 port._receivePortId]); | |
| 146 } | 159 } |
| 147 | 160 |
| 148 visitReceivePort(ReceivePortImpl port) { | 161 visitReceivePort(ReceivePortImpl port) { |
| 149 return visitSendPort(port.toSendPort());; | 162 return visitSendPort(port.toSendPort());; |
| 150 } | 163 } |
| 151 | 164 |
| 152 visitReceivePortSingleShot(ReceivePortSingleShotImpl port) { | 165 visitReceivePortSingleShot(ReceivePortSingleShotImpl port) { |
| 153 return visitSendPort(port.toSendPort()); | 166 return visitSendPort(port.toSendPort()); |
| 154 } | 167 } |
| 155 | 168 |
| 156 _serializeDartListIntoNewJsArray(List list) { | 169 _serializeList(List list) { |
| 157 int len = list.length; | 170 int len = list.length; |
| 158 var jsArray = _newJsArray(len); | 171 var result = new List(len); |
| 159 for (int i = 0; i < len; i++) { | 172 for (int i = 0; i < len; i++) { |
| 160 _jsArrayIndexSet(jsArray, i, _dispatch(list[i])); | 173 result[i] = _dispatch(list[i]); |
| 161 } | 174 } |
| 162 return jsArray; | 175 return result; |
| 163 } | |
| 164 | |
| 165 _makeRef(int id) { | |
| 166 return _dartListToJsArrayNoCopy(['ref', id]); | |
| 167 } | 176 } |
| 168 | 177 |
| 169 int _nextFreeRefId = 0; | 178 int _nextFreeRefId = 0; |
| 170 | |
| 171 static _newJsArray(int len) native; | |
| 172 static _jsArrayIndexSet(jsArray, int index, val) native; | |
| 173 static _dartListToJsArrayNoCopy(List list) native; | |
| 174 } | 179 } |
| 175 | 180 |
| 181 /** Deserializes arrays created with [Serializer]. */ | |
| 176 class Deserializer { | 182 class Deserializer { |
| 177 Deserializer(); | 183 Deserializer(); |
| 178 | 184 |
| 179 static bool isPrimitive(x) { | 185 static bool isPrimitive(x) { |
| 180 return (x === null) || (x is String) || (x is num) || (x is bool); | 186 return (x === null) || (x is String) || (x is num) || (x is bool); |
| 181 } | 187 } |
| 182 | 188 |
| 183 deserialize(x) { | 189 deserialize(x) { |
| 184 if (isPrimitive(x)) return x; | 190 if (isPrimitive(x)) return x; |
| 185 // TODO(floitsch): this should be new HashMap<int, var|Dynamic>() | 191 // TODO(floitsch): this should be new HashMap<int, var|Dynamic>() |
| 186 _deserialized = new HashMap(); | 192 _deserialized = new HashMap(); |
| 187 return _deserializeHelper(x); | 193 return _deserializeHelper(x); |
| 188 } | 194 } |
| 189 | 195 |
| 190 _deserializeHelper(x) { | 196 _deserializeHelper(x) { |
| 191 if (isPrimitive(x)) return x; | 197 if (isPrimitive(x)) return x; |
| 192 assert(_isJsArray(x)); | 198 assert(x is List); |
| 193 switch (_jsArrayIndex(x, 0)) { | 199 switch (x[0]) { |
| 194 case 'ref': return _deserializeRef(x); | 200 case 'ref': return _deserializeRef(x); |
| 195 case 'list': return _deserializeList(x); | 201 case 'list': return _deserializeList(x); |
| 196 case 'map': return _deserializeMap(x); | 202 case 'map': return _deserializeMap(x); |
| 197 case 'sendport': return _deserializeSendPort(x); | 203 case 'sendport': return _deserializeSendPort(x); |
| 198 // TODO(floitsch): Use real exception (which one?). | 204 // TODO(floitsch): Use real exception (which one?). |
| 199 default: throw "Unexpected serialized object"; | 205 default: throw "Unexpected serialized object"; |
| 200 } | 206 } |
| 201 } | 207 } |
| 202 | 208 |
| 203 _deserializeRef(x) { | 209 _deserializeRef(List x) { |
| 204 int id = _jsArrayIndex(x, 1); | 210 int id = x[1]; |
| 205 var result = _deserialized[id]; | 211 var result = _deserialized[id]; |
| 206 assert(result !== null); | 212 assert(result !== null); |
| 207 return result; | 213 return result; |
| 208 } | 214 } |
| 209 | 215 |
| 210 List _deserializeList(x) { | 216 List _deserializeList(List x) { |
| 211 int id = _jsArrayIndex(x, 1); | 217 int id = x[1]; |
| 212 var jsArray = _jsArrayIndex(x, 2); | 218 // We rely on the fact that Dart-lists are directly mapped to Js-arrays. |
| 213 assert(_isJsArray(jsArray)); | 219 List dartList = x[2]; |
| 214 List dartList = _jsArrayToDartListNoCopy(jsArray); | |
| 215 _deserialized[id] = dartList; | 220 _deserialized[id] = dartList; |
| 216 int len = dartList.length; | 221 int len = dartList.length; |
| 217 for (int i = 0; i < len; i++) { | 222 for (int i = 0; i < len; i++) { |
| 218 dartList[i] = _deserializeHelper(dartList[i]); | 223 dartList[i] = _deserializeHelper(dartList[i]); |
| 219 } | 224 } |
| 220 return dartList; | 225 return dartList; |
| 221 } | 226 } |
| 222 | 227 |
| 223 Map _deserializeMap(x) { | 228 Map _deserializeMap(List x) { |
| 224 Map result = new Map(); | 229 Map result = new Map(); |
| 225 int id = _jsArrayIndex(x, 1); | 230 int id = x[1]; |
| 226 _deserialized[id] = result; | 231 _deserialized[id] = result; |
| 227 var keys = _jsArrayIndex(x, 2); | 232 List keys = x[2]; |
| 228 var values = _jsArrayIndex(x, 3); | 233 List values = x[3]; |
| 229 assert(_isJsArray(keys)); | 234 int len = keys.length; |
| 230 assert(_isJsArray(values)); | 235 assert(len == values.length); |
| 231 int len = _jsArrayLength(keys); | |
| 232 assert(len == _jsArrayLength(values)); | |
| 233 for (int i = 0; i < len; i++) { | 236 for (int i = 0; i < len; i++) { |
| 234 var key = _deserializeHelper(_jsArrayIndex(keys, i)); | 237 var key = _deserializeHelper(keys[i]); |
| 235 var value = _deserializeHelper(_jsArrayIndex(values, i)); | 238 var value = _deserializeHelper(values[i]); |
| 236 result[key] = value; | 239 result[key] = value; |
| 237 } | 240 } |
| 238 return result; | 241 return result; |
| 239 } | 242 } |
| 240 | 243 |
| 241 SendPort _deserializeSendPort(x) { | 244 SendPort _deserializeSendPort(List x) { |
| 242 int workerId = _jsArrayIndex(x, 1); | 245 int workerId = x[1]; |
| 243 int isolateId = _jsArrayIndex(x, 2); | 246 int isolateId = x[2]; |
| 244 int receivePortId = _jsArrayIndex(x, 3); | 247 int receivePortId = x[3]; |
| 245 return new SendPortImpl(workerId, isolateId, receivePortId); | 248 return new SendPortImpl(workerId, isolateId, receivePortId); |
| 246 } | 249 } |
| 247 | 250 |
| 248 List _jsArrayToDartListNoCopy(a) { | |
| 249 // We rely on the fact that Dart-lists are directly mapped to Js-arrays. | |
| 250 // TODO(floitsch): can we do better here? | |
| 251 assert(a is List); | |
| 252 return a; | |
| 253 } | |
| 254 | |
| 255 // TODO(floitsch): this should by Map<int, var> or Map<int, Dynamic>. | 251 // TODO(floitsch): this should by Map<int, var> or Map<int, Dynamic>. |
| 256 Map _deserialized; | 252 Map<int, Dynamic> _deserialized; |
| 257 | |
| 258 static bool _isJsArray(x) native; | |
| 259 static _jsArrayIndex(x, int index) native; | |
| 260 static int _jsArrayLength(x) native; | |
| 261 } | 253 } |
| OLD | NEW |