Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: lib/isolate/frog/messages.dart

Issue 10696091: Refactor the message serialization code a bit so we can start playing with it for JS interop purpos… (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Forgot file. Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | lib/isolate/frog/ports.dart » ('j') | lib/isolate/serialization.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 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 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 // Defines message visitors, serialization, and deserialization. 5 // Defines message visitors, serialization, and deserialization.
6 6
7 /** Serialize [message] (or simulate serialization). */ 7 /** Serialize [message] (or simulate serialization). */
8 _serializeMessage(message) { 8 _serializeMessage(message) {
9 if (_globalState.needSerialization) { 9 if (_globalState.needSerialization) {
10 return new _Serializer().traverse(message); 10 return new _JsSerializer().traverse(message);
11 } else { 11 } else {
12 return new _Copier().traverse(message); 12 return new _JsCopier().traverse(message);
13 } 13 }
14 } 14 }
15 15
16 /** Deserialize [message] (or simulate deserialization). */ 16 /** Deserialize [message] (or simulate deserialization). */
17 _deserializeMessage(message) { 17 _deserializeMessage(message) {
18 if (_globalState.needSerialization) { 18 if (_globalState.needSerialization) {
19 return new _Deserializer().deserialize(message); 19 return new _JsDeserializer().deserialize(message);
20 } else { 20 } else {
21 // Nothing more to do. 21 // Nothing more to do.
22 return message; 22 return message;
23 } 23 }
24 } 24 }
25 25
26 /** Abstract visitor for dart objects that can be sent as isolate messages. */ 26 class _JsSerializer extends _Serializer {
27 class _MessageTraverser {
28 27
29 List _taggedObjects; 28 _JsSerializer() : super() { _visited = new _JsVisitedMap(); }
30 29
31 _MessageTraverser(); 30 visitSendPort(SendPort x) {
32
33 /** Visitor's entry point. */
34 traverse(var x) {
35 if (isPrimitive(x)) return visitPrimitive(x);
36 _taggedObjects = new List();
37 var result;
38 try {
39 result = _dispatch(x);
40 } finally {
41 _cleanup();
42 }
43 return result;
44 }
45
46 /** Remove all information injected in the native objects by this visitor. */
47 void _cleanup() {
48 int len = _taggedObjects.length;
49 for (int i = 0; i < len; i++) {
50 _clearAttachedInfo(_taggedObjects[i]);
51 }
52 _taggedObjects = null;
53 }
54
55 /** Injects into the native object some information used by the visitor. */
56 void _attachInfo(var o, var info) {
57 _taggedObjects.add(o);
58 _setAttachedInfo(o, info);
59 }
60
61 /** Retrieves any information stored in the native object [o]. */
62 _getInfo(var o) {
63 return _getAttachedInfo(o);
64 }
65
66 _dispatch(var x) {
67 if (isPrimitive(x)) return visitPrimitive(x);
68 if (x is List) return visitList(x);
69 if (x is Map) return visitMap(x);
70 if (x is _NativeJsSendPort) return visitNativeJsSendPort(x); 31 if (x is _NativeJsSendPort) return visitNativeJsSendPort(x);
71 if (x is _WorkerSendPort) return visitWorkerSendPort(x); 32 if (x is _WorkerSendPort) return visitWorkerSendPort(x);
72 if (x is _BufferingSendPort) return visitBufferingSendPort(x); 33 if (x is _BufferingSendPort) return visitBufferingSendPort(x);
73 // TODO(floitsch): make this a real exception. (which one)?
74 throw "Message serialization: Illegal value $x passed";
75 }
76
77 abstract visitPrimitive(x);
78 abstract visitList(List x);
79 abstract visitMap(Map x);
80 abstract visitNativeJsSendPort(_NativeJsSendPort x);
81 abstract visitWorkerSendPort(_WorkerSendPort x);
82 abstract visitBufferingSendPort(_BufferingSendPort x);
83
84 _clearAttachedInfo(var o) native
85 "o['__MessageTraverser__attached_info__'] = (void 0);";
86
87 _setAttachedInfo(var o, var info) native
88 "o['__MessageTraverser__attached_info__'] = info;";
89
90 _getAttachedInfo(var o) native
91 "return o['__MessageTraverser__attached_info__'];";
92
93 _visitNativeOrWorkerPort(SendPort p) {
94 if (p is _NativeJsSendPort) return visitNativeJsSendPort(p);
95 if (p is _WorkerSendPort) return visitWorkerSendPort(p);
96 throw "Illegal underlying port $p"; 34 throw "Illegal underlying port $p";
97 } 35 }
98 36
99 static bool isPrimitive(x) { 37 visitNativeJsSendPort(_NativeJsSendPort port) {
100 return (x === null) || (x is String) || (x is num) || (x is bool); 38 return ['sendport', _globalState.currentManagerId,
101 } 39 port._isolateId, port._receivePort._id];
102 }
103
104
105 /** A visitor that recursively copies a message. */
106 class _Copier extends _MessageTraverser {
107 _Copier() : super();
108
109 visitPrimitive(x) => x;
110
111 List visitList(List list) {
112 List copy = _getInfo(list);
113 if (copy !== null) return copy;
114
115 int len = list.length;
116
117 // TODO(floitsch): we loose the generic type of the List.
118 copy = new List(len);
119 _attachInfo(list, copy);
120 for (int i = 0; i < len; i++) {
121 copy[i] = _dispatch(list[i]);
122 }
123 return copy;
124 } 40 }
125 41
126 Map visitMap(Map map) { 42 visitWorkerSendPort(_WorkerSendPort port) {
127 Map copy = _getInfo(map); 43 return ['sendport', port._workerId, port._isolateId, port._receivePortId];
128 if (copy !== null) return copy;
129
130 // TODO(floitsch): we loose the generic type of the map.
131 copy = new Map();
132 _attachInfo(map, copy);
133 map.forEach((key, val) {
134 copy[_dispatch(key)] = _dispatch(val);
135 });
136 return copy;
137 } 44 }
138 45
139 SendPort visitNativeJsSendPort(_NativeJsSendPort port) { 46 visitBufferingSendPort(_BufferingSendPort port) {
140 return new _NativeJsSendPort(port._receivePort, port._isolateId);
141 }
142
143 SendPort visitWorkerSendPort(_WorkerSendPort port) {
144 return new _WorkerSendPort(
145 port._workerId, port._isolateId, port._receivePortId);
146 }
147
148 SendPort visitBufferingSendPort(_BufferingSendPort port) {
149 if (port._port != null) { 47 if (port._port != null) {
150 return _visitNativeOrWorkerPort(port._port); 48 return visitSendPort(port._port);
151 } else { 49 } else {
152 // TODO(floitsch): Use real exception (which one?). 50 // TODO(floitsch): Use real exception (which one?).
153 throw 51 throw
154 "internal error: must call _waitForPendingPorts to ensure all" 52 "internal error: must call _waitForPendingPorts to ensure all"
155 " ports are resolved at this point."; 53 " ports are resolved at this point.";
156 } 54 }
157 } 55 }
56
vsm 2012/07/04 05:21:54 nit: extra newline
158 } 57 }
159 58
160 /** Visitor that serializes a message as a JSON array. */
161 class _Serializer extends _MessageTraverser {
162 int _nextFreeRefId = 0;
163 59
164 _Serializer() : super(); 60 class _JsCopier extends _Copier {
165 61
166 visitPrimitive(x) => x; 62 _JsCopier() : super() { _visited = new _JsVisitedMap(); }
167 63
168 visitList(List list) { 64 visitSendPort(SendPort x) {
169 int copyId = _getInfo(list); 65 if (x is _NativeJsSendPort) return visitNativeJsSendPort(x);
170 if (copyId !== null) return ['ref', copyId]; 66 if (x is _WorkerSendPort) return visitWorkerSendPort(x);
171 67 if (x is _BufferingSendPort) return visitBufferingSendPort(x);
172 int id = _nextFreeRefId++; 68 throw "Illegal underlying port $p";
173 _attachInfo(list, id);
174 var jsArray = _serializeList(list);
175 // TODO(floitsch): we are losing the generic type.
176 return ['list', id, jsArray];
177 } 69 }
178 70
179 visitMap(Map map) { 71 SendPort visitNativeJsSendPort(_NativeJsSendPort port) {
180 int copyId = _getInfo(map); 72 return new _NativeJsSendPort(port._receivePort, port._isolateId);
181 if (copyId !== null) return ['ref', copyId];
182
183 int id = _nextFreeRefId++;
184 _attachInfo(map, id);
185 var keys = _serializeList(map.getKeys());
186 var values = _serializeList(map.getValues());
187 // TODO(floitsch): we are losing the generic type.
188 return ['map', id, keys, values];
189 } 73 }
190 74
191 visitNativeJsSendPort(_NativeJsSendPort port) { 75 SendPort visitWorkerSendPort(_WorkerSendPort port) {
192 return ['sendport', _globalState.currentManagerId, 76 return new _WorkerSendPort(
193 port._isolateId, port._receivePort._id]; 77 port._workerId, port._isolateId, port._receivePortId);
194 } 78 }
195 79
196 visitWorkerSendPort(_WorkerSendPort port) { 80 SendPort visitBufferingSendPort(_BufferingSendPort port) {
197 return ['sendport', port._workerId, port._isolateId, port._receivePortId];
198 }
199
200 visitBufferingSendPort(_BufferingSendPort port) {
201 if (port._port != null) { 81 if (port._port != null) {
202 return _visitNativeOrWorkerPort(port._port); 82 return visitSendPort(port._port);
203 } else { 83 } else {
204 // TODO(floitsch): Use real exception (which one?). 84 // TODO(floitsch): Use real exception (which one?).
205 throw 85 throw
206 "internal error: must call _waitForPendingPorts to ensure all" 86 "internal error: must call _waitForPendingPorts to ensure all"
207 " ports are resolved at this point."; 87 " ports are resolved at this point.";
208 } 88 }
209 } 89 }
210 90
vsm 2012/07/04 05:21:54 nit: extra newline
211 _serializeList(List list) {
212 int len = list.length;
213 var result = new List(len);
214 for (int i = 0; i < len; i++) {
215 result[i] = _dispatch(list[i]);
216 }
217 return result;
218 }
219 } 91 }
220 92
221 /** Deserializes arrays created with [_Serializer]. */ 93 class _JsDeserializer extends _Deserializer {
222 class _Deserializer {
223 Map<int, Dynamic> _deserialized;
224 94
225 _Deserializer(); 95 SendPort deserializeSendPort(List x) {
226
227 static bool isPrimitive(x) {
228 return (x === null) || (x is String) || (x is num) || (x is bool);
229 }
230
231 deserialize(x) {
232 if (isPrimitive(x)) return x;
233 // TODO(floitsch): this should be new HashMap<int, var|Dynamic>()
234 _deserialized = new HashMap();
235 return _deserializeHelper(x);
236 }
237
238 _deserializeHelper(x) {
239 if (isPrimitive(x)) return x;
240 assert(x is List);
241 switch (x[0]) {
242 case 'ref': return _deserializeRef(x);
243 case 'list': return _deserializeList(x);
244 case 'map': return _deserializeMap(x);
245 case 'sendport': return _deserializeSendPort(x);
246 // TODO(floitsch): Use real exception (which one?).
247 default: throw "Unexpected serialized object";
248 }
249 }
250
251 _deserializeRef(List x) {
252 int id = x[1];
253 var result = _deserialized[id];
254 assert(result !== null);
255 return result;
256 }
257
258 List _deserializeList(List x) {
259 int id = x[1];
260 // We rely on the fact that Dart-lists are directly mapped to Js-arrays.
261 List dartList = x[2];
262 _deserialized[id] = dartList;
263 int len = dartList.length;
264 for (int i = 0; i < len; i++) {
265 dartList[i] = _deserializeHelper(dartList[i]);
266 }
267 return dartList;
268 }
269
270 Map _deserializeMap(List x) {
271 Map result = new Map();
272 int id = x[1];
273 _deserialized[id] = result;
274 List keys = x[2];
275 List values = x[3];
276 int len = keys.length;
277 assert(len == values.length);
278 for (int i = 0; i < len; i++) {
279 var key = _deserializeHelper(keys[i]);
280 var value = _deserializeHelper(values[i]);
281 result[key] = value;
282 }
283 return result;
284 }
285
286 SendPort _deserializeSendPort(List x) {
287 int managerId = x[1]; 96 int managerId = x[1];
288 int isolateId = x[2]; 97 int isolateId = x[2];
289 int receivePortId = x[3]; 98 int receivePortId = x[3];
290 // If two isolates are in the same manager, we use NativeJsSendPorts to 99 // If two isolates are in the same manager, we use NativeJsSendPorts to
291 // deliver messages directly without using postMessage. 100 // deliver messages directly without using postMessage.
292 if (managerId == _globalState.currentManagerId) { 101 if (managerId == _globalState.currentManagerId) {
293 var isolate = _globalState.isolates[isolateId]; 102 var isolate = _globalState.isolates[isolateId];
294 if (isolate == null) return null; // Isolate has been closed. 103 if (isolate == null) return null; // Isolate has been closed.
295 var receivePort = isolate.lookup(receivePortId); 104 var receivePort = isolate.lookup(receivePortId);
296 return new _NativeJsSendPort(receivePort, isolateId); 105 return new _NativeJsSendPort(receivePort, isolateId);
297 } else { 106 } else {
298 return new _WorkerSendPort(managerId, isolateId, receivePortId); 107 return new _WorkerSendPort(managerId, isolateId, receivePortId);
299 } 108 }
300 } 109 }
110
111 }
112
113 class _JsVisitedMap implements _MessageTraverserVisitedMap {
114 List tagged;
115
116 /** Retrieves any information stored in the native object [object]. */
117 operator[](var object) {
118 return _getAttachedInfo(object);
119 }
120
121 /** Injects some information into the native [object]. */
122 void operator[]=(var object, var info) {
123 tagged.add(object);
124 _setAttachedInfo(object, info);
125 }
126
127 /** Get ready to rumble. */
128 void reset() {
129 assert(tagged == null);
130 tagged = new List();
131 }
132
133 /** Remove all information injected in the native objects. */
134 cleanup() {
135 int length = tagged.length;
136 for (int i = 0, length = tagged.length; i < length; i++) {
vsm 2012/07/04 05:21:54 Redundant length = tagged.length.
kasperl 2012/07/04 05:50:14 Done.
137 _clearAttachedInfo(tagged[i]);
138 }
139 tagged = null;
140 }
141
142 _clearAttachedInfo(var o) native
143 "o['__MessageTraverser__attached_info__'] = (void 0);";
vsm 2012/07/04 05:21:54 I think this leaves the property on the object. T
kasperl 2012/07/04 05:50:14 This is intentional. We don't want to force the ob
144
145 _setAttachedInfo(var o, var info) native
146 "o['__MessageTraverser__attached_info__'] = info;";
147
148 _getAttachedInfo(var o) native
149 "return o['__MessageTraverser__attached_info__'];";
301 } 150 }
302 151
303 // only visible for testing purposes 152 // only visible for testing purposes
304 // TODO(sigmund): remove once we can disable privacy for testing (bug #1882) 153 // TODO(sigmund): remove once we can disable privacy for testing (bug #1882)
305 class TestingOnly { 154 class TestingOnly {
306 static copy(x) { 155 static copy(x) {
307 return new _Copier().traverse(x); 156 return new _JsCopier().traverse(x);
308 } 157 }
309 158
310 // only visible for testing purposes 159 // only visible for testing purposes
311 static serialize(x) { 160 static serialize(x) {
312 _Serializer serializer = new _Serializer(); 161 _Serializer serializer = new _JsSerializer();
313 _Deserializer deserializer = new _Deserializer(); 162 _Deserializer deserializer = new _JsDeserializer();
314 return deserializer.deserialize(serializer.traverse(x)); 163 return deserializer.deserialize(serializer.traverse(x));
315 } 164 }
316 } 165 }
OLDNEW
« no previous file with comments | « no previous file | lib/isolate/frog/ports.dart » ('j') | lib/isolate/serialization.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698