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

Side by Side Diff: sdk/lib/_internal/compiler/js_lib/isolate_serialization.dart

Issue 742873002: Isolates: allow sending of arbitrary objects in dart2js. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments and map-serialization fix. Created 6 years 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
OLDNEW
(Empty)
1 // Copyright (c) 2014, 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 part of _isolate_helper;
6
7 /// Serialize [message].
8 _serializeMessage(message) {
9 return new _Serializer().serialize(message);
10 }
11
12 /// Deserialize [message].
13 _deserializeMessage(message) {
14 return new _Deserializer().deserialize(message);
15 }
16
17 /// Clones the message.
18 ///
19 /// Contrary to a `_deserializeMessage(_serializeMessage(x))` the `_clone`
20 /// function will not try to adjust SendPort values and pass them through.
21 _clone(message) {
22 _Serializer serializer = new _Serializer(serializeSendPorts: false);
23 _Deserializer deserializer = new _Deserializer();
24 return deserializer.deserialize(serializer.serialize(message));
25 }
26
27 class _Serializer {
28 final bool _serializeSendPorts;
29 Map<dynamic, int> serializedObjectIds = new Map<dynamic, int>.identity();
30
31 _Serializer({serializeSendPorts: true})
32 : _serializeSendPorts = serializeSendPorts;
33
34 /// Returns a message that can be transmitted through web-worker channels.
35 serialize(x) {
36 if (isPrimitive(x)) return serializePrimitive(x);
37
38 int serializationId = serializedObjectIds[x];
39 if (serializationId != null) return makeRef(serializationId);
40
41 serializationId = serializedObjectIds.length;
42 serializedObjectIds[x] = serializationId;
43
44 if (x is JSIndexable) return serializeJSIndexable(x);
45 if (x is InternalMap) return serializeMap(x);
46
47 if (x is JSObject) return serializeJSObject(x);
48
49 // We should not have any interceptors any more.
50 if (x is Interceptor) unsupported(x);
51
52 if (x is RawReceivePort) {
53 unsupported(x, "RawReceivePorts can't be transmitted:");
54 }
55
56 // SendPorts need their workerIds adjusted (either during serialization or
57 // deserialization).
58 if (x is _NativeJsSendPort) return serializeJsSendPort(x);
59 if (x is _WorkerSendPort) return serializeWorkerSendPort(x);
60
61 if (x is Closure) return serializeClosure(x);
62
63 return serializeDartObject(x);
64 }
65
66 void unsupported(x, [String message]) {
67 if (message == null) message = "Can't transmit:";
68 throw new UnsupportedError("$message $x");
69 }
70
71 makeRef(int serializationId) => ["ref", serializationId];
72
73 bool isPrimitive(x) => x == null || x is String || x is num || x is bool;
74 serializePrimitive(primitive) => primitive;
75
76 serializeJSIndexable(JSIndexable indexable) {
77 // Strings are JSIndexable but should have been treated earlier.
78 assert(indexable is! String);
79 if (indexable is TypedData) {
80 return ["typed", indexable];
81 }
82 List serialized = serializeArray(indexable);
83 if (indexable is JSFixedArray) return ["fixed", serialized];
84 if (indexable is JSExtendableArray) return ["extendable", serialized];
85 // MutableArray check must be last, since JSFixedArray and JSExtendableArray
86 // extend JSMutableArray.
87 if (indexable is JSMutableArray) return ["mutable", serialized];
88 // The only JSArrays left are the const Lists (as in `const [1, 2]`).
89 if (indexable is JSArray) return ["const", serialized];
90 unsupported(indexable, "Can't serialize indexable: ");
91 return null;
92 }
93
94 serializeArray(JSArray x) {
95 List serialized = [];
96 serialized.length = x.length;
97 for (int i = 0; i < x.length; i++) {
98 serialized[i] = serialize(x[i]);
99 }
100 return serialized;
101 }
102
103 serializeArrayInPlace(JSArray x) {
104 for (int i = 0; i < x.length; i++) {
105 x[i] = serialize(x[i]);
106 }
107 return x;
108 }
109
110 serializeMap(Map x) {
111 return ['map',
112 x.keys.map(serialize).toList(),
113 x.values.map(serialize).toList()];
114 }
115
116 serializeJSObject(JSObject x) {
117 if (JS('bool', '#.constructor', x) &&
118 JS('bool', 'x.constructor !== Object')) {
Lasse Reichstein Nielsen 2014/11/24 15:37:05 Still document what the case is that you are guard
floitsch 2014/11/25 12:32:18 Changed comment to: // We only serialize direc
Lasse Reichstein Nielsen 2014/11/25 13:07:53 Not sure what "direct properties" mean. Is it "own
floitsch 2014/11/25 13:39:18 Done.
119 unsupported(x, "Only plain JS Objects are supported:");
120 }
121 List keys = JS('JSArray', 'Object.keys(#)', x);
122 List values = [];
123 values.length = keys.length;
124 for (int i = 0; i < keys.length; i++) {
125 values[i] = serialize(JS('', '#[#]', x, keys[i]));
126 }
127 return ['js-object', keys, values];
128 }
129
130 serializeWorkerSendPort(_WorkerSendPort x) {
131 if (_serializeSendPorts) {
132 return ['sendport', x._workerId, x._isolateId, x._receivePortId];
133 }
134 return ['raw sendport', x];
135 }
136
137 serializeJsSendPort(_NativeJsSendPort x) {
138 if (_serializeSendPorts) {
139 int workerId = _globalState.currentManagerId;
140 return ['sendport', workerId, x._isolateId, x._receivePort._id];
141 }
142 return ['raw sendport', x];
143 }
144
145 serializeCapability(CapabilityImpl x) => ['capability', x._id];
146
147 serializeClosure(Closure x) {
148 final name = IsolateNatives._getJSFunctionName(x);
149 if (name == null) {
150 unsupported(x, "Closures can't be transmitted:");
151 }
152 return ['function', name];
153 }
154
155 serializeDartObject(x) {
156 var classExtractor = JS_EMBEDDED_GLOBAL('', CLASS_ID_EXTRACTOR);
157 var fieldsExtractor = JS_EMBEDDED_GLOBAL('', CLASS_FIELDS_EXTRACTOR);
158 String classId = JS('String', '#(#)', classExtractor, x);
159 List fields = JS('JSArray', '#(#)', fieldsExtractor, x);
160 return ['dart', classId, serializeArrayInPlace(fields)];
161 }
162 }
163
164 class _Deserializer {
165 /// When `true`, encodes sendports specially so that they can be adjusted on
166 /// the receiving end.
167 ///
168 /// When `false`, sendports are cloned like any other object.
169 final bool _adjustSendPorts;
170
171 List<dynamic> deserializedObjects = new List<dynamic>();
172
173 _Deserializer({adjustSendPorts: true}) : _adjustSendPorts = adjustSendPorts;
174
175 /// Returns a message that can be transmitted through web-worker channels.
176 deserialize(x) {
177 if (isPrimitive(x)) return deserializePrimitive(x);
178
179 assert(x is List);
180 switch (x.first) {
181 case "ref": return deserializeRef(x);
182 case "typed": return deserializeTyped(x);
183 case "fixed": return deserializeFixed(x);
184 case "extendable": return deserializeExtendable(x);
185 case "mutable": return deserializeMutable(x);
186 case "const": return deserializeConst(x);
187 case "map": return deserializeMap(x);
188 case "sendport": return deserializeSendPort(x);
189 case "raw sendport": return deserializeRawSendPort(x);
190 case "js-object": return deserializeJSObject(x);
191 case "function": return deserializeClosure(x);
192 case "dart": return deserializeDartObject(x);
193 default: throw "couldn't deserialize: $x";
194 }
195 }
196
197 bool isPrimitive(x) => x == null || x is String || x is num || x is bool;
198 deserializePrimitive(x) => x;
199
200 // ['ref', id].
201 deserializeRef(x) {
202 assert(x[0] == 'ref');
203 int serializationId = x[1];
204 return deserializedObjects[serializationId];
205 }
206
207 // ['typed', <typed array>].
208 TypedData deserializeTyped(x) {
209 assert(x[0] == 'typed');
210 TypedData result = x[1];
211 deserializedObjects.add(result);
212 return result;
213 }
214
215 // Updates the given array in place with its deserialized content.
216 List deserializeArrayInPlace(JSArray x) {
217 for (int i = 0; i < x.length; i++) {
218 x[i] = deserialize(x[i]);
219 }
220 return x;
221 }
222
223 // ['fixed', <array>].
224 List deserializeFixed(x) {
225 assert(x[0] == 'fixed');
226 List result = x[1];
227 deserializedObjects.add(result);
228 return new JSArray.markFixed(deserializeArrayInPlace(result));
229 }
230
231 // ['extendable', <array>].
232 List deserializeExtendable(x) {
233 assert(x[0] == 'extendable');
234 List result = x[1];
235 deserializedObjects.add(result);
236 return new JSArray.markGrowable(deserializeArrayInPlace(result));
237 }
238
239 // ['mutable', <array>].
240 List deserializeMutable(x) {
241 assert(x[0] == 'mutable');
242 List result = x[1];
243 deserializedObjects.add(result);
244 return deserializeArrayInPlace(result);
245 }
246
247 // ['const', <array>].
248 List deserializeConst(x) {
249 assert(x[0] == 'const');
250 List result = x[1];
251 deserializedObjects.add(result);
252 // TODO(floitsch): need to mark list as non-changeable.
253 return new JSArray.markFixed(deserializeArrayInPlace(result));
254 }
255
256 // ['map', <key-list>, <value-list>].
257 Map deserializeMap(x) {
258 assert(x[0] == 'map');
259 List keys = x[1];
260 List values = x[2];
261 Map result = {};
262 deserializedObjects.add(result);
263 // We need to keep the order of how objects were serialized.
264 // First deserialize all keys, and then only deserialize the values.
265 keys = keys.map(deserialize).toList();
266
267 for (int i = 0; i < keys.length; i++) {
268 result[keys[i]] = deserialize(values[i]);
269 }
270 return result;
271 }
272
273 // ['sendport', <managerId>, <isolateId>, <receivePortId>].
274 SendPort deserializeSendPort(x) {
275 assert(x[0] == 'sendport');
276 int managerId = x[1];
277 int isolateId = x[2];
278 int receivePortId = x[3];
279 SendPort result;
280 // If two isolates are in the same manager, we use NativeJsSendPorts to
281 // deliver messages directly without using postMessage.
282 if (managerId == _globalState.currentManagerId) {
283 var isolate = _globalState.isolates[isolateId];
284 if (isolate == null) return null; // Isolate has been closed.
285 var receivePort = isolate.lookup(receivePortId);
286 if (receivePort == null) return null; // Port has been closed.
287 result = new _NativeJsSendPort(receivePort, isolateId);
288 } else {
289 result = new _WorkerSendPort(managerId, isolateId, receivePortId);
290 }
291 deserializedObjects.add(result);
292 return result;
293 }
294
295 // ['raw sendport', <sendport>].
296 SendPort deserializeRawSendPort(x) {
297 assert(x[0] == 'raw sendport');
298 SendPort result = x[1];
299 deserializedObjects.add(result);
300 return result;
301 }
302
303 // ['js-object', <key-list>, <value-list>].
304 deserializeJSObject(x) {
305 assert(x[0] == 'js-object');
306 List keys = x[1];
307 List values = x[2];
308 var o = JS('', '{}');
309 deserializedObjects.add(o);
310 for (int i = 0; i < keys.length; i++) {
311 JS('', '#[#]=#', o, keys[i], deserialize(values[i]));
312 }
313 return o;
314 }
315
316 // ['function', <name>].
317 Function deserializeClosure(x) {
318 assert(x[0] == 'function');
319 String name = x[1];
320 Function result = IsolateNatives._getJSFunctionFromName(name);
321 deserializedObjects.add(result);
322 return result;
323 }
324
325 // ['dart', <class-id>, <field-list>].
326 deserializeDartObject(x) {
327 assert(x[0] == 'dart');
328 String classId = x[1];
329 List fields = x[2];
330 var instanceFromClassId = JS_EMBEDDED_GLOBAL('', INSTANCE_FROM_CLASS_ID);
331 var initializeObject = JS_EMBEDDED_GLOBAL('', INITIALIZE_EMPTY_INSTANCE);
332
333 var emptyInstance = JS('', '#(#)', instanceFromClassId, classId);
334 deserializedObjects.add(emptyInstance);
335 deserializeArrayInPlace(fields);
336 return JS('', '#(#, #, #)',
337 initializeObject, classId, emptyInstance, fields);
338 }
339 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698