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

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: Change comment. 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);
sra1 2014/12/03 00:53:52 ByteData is a TypedData that is not indexable. Byt
floitsch 2014/12/04 16:16:19 Done.
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) {
sra1 2014/12/03 00:53:52 There are classes that implement this that are not
floitsch 2014/12/04 16:16:19 Done.
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()];
sra1 2014/12/03 00:53:52 Unfortunately this creates a second tear-off closu
floitsch 2014/12/04 16:16:19 Done.
114 }
115
116 serializeJSObject(JSObject x) {
117 // Don't serialize objects if their `constructor` property isn't `Object`
118 // or undefined/null.
119 // A different constructor is taken as a sign that the object has complex
120 // internal state, or that it is a function, and won't be serialized.
121 if (JS('bool', '!!(#.constructor)', x) &&
122 JS('bool', 'x.constructor !== Object')) {
123 unsupported(x, "Only plain JS Objects are supported:");
124 }
125 List keys = JS('JSArray', 'Object.keys(#)', x);
126 List values = [];
127 values.length = keys.length;
128 for (int i = 0; i < keys.length; i++) {
129 values[i] = serialize(JS('', '#[#]', x, keys[i]));
130 }
131 return ['js-object', keys, values];
132 }
133
134 serializeWorkerSendPort(_WorkerSendPort x) {
135 if (_serializeSendPorts) {
136 return ['sendport', x._workerId, x._isolateId, x._receivePortId];
137 }
138 return ['raw sendport', x];
139 }
140
141 serializeJsSendPort(_NativeJsSendPort x) {
142 if (_serializeSendPorts) {
143 int workerId = _globalState.currentManagerId;
144 return ['sendport', workerId, x._isolateId, x._receivePort._id];
145 }
146 return ['raw sendport', x];
147 }
148
149 serializeCapability(CapabilityImpl x) => ['capability', x._id];
150
151 serializeClosure(Closure x) {
152 final name = IsolateNatives._getJSFunctionName(x);
153 if (name == null) {
154 unsupported(x, "Closures can't be transmitted:");
155 }
156 return ['function', name];
157 }
158
159 serializeDartObject(x) {
160 var classExtractor = JS_EMBEDDED_GLOBAL('', CLASS_ID_EXTRACTOR);
161 var fieldsExtractor = JS_EMBEDDED_GLOBAL('', CLASS_FIELDS_EXTRACTOR);
162 String classId = JS('String', '#(#)', classExtractor, x);
163 List fields = JS('JSArray', '#(#)', fieldsExtractor, x);
164 return ['dart', classId, serializeArrayInPlace(fields)];
165 }
166 }
167
168 class _Deserializer {
169 /// When `true`, encodes sendports specially so that they can be adjusted on
170 /// the receiving end.
171 ///
172 /// When `false`, sendports are cloned like any other object.
173 final bool _adjustSendPorts;
174
175 List<dynamic> deserializedObjects = new List<dynamic>();
176
177 _Deserializer({adjustSendPorts: true}) : _adjustSendPorts = adjustSendPorts;
178
179 /// Returns a message that can be transmitted through web-worker channels.
180 deserialize(x) {
181 if (isPrimitive(x)) return deserializePrimitive(x);
182
183 if (x is! JSArray) throw new ArgumentError("Bad serialized message: $x");
184
185 switch (x.first) {
186 case "ref": return deserializeRef(x);
187 case "typed": return deserializeTyped(x);
188 case "fixed": return deserializeFixed(x);
189 case "extendable": return deserializeExtendable(x);
190 case "mutable": return deserializeMutable(x);
191 case "const": return deserializeConst(x);
192 case "map": return deserializeMap(x);
193 case "sendport": return deserializeSendPort(x);
194 case "raw sendport": return deserializeRawSendPort(x);
195 case "js-object": return deserializeJSObject(x);
196 case "function": return deserializeClosure(x);
197 case "dart": return deserializeDartObject(x);
198 default: throw "couldn't deserialize: $x";
199 }
200 }
201
202 bool isPrimitive(x) => x == null || x is String || x is num || x is bool;
203 deserializePrimitive(x) => x;
204
205 // ['ref', id].
206 deserializeRef(x) {
207 assert(x[0] == 'ref');
208 int serializationId = x[1];
209 return deserializedObjects[serializationId];
210 }
211
212 // ['typed', <typed array>].
213 TypedData deserializeTyped(x) {
214 assert(x[0] == 'typed');
215 TypedData result = x[1];
216 deserializedObjects.add(result);
217 return result;
218 }
219
220 // Updates the given array in place with its deserialized content.
221 List deserializeArrayInPlace(JSArray x) {
222 for (int i = 0; i < x.length; i++) {
223 x[i] = deserialize(x[i]);
224 }
225 return x;
226 }
227
228 // ['fixed', <array>].
229 List deserializeFixed(x) {
230 assert(x[0] == 'fixed');
231 List result = x[1];
232 deserializedObjects.add(result);
233 return new JSArray.markFixed(deserializeArrayInPlace(result));
234 }
235
236 // ['extendable', <array>].
237 List deserializeExtendable(x) {
238 assert(x[0] == 'extendable');
239 List result = x[1];
240 deserializedObjects.add(result);
241 return new JSArray.markGrowable(deserializeArrayInPlace(result));
242 }
243
244 // ['mutable', <array>].
245 List deserializeMutable(x) {
246 assert(x[0] == 'mutable');
247 List result = x[1];
248 deserializedObjects.add(result);
249 return deserializeArrayInPlace(result);
250 }
251
252 // ['const', <array>].
253 List deserializeConst(x) {
254 assert(x[0] == 'const');
255 List result = x[1];
256 deserializedObjects.add(result);
257 // TODO(floitsch): need to mark list as non-changeable.
258 return new JSArray.markFixed(deserializeArrayInPlace(result));
259 }
260
261 // ['map', <key-list>, <value-list>].
262 Map deserializeMap(x) {
263 assert(x[0] == 'map');
264 List keys = x[1];
265 List values = x[2];
266 Map result = {};
267 deserializedObjects.add(result);
268 // We need to keep the order of how objects were serialized.
269 // First deserialize all keys, and then only deserialize the values.
270 keys = keys.map(deserialize).toList();
271
272 for (int i = 0; i < keys.length; i++) {
273 result[keys[i]] = deserialize(values[i]);
274 }
275 return result;
276 }
277
278 // ['sendport', <managerId>, <isolateId>, <receivePortId>].
279 SendPort deserializeSendPort(x) {
280 assert(x[0] == 'sendport');
281 int managerId = x[1];
282 int isolateId = x[2];
283 int receivePortId = x[3];
284 SendPort result;
285 // If two isolates are in the same manager, we use NativeJsSendPorts to
286 // deliver messages directly without using postMessage.
287 if (managerId == _globalState.currentManagerId) {
288 var isolate = _globalState.isolates[isolateId];
289 if (isolate == null) return null; // Isolate has been closed.
290 var receivePort = isolate.lookup(receivePortId);
291 if (receivePort == null) return null; // Port has been closed.
292 result = new _NativeJsSendPort(receivePort, isolateId);
293 } else {
294 result = new _WorkerSendPort(managerId, isolateId, receivePortId);
295 }
296 deserializedObjects.add(result);
297 return result;
298 }
299
300 // ['raw sendport', <sendport>].
301 SendPort deserializeRawSendPort(x) {
302 assert(x[0] == 'raw sendport');
303 SendPort result = x[1];
304 deserializedObjects.add(result);
305 return result;
306 }
307
308 // ['js-object', <key-list>, <value-list>].
309 deserializeJSObject(x) {
310 assert(x[0] == 'js-object');
311 List keys = x[1];
312 List values = x[2];
313 var o = JS('', '{}');
314 deserializedObjects.add(o);
315 for (int i = 0; i < keys.length; i++) {
316 JS('', '#[#]=#', o, keys[i], deserialize(values[i]));
317 }
318 return o;
319 }
320
321 // ['function', <name>].
322 Function deserializeClosure(x) {
323 assert(x[0] == 'function');
324 String name = x[1];
325 Function result = IsolateNatives._getJSFunctionFromName(name);
326 deserializedObjects.add(result);
327 return result;
328 }
329
330 // ['dart', <class-id>, <field-list>].
331 deserializeDartObject(x) {
332 assert(x[0] == 'dart');
333 String classId = x[1];
334 List fields = x[2];
335 var instanceFromClassId = JS_EMBEDDED_GLOBAL('', INSTANCE_FROM_CLASS_ID);
336 var initializeObject = JS_EMBEDDED_GLOBAL('', INITIALIZE_EMPTY_INSTANCE);
337
338 var emptyInstance = JS('', '#(#)', instanceFromClassId, classId);
339 deserializedObjects.add(emptyInstance);
340 deserializeArrayInPlace(fields);
341 return JS('', '#(#, #, #)',
342 initializeObject, classId, emptyInstance, fields);
343 }
344 }
OLDNEW
« no previous file with comments | « sdk/lib/_internal/compiler/js_lib/isolate_helper.dart ('k') | sdk/lib/_internal/compiler/js_lib/js_helper.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698