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 |