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

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: Support CSP mode. 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 NativeByteBuffer) return serializeByteBuffer(x);
45 if (x is NativeTypedData) return serializeTypedData(x);
46 if (x is JSIndexable) return serializeJSIndexable(x);
47 if (x is InternalMap) return serializeMap(x);
48
49 if (x is JSObject) return serializeJSObject(x);
50
51 // We should not have any interceptors any more.
52 if (x is Interceptor) unsupported(x);
53
54 if (x is RawReceivePort) {
55 unsupported(x, "RawReceivePorts can't be transmitted:");
56 }
57
58 // SendPorts need their workerIds adjusted (either during serialization or
59 // deserialization).
60 if (x is _NativeJsSendPort) return serializeJsSendPort(x);
61 if (x is _WorkerSendPort) return serializeWorkerSendPort(x);
62
63 if (x is Closure) return serializeClosure(x);
64
65 return serializeDartObject(x);
66 }
67
68 void unsupported(x, [String message]) {
69 if (message == null) message = "Can't transmit:";
70 throw new UnsupportedError("$message $x");
71 }
72
73 makeRef(int serializationId) => ["ref", serializationId];
74
75 bool isPrimitive(x) => x == null || x is String || x is num || x is bool;
76 serializePrimitive(primitive) => primitive;
77
78 serializeByteBuffer(NativeByteBuffer buffer) {
79 return ["buffer", buffer];
80 }
81
82 serializeTypedData(NativeTypedData data) {
83 return ["typed", data];
84 }
85
86 serializeJSIndexable(JSIndexable indexable) {
87 // Strings are JSIndexable but should have been treated earlier.
88 assert(indexable is! String);
89 List serialized = serializeArray(indexable);
90 if (indexable is JSFixedArray) return ["fixed", serialized];
91 if (indexable is JSExtendableArray) return ["extendable", serialized];
92 // MutableArray check must be last, since JSFixedArray and JSExtendableArray
93 // extend JSMutableArray.
94 if (indexable is JSMutableArray) return ["mutable", serialized];
95 // The only JSArrays left are the const Lists (as in `const [1, 2]`).
96 if (indexable is JSArray) return ["const", serialized];
97 unsupported(indexable, "Can't serialize indexable: ");
98 return null;
99 }
100
101 serializeArray(JSArray x) {
102 List serialized = [];
103 serialized.length = x.length;
104 for (int i = 0; i < x.length; i++) {
105 serialized[i] = serialize(x[i]);
106 }
107 return serialized;
108 }
109
110 serializeArrayInPlace(JSArray x) {
111 for (int i = 0; i < x.length; i++) {
112 x[i] = serialize(x[i]);
113 }
114 return x;
115 }
116
117 serializeMap(Map x) {
118 Function serializeTearOff = serialize;
119 return ['map',
120 x.keys.map(serializeTearOff).toList(),
121 x.values.map(serializeTearOff).toList()];
122 }
123
124 serializeJSObject(JSObject x) {
125 // Don't serialize objects if their `constructor` property isn't `Object`
126 // or undefined/null.
127 // A different constructor is taken as a sign that the object has complex
128 // internal state, or that it is a function, and won't be serialized.
129 if (JS('bool', '!!(#.constructor)', x) &&
130 JS('bool', 'x.constructor !== Object')) {
131 unsupported(x, "Only plain JS Objects are supported:");
132 }
133 List keys = JS('JSArray', 'Object.keys(#)', x);
134 List values = [];
135 values.length = keys.length;
136 for (int i = 0; i < keys.length; i++) {
137 values[i] = serialize(JS('', '#[#]', x, keys[i]));
138 }
139 return ['js-object', keys, values];
140 }
141
142 serializeWorkerSendPort(_WorkerSendPort x) {
143 if (_serializeSendPorts) {
144 return ['sendport', x._workerId, x._isolateId, x._receivePortId];
145 }
146 return ['raw sendport', x];
147 }
148
149 serializeJsSendPort(_NativeJsSendPort x) {
150 if (_serializeSendPorts) {
151 int workerId = _globalState.currentManagerId;
152 return ['sendport', workerId, x._isolateId, x._receivePort._id];
153 }
154 return ['raw sendport', x];
155 }
156
157 serializeCapability(CapabilityImpl x) => ['capability', x._id];
158
159 serializeClosure(Closure x) {
160 final name = IsolateNatives._getJSFunctionName(x);
161 if (name == null) {
162 unsupported(x, "Closures can't be transmitted:");
163 }
164 return ['function', name];
165 }
166
167 serializeDartObject(x) {
168 var classExtractor = JS_EMBEDDED_GLOBAL('', CLASS_ID_EXTRACTOR);
169 var fieldsExtractor = JS_EMBEDDED_GLOBAL('', CLASS_FIELDS_EXTRACTOR);
170 String classId = JS('String', '#(#)', classExtractor, x);
171 List fields = JS('JSArray', '#(#)', fieldsExtractor, x);
172 return ['dart', classId, serializeArrayInPlace(fields)];
173 }
174 }
175
176 class _Deserializer {
177 /// When `true`, encodes sendports specially so that they can be adjusted on
178 /// the receiving end.
179 ///
180 /// When `false`, sendports are cloned like any other object.
181 final bool _adjustSendPorts;
182
183 List<dynamic> deserializedObjects = new List<dynamic>();
184
185 _Deserializer({adjustSendPorts: true}) : _adjustSendPorts = adjustSendPorts;
186
187 /// Returns a message that can be transmitted through web-worker channels.
188 deserialize(x) {
189 if (isPrimitive(x)) return deserializePrimitive(x);
190
191 if (x is! JSArray) throw new ArgumentError("Bad serialized message: $x");
192
193 switch (x.first) {
194 case "ref": return deserializeRef(x);
195 case "buffer": return deserializeByteBuffer(x);
196 case "typed": return deserializeTypedData(x);
197 case "fixed": return deserializeFixed(x);
198 case "extendable": return deserializeExtendable(x);
199 case "mutable": return deserializeMutable(x);
200 case "const": return deserializeConst(x);
201 case "map": return deserializeMap(x);
202 case "sendport": return deserializeSendPort(x);
203 case "raw sendport": return deserializeRawSendPort(x);
204 case "js-object": return deserializeJSObject(x);
205 case "function": return deserializeClosure(x);
206 case "dart": return deserializeDartObject(x);
207 default: throw "couldn't deserialize: $x";
208 }
209 }
210
211 bool isPrimitive(x) => x == null || x is String || x is num || x is bool;
212 deserializePrimitive(x) => x;
213
214 // ['ref', id].
215 deserializeRef(x) {
216 assert(x[0] == 'ref');
217 int serializationId = x[1];
218 return deserializedObjects[serializationId];
219 }
220
221 // ['buffer', <byte buffer>].
222 NativeByteBuffer deserializeByteBuffer(x) {
223 assert(x[0] == 'buffer');
224 NativeByteBuffer result = x[1];
225 deserializedObjects.add(result);
226 return result;
227 }
228
229 // ['typed', <typed array>].
230 NativeTypedData deserializeTypedData(x) {
231 assert(x[0] == 'typed');
232 NativeTypedData result = x[1];
233 deserializedObjects.add(result);
234 return result;
235 }
236
237 // Updates the given array in place with its deserialized content.
238 List deserializeArrayInPlace(JSArray x) {
239 for (int i = 0; i < x.length; i++) {
240 x[i] = deserialize(x[i]);
241 }
242 return x;
243 }
244
245 // ['fixed', <array>].
246 List deserializeFixed(x) {
247 assert(x[0] == 'fixed');
248 List result = x[1];
249 deserializedObjects.add(result);
250 return new JSArray.markFixed(deserializeArrayInPlace(result));
251 }
252
253 // ['extendable', <array>].
254 List deserializeExtendable(x) {
255 assert(x[0] == 'extendable');
256 List result = x[1];
257 deserializedObjects.add(result);
258 return new JSArray.markGrowable(deserializeArrayInPlace(result));
259 }
260
261 // ['mutable', <array>].
262 List deserializeMutable(x) {
263 assert(x[0] == 'mutable');
264 List result = x[1];
265 deserializedObjects.add(result);
266 return deserializeArrayInPlace(result);
267 }
268
269 // ['const', <array>].
270 List deserializeConst(x) {
271 assert(x[0] == 'const');
272 List result = x[1];
273 deserializedObjects.add(result);
274 // TODO(floitsch): need to mark list as non-changeable.
275 return new JSArray.markFixed(deserializeArrayInPlace(result));
276 }
277
278 // ['map', <key-list>, <value-list>].
279 Map deserializeMap(x) {
280 assert(x[0] == 'map');
281 List keys = x[1];
282 List values = x[2];
283 Map result = {};
284 deserializedObjects.add(result);
285 // We need to keep the order of how objects were serialized.
286 // First deserialize all keys, and then only deserialize the values.
287 keys = keys.map(deserialize).toList();
288
289 for (int i = 0; i < keys.length; i++) {
290 result[keys[i]] = deserialize(values[i]);
291 }
292 return result;
293 }
294
295 // ['sendport', <managerId>, <isolateId>, <receivePortId>].
296 SendPort deserializeSendPort(x) {
297 assert(x[0] == 'sendport');
298 int managerId = x[1];
299 int isolateId = x[2];
300 int receivePortId = x[3];
301 SendPort result;
302 // If two isolates are in the same manager, we use NativeJsSendPorts to
303 // deliver messages directly without using postMessage.
304 if (managerId == _globalState.currentManagerId) {
305 var isolate = _globalState.isolates[isolateId];
306 if (isolate == null) return null; // Isolate has been closed.
307 var receivePort = isolate.lookup(receivePortId);
308 if (receivePort == null) return null; // Port has been closed.
309 result = new _NativeJsSendPort(receivePort, isolateId);
310 } else {
311 result = new _WorkerSendPort(managerId, isolateId, receivePortId);
312 }
313 deserializedObjects.add(result);
314 return result;
315 }
316
317 // ['raw sendport', <sendport>].
318 SendPort deserializeRawSendPort(x) {
319 assert(x[0] == 'raw sendport');
320 SendPort result = x[1];
321 deserializedObjects.add(result);
322 return result;
323 }
324
325 // ['js-object', <key-list>, <value-list>].
326 deserializeJSObject(x) {
327 assert(x[0] == 'js-object');
328 List keys = x[1];
329 List values = x[2];
330 var o = JS('', '{}');
331 deserializedObjects.add(o);
332 for (int i = 0; i < keys.length; i++) {
333 JS('', '#[#]=#', o, keys[i], deserialize(values[i]));
334 }
335 return o;
336 }
337
338 // ['function', <name>].
339 Function deserializeClosure(x) {
340 assert(x[0] == 'function');
341 String name = x[1];
342 Function result = IsolateNatives._getJSFunctionFromName(name);
343 deserializedObjects.add(result);
344 return result;
345 }
346
347 // ['dart', <class-id>, <field-list>].
348 deserializeDartObject(x) {
349 assert(x[0] == 'dart');
350 String classId = x[1];
351 List fields = x[2];
352 var instanceFromClassId = JS_EMBEDDED_GLOBAL('', INSTANCE_FROM_CLASS_ID);
353 var initializeObject = JS_EMBEDDED_GLOBAL('', INITIALIZE_EMPTY_INSTANCE);
354
355 var emptyInstance = JS('', '#(#)', instanceFromClassId, classId);
356 deserializedObjects.add(emptyInstance);
357 deserializeArrayInPlace(fields);
358 return JS('', '#(#, #, #)',
359 initializeObject, classId, emptyInstance, fields);
360 }
361 }
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