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

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: Remove unnecessary 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 id = serializedObjectIds[x];
39 if (id != null) return makeRef(id);
40
41 id = serializedObjectIds.length;
42 serializedObjectIds[x] = id;
43
44 if (x is JSIndexable) return serializeJSIndexable(x, id);
45 if (x is InternalMap) return serializeMap(x, id);
46
47 if (x is JSObject) return serializeJSObject(x, id);
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, id);
59 if (x is _WorkerSendPort) return serializeWorkerSendPort(x, id);
60
61 if (x is Closure) return serializeClosure(x, id);
62
63 return serializeAny(x, id);
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 id) => ["ref", id];
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, int id) {
77 // Strings are JSIndexable but should have been treated earlier.
78 assert(indexable is! String);
79 if (indexable is TypedData) {
80 return ["typed", id, indexable];
81 }
82 List serialized = serializeArray(indexable);
83 if (indexable is JSFixedArray) return ["fixed", id, serialized];
84 if (indexable is JSExtendableArray) return ["extendable", id, serialized];
85 // MutableArray check must be last, since JSFixedArray and JSExtendableArray
86 // extend JSMutableArray.
87 if (indexable is JSMutableArray) return ["mutable", id, serialized];
88 if (indexable is JSArray) return ["const", id, serialized];
sigurdm 2014/11/24 09:06:09 Maybe use a different keyword. 'const' has a certa
Lasse Reichstein Nielsen 2014/11/24 12:55:41 This is a const array (created using `const[...]`)
floitsch 2014/11/24 15:06:57 This is the const List (as in const [1, 2]). Since
floitsch 2014/11/24 15:06:57 Yes. Since it is not a JSMutableArray it must be c
89 unsupported(indexable, "Can't serialize indexable: ");
90 return null;
91 }
92
93 serializeArray(JSArray x) {
94 List serialized = [];
95 serialized.length = x.length;
96 for (int i = 0; i < x.length; i++) {
97 serialized[i] = serialize(x[i]);
98 }
99 return serialized;
100 }
101
102 serializeArrayInPlace(JSArray x) {
103 for (int i = 0; i < x.length; i++) {
104 x[i] = serialize(x[i]);
105 }
106 return x;
107 }
108
109 serializeMap(Map x, int id) {
110 return ['map', id,
Lasse Reichstein Nielsen 2014/11/24 12:55:42 Do you have to send the id with the object - can't
floitsch 2014/11/24 15:06:57 I thought it would be less brittle with the ids, b
111 x.keys.map(serialize).toList(),
112 x.values.map(serialize).toList()];
113 }
114
115 serializeJSObject(JSObject x, int id) {
116 // TODO(floitsch): weed out more JS objects.
Lasse Reichstein Nielsen 2014/11/24 12:55:41 Document what you are trying to guard against. The
floitsch 2014/11/24 15:06:57 Changed to checking the constructor, which is what
117 if (JS('bool', '(typeof #.__proto__) !== "undefined"', x) &&
118 JS('bool', '(typeof #.__proto__) !== "object"', x)) {
Lasse Reichstein Nielsen 2014/11/24 12:55:41 Are there any prototypes that don't have typeof "o
floitsch 2014/11/24 15:06:56 Functions have "function" as type for the prototyp
119 unsupported(x, "Only JS Objects without custom prototype 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', id, keys, values];
128 }
129
130 serializeWorkerSendPort(_WorkerSendPort x, int id) {
131 if (_serializeSendPorts) {
132 return ['sendport', id, x._workerId, x._isolateId, x._receivePortId];
133 }
134 return ['raw sendport', x];
135 }
136
137 serializeJsSendPort(_NativeJsSendPort x, int id) {
138 if (_serializeSendPorts) {
139 int workerId = _globalState.currentManagerId;
140 return ['sendport', id, workerId, x._isolateId, x._receivePort._id];
141 }
142 return ['raw sendport', x];
143 }
144
145 serializeCapability(CapabilityImpl x, int id) => ['capability', id, x._id];
146
147 serializeClosure(Closure x, int id) {
148 final name = IsolateNatives._getJSFunctionName(x);
149 if (name == null) {
150 unsupported(x, "Closures can't be transmitted:");
151 }
152 return ['function', id, name];
153 }
154
155 serializeAny(x, int id) {
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 ['any', id, 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 Map<int, dynamic> deserializedObjects = new Map<int, 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 "any": return deserializeAny(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 id = x[1];
204 return deserializedObjects[id];
205 }
206
207 // ['typed', id, <typed array>].
208 TypedData deserializeTyped(x) {
209 assert(x[0] == 'typed');
210 int id = x[1];
211 TypedData result = x[2];
212 deserializedObjects[id] = result;
213 return result;
214 }
215
216 // Updates the given array in place with its deserialized content.
217 List deserializeArrayInPlace(JSArray x) {
218 for (int i = 0; i < x.length; i++) {
219 x[i] = deserialize(x[i]);
220 }
221 return x;
222 }
223
224 // ['fixed', id, <array>].
225 List deserializeFixed(x) {
226 assert(x[0] == 'fixed');
227 int id = x[1];
228 List result = x[2];
229 deserializedObjects[id] = result;
230 return new JSArray.markFixed(deserializeArrayInPlace(result));
231 }
232
233 // ['extendable', id, <array>].
234 List deserializeExtendable(x) {
235 assert(x[0] == 'extendable');
236 int id = x[1];
237 List result = x[2];
238 deserializedObjects[id] = result;
239 return new JSArray.markGrowable(deserializeArrayInPlace(result));
240 }
241
242 // ['mutable', id, <array>].
243 List deserializeMutable(x) {
244 assert(x[0] == 'mutable');
245 int id = x[1];
246 List result = x[2];
247 deserializedObjects[id] = result;
248 return deserializeArrayInPlace(result);
249 }
250
251 // ['const', id, <array>].
252 List deserializeConst(x) {
253 assert(x[0] == 'const');
254 int id = x[1];
255 List result = x[2];
256 deserializedObjects[id] = result;
257 // TODO(floitsch): need to mark list as non-changeable.
258 return new JSArray.markFixed(deserializeArrayInPlace(result));
259 }
260
261 // ['map', id, <key-list>, <value-list>].
262 Map deserializeMap(x) {
263 assert(x[0] == 'map');
264 int id = x[1];
265 List keys = x[2];
266 List values = x[3];
267 Map result = {};
268 deserializedObjects[x[1]] = result;
269 for (int i = 0; i < keys.length; i++) {
270 result[deserialize(keys[i])] = deserialize(values[i]);
271 }
272 return result;
Lasse Reichstein Nielsen 2014/11/24 12:55:41 This special casing of just a single Map implement
floitsch 2014/11/24 15:06:56 This is just a special case for the extremely comm
273 }
274
275 // ['sendport', id, <managerId>, <isolateId>, <receivePortId>].
276 SendPort deserializeSendPort(x) {
277 assert(x[0] == 'sendport');
278 int id = x[1];
279 int managerId = x[2];
280 int isolateId = x[3];
281 int receivePortId = x[4];
282 SendPort result;
283 // If two isolates are in the same manager, we use NativeJsSendPorts to
284 // deliver messages directly without using postMessage.
285 if (managerId == _globalState.currentManagerId) {
286 var isolate = _globalState.isolates[isolateId];
287 if (isolate == null) return null; // Isolate has been closed.
288 var receivePort = isolate.lookup(receivePortId);
289 if (receivePort == null) return null; // Port has been closed.
290 result = new _NativeJsSendPort(receivePort, isolateId);
291 } else {
292 result = new _WorkerSendPort(managerId, isolateId, receivePortId);
293 }
294 deserializedObjects[id] = result;
295 return result;
296 }
297
298 // ['raw sendport', <sendport>].
299 SendPort deserializeRawSendPort(x) {
300 assert(x[0] == 'raw sendport');
301 return x[1];
Lasse Reichstein Nielsen 2014/11/24 12:55:41 This means the SendPort preserves its identity whe
floitsch 2014/11/24 15:06:57 Yes. But anything else would have required big ref
302 }
303
304 // ['js-object', id, <key-list>, <value-list>].
305 deserializeJSObject(x) {
306 assert(x[0] == 'js-object');
307 int id = x[1];
308 List keys = x[2];
309 List values = x[3];
310 var o = JS('', '{}');
311 deserializedObjects[id] = o;
312 for (int i = 0; i < keys.length; i++) {
313 JS('', '#[#]=#', o, keys[i], deserialize(values[i]));
314 }
315 return o;
316 }
317
318 // ['function', id, <name>].
319 Function deserializeClosure(x) {
320 assert(x[0] == 'function');
321 int id = x[1];
322 String name = x[2];
323 Function result = IsolateNatives._getJSFunctionFromName(name);
324 deserializedObjects[id] = result;
325 return result;
326 }
327
328 // ['any', id, <class-id>, <field-list>].
329 deserializeAny(x) {
sigurdm 2014/11/24 09:06:09 Maybe name this 'deserializeDartObject'
floitsch 2014/11/24 15:06:56 Done.
330 assert(x[0] == 'any');
331 int id = x[1];
332 String classId = x[2];
333 List fields = x[3];
334 var instanceFromClassId = JS_EMBEDDED_GLOBAL('', INSTANCE_FROM_CLASS_ID);
335 var initializeObject = JS_EMBEDDED_GLOBAL('', INITIALIZE_EMPTY_INSTANCE);
336
337 var emptyInstance = JS('', '#(#)', instanceFromClassId, classId);
338 deserializedObjects[id] = emptyInstance;
339 deserializeArrayInPlace(fields);
340 return JS('', '#(#, #, #)',
341 initializeObject, classId, emptyInstance, fields);
342 }
343 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698