OLD | NEW |
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 library _isolate_helper; | 5 library _isolate_helper; |
6 | 6 |
7 import 'shared/embedded_names.dart' show | 7 import 'shared/embedded_names.dart' show |
| 8 CLASS_ID_EXTRACTOR, |
| 9 CLASS_FIELDS_EXTRACTOR, |
8 CURRENT_SCRIPT, | 10 CURRENT_SCRIPT, |
9 GLOBAL_FUNCTIONS; | 11 GLOBAL_FUNCTIONS, |
| 12 INITIALIZE_EMPTY_INSTANCE, |
| 13 INSTANCE_FROM_CLASS_ID; |
10 | 14 |
11 import 'dart:async'; | 15 import 'dart:async'; |
12 import 'dart:collection' show Queue, HashMap; | 16 import 'dart:collection' show Queue, HashMap; |
13 import 'dart:isolate'; | 17 import 'dart:isolate'; |
| 18 import 'dart:_native_typed_data' show NativeByteBuffer, NativeTypedData; |
| 19 |
14 import 'dart:_js_helper' show | 20 import 'dart:_js_helper' show |
15 Closure, | 21 Closure, |
| 22 InternalMap, |
16 Null, | 23 Null, |
17 Primitives, | 24 Primitives, |
18 convertDartClosureToJS, | 25 convertDartClosureToJS, |
19 random64, | 26 random64, |
20 requiresPreamble; | 27 requiresPreamble; |
| 28 |
21 import 'dart:_foreign_helper' show DART_CLOSURE_TO_JS, | 29 import 'dart:_foreign_helper' show DART_CLOSURE_TO_JS, |
22 JS, | 30 JS, |
23 JS_CREATE_ISOLATE, | 31 JS_CREATE_ISOLATE, |
24 JS_CURRENT_ISOLATE_CONTEXT, | 32 JS_CURRENT_ISOLATE_CONTEXT, |
25 JS_CURRENT_ISOLATE, | 33 JS_CURRENT_ISOLATE, |
26 JS_EMBEDDED_GLOBAL, | 34 JS_EMBEDDED_GLOBAL, |
27 JS_SET_CURRENT_ISOLATE, | 35 JS_SET_CURRENT_ISOLATE, |
28 IsolateContext; | 36 IsolateContext; |
29 import 'dart:_interceptors' show JSExtendableArray; | 37 |
| 38 import 'dart:_interceptors' show Interceptor, |
| 39 JSArray, |
| 40 JSExtendableArray, |
| 41 JSFixedArray, |
| 42 JSIndexable, |
| 43 JSMutableArray, |
| 44 JSObject; |
| 45 |
| 46 |
| 47 part 'isolate_serialization.dart'; |
30 | 48 |
31 /** | 49 /** |
32 * Called by the compiler to support switching | 50 * Called by the compiler to support switching |
33 * between isolates when we get a callback from the DOM. | 51 * between isolates when we get a callback from the DOM. |
34 */ | 52 */ |
35 _callInIsolate(_IsolateContext isolate, Function function) { | 53 _callInIsolate(_IsolateContext isolate, Function function) { |
36 var result = isolate.eval(function); | 54 var result = isolate.eval(function); |
37 _globalState.topEventLoop.run(); | 55 _globalState.topEventLoop.run(); |
38 return result; | 56 return result; |
39 } | 57 } |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
179 /** Whether we support spawning web workers. */ | 197 /** Whether we support spawning web workers. */ |
180 bool supportsWorkers; | 198 bool supportsWorkers; |
181 | 199 |
182 /** | 200 /** |
183 * Whether to use web workers when implementing isolates. Set to false for | 201 * Whether to use web workers when implementing isolates. Set to false for |
184 * debugging/testing. | 202 * debugging/testing. |
185 */ | 203 */ |
186 bool get useWorkers => supportsWorkers; | 204 bool get useWorkers => supportsWorkers; |
187 | 205 |
188 /** | 206 /** |
189 * Whether to use the web-worker JSON-based message serialization protocol. By | |
190 * default this is only used with web workers. For debugging, you can force | |
191 * using this protocol by changing this field value to [:true:]. | |
192 */ | |
193 bool get needSerialization => useWorkers; | |
194 | |
195 /** | |
196 * Registry of isolates. Isolates must be registered if, and only if, receive | 207 * Registry of isolates. Isolates must be registered if, and only if, receive |
197 * ports are alive. Normally no open receive-ports means that the isolate is | 208 * ports are alive. Normally no open receive-ports means that the isolate is |
198 * dead, but DOM callbacks could resurrect it. | 209 * dead, but DOM callbacks could resurrect it. |
199 */ | 210 */ |
200 Map<int, _IsolateContext> isolates; | 211 Map<int, _IsolateContext> isolates; |
201 | 212 |
202 /** Reference to the main [_Manager]. Null in the main [_Manager] itself. */ | 213 /** Reference to the main [_Manager]. Null in the main [_Manager] itself. */ |
203 _MainManagerStub mainManager; | 214 _MainManagerStub mainManager; |
204 | 215 |
205 /// Registry of active Web Workers. Only used in the main [_Manager]. | 216 /// Registry of active Web Workers. Only used in the main [_Manager]. |
(...skipping 767 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
973 return completer.future; | 984 return completer.future; |
974 } | 985 } |
975 | 986 |
976 static void _startWorker( | 987 static void _startWorker( |
977 String functionName, String uri, | 988 String functionName, String uri, |
978 List<String> args, message, | 989 List<String> args, message, |
979 bool isSpawnUri, | 990 bool isSpawnUri, |
980 bool startPaused, | 991 bool startPaused, |
981 SendPort replyPort, | 992 SendPort replyPort, |
982 void onError(String message)) { | 993 void onError(String message)) { |
| 994 // Make sure that the args list is a fresh generic list. A newly spawned |
| 995 // isolate should be able to assume that the arguments list is an |
| 996 // extendable list. |
| 997 if (args != null) args = new List<String>.from(args); |
983 if (_globalState.isWorker) { | 998 if (_globalState.isWorker) { |
984 _globalState.mainManager.postMessage(_serializeMessage({ | 999 _globalState.mainManager.postMessage(_serializeMessage({ |
985 'command': 'spawn-worker', | 1000 'command': 'spawn-worker', |
986 'functionName': functionName, | 1001 'functionName': functionName, |
987 'args': args, | 1002 'args': args, |
988 'msg': message, | 1003 'msg': message, |
989 'uri': uri, | 1004 'uri': uri, |
990 'isSpawnUri': isSpawnUri, | 1005 'isSpawnUri': isSpawnUri, |
991 'startPaused': startPaused, | 1006 'startPaused': startPaused, |
992 'replyPort': replyPort})); | 1007 'replyPort': replyPort})); |
993 } else { | 1008 } else { |
994 _spawnWorker(functionName, uri, args, message, | 1009 _spawnWorker(functionName, uri, args, message, |
995 isSpawnUri, startPaused, replyPort, onError); | 1010 isSpawnUri, startPaused, replyPort, onError); |
996 } | 1011 } |
997 } | 1012 } |
998 | 1013 |
999 static void _startNonWorker( | 1014 static void _startNonWorker( |
1000 String functionName, String uri, | 1015 String functionName, String uri, |
1001 List<String> args, var message, | 1016 List<String> args, var message, |
1002 bool isSpawnUri, | 1017 bool isSpawnUri, |
1003 bool startPaused, | 1018 bool startPaused, |
1004 SendPort replyPort) { | 1019 SendPort replyPort) { |
1005 // TODO(eub): support IE9 using an iframe -- Dart issue 1702. | 1020 // TODO(eub): support IE9 using an iframe -- Dart issue 1702. |
1006 if (uri != null) { | 1021 if (uri != null) { |
1007 throw new UnsupportedError( | 1022 throw new UnsupportedError( |
1008 "Currently spawnUri is not supported without web workers."); | 1023 "Currently spawnUri is not supported without web workers."); |
1009 } | 1024 } |
1010 message = _serializeMessage(message); | 1025 // Clone the message to enforce the restrictions we have on isolate |
1011 args = _serializeMessage(args); // Or just args.toList() ? | 1026 // messages. |
| 1027 message = _clone(message); |
| 1028 // Make sure that the args list is a fresh generic list. A newly spawned |
| 1029 // isolate should be able to assume that the arguments list is an |
| 1030 // extendable list. |
| 1031 if (args != null) args = new List<String>.from(args); |
1012 _globalState.topEventLoop.enqueue(new _IsolateContext(), () { | 1032 _globalState.topEventLoop.enqueue(new _IsolateContext(), () { |
1013 final func = _getJSFunctionFromName(functionName); | 1033 final func = _getJSFunctionFromName(functionName); |
1014 _startIsolate(func, args, message, isSpawnUri, startPaused, replyPort); | 1034 _startIsolate(func, args, message, isSpawnUri, startPaused, replyPort); |
1015 }, 'nonworker start'); | 1035 }, 'nonworker start'); |
1016 } | 1036 } |
1017 | 1037 |
1018 static void _startIsolate(Function topLevel, | 1038 static void _startIsolate(Function topLevel, |
1019 List<String> args, message, | 1039 List<String> args, message, |
1020 bool isSpawnUri, | 1040 bool isSpawnUri, |
1021 bool startPaused, | 1041 bool startPaused, |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1158 class _NativeJsSendPort extends _BaseSendPort implements SendPort { | 1178 class _NativeJsSendPort extends _BaseSendPort implements SendPort { |
1159 final RawReceivePortImpl _receivePort; | 1179 final RawReceivePortImpl _receivePort; |
1160 | 1180 |
1161 const _NativeJsSendPort(this._receivePort, int isolateId) : super(isolateId); | 1181 const _NativeJsSendPort(this._receivePort, int isolateId) : super(isolateId); |
1162 | 1182 |
1163 void send(var message) { | 1183 void send(var message) { |
1164 // Check that the isolate still runs and the port is still open | 1184 // Check that the isolate still runs and the port is still open |
1165 final isolate = _globalState.isolates[_isolateId]; | 1185 final isolate = _globalState.isolates[_isolateId]; |
1166 if (isolate == null) return; | 1186 if (isolate == null) return; |
1167 if (_receivePort._isClosed) return; | 1187 if (_receivePort._isClosed) return; |
1168 // We force serialization/deserialization as a simple way to ensure | 1188 // Clone the message to enforce the restrictions we have on isolate |
1169 // isolate communication restrictions are respected between isolates that | 1189 // messages. |
1170 // live in the same worker. [_NativeJsSendPort] delivers both messages | 1190 var msg = _clone(message); |
1171 // from the same worker and messages from other workers. In particular, | |
1172 // messages sent from a worker via a [_WorkerSendPort] are received at | |
1173 // [_processWorkerMessage] and forwarded to a native port. In such cases, | |
1174 // here we'll see [_globalState.currentContext == null]. | |
1175 final shouldSerialize = _globalState.currentContext != null | |
1176 && _globalState.currentContext.id != _isolateId; | |
1177 var msg = message; | |
1178 if (shouldSerialize) { | |
1179 msg = _serializeMessage(msg); | |
1180 } | |
1181 if (isolate.controlPort == _receivePort) { | 1191 if (isolate.controlPort == _receivePort) { |
1182 isolate.handleControlMessage(msg); | 1192 isolate.handleControlMessage(msg); |
1183 return; | 1193 return; |
1184 } | 1194 } |
1185 _globalState.topEventLoop.enqueue(isolate, () { | 1195 _globalState.topEventLoop.enqueue(isolate, () { |
1186 if (!_receivePort._isClosed) { | 1196 if (!_receivePort._isClosed) { |
1187 if (shouldSerialize) { | |
1188 msg = _deserializeMessage(msg); | |
1189 } | |
1190 _receivePort._add(msg); | 1197 _receivePort._add(msg); |
1191 } | 1198 } |
1192 }, 'receive $message'); | 1199 }, 'receive $message'); |
1193 } | 1200 } |
1194 | 1201 |
1195 bool operator ==(var other) => (other is _NativeJsSendPort) && | 1202 bool operator ==(var other) => (other is _NativeJsSendPort) && |
1196 (_receivePort == other._receivePort); | 1203 (_receivePort == other._receivePort); |
1197 | 1204 |
1198 int get hashCode => _receivePort._id; | 1205 int get hashCode => _receivePort._id; |
1199 } | 1206 } |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1310 } | 1317 } |
1311 | 1318 |
1312 void close() { | 1319 void close() { |
1313 _rawPort.close(); | 1320 _rawPort.close(); |
1314 _controller.close(); | 1321 _controller.close(); |
1315 } | 1322 } |
1316 | 1323 |
1317 SendPort get sendPort => _rawPort.sendPort; | 1324 SendPort get sendPort => _rawPort.sendPort; |
1318 } | 1325 } |
1319 | 1326 |
1320 | |
1321 /******************************************************** | |
1322 Inserted from lib/isolate/dart2js/messages.dart | |
1323 ********************************************************/ | |
1324 | |
1325 // Defines message visitors, serialization, and deserialization. | |
1326 | |
1327 /** Serialize [message] (or simulate serialization). */ | |
1328 _serializeMessage(message) { | |
1329 if (_globalState.needSerialization) { | |
1330 return new _JsSerializer().traverse(message); | |
1331 } else { | |
1332 return new _JsCopier().traverse(message); | |
1333 } | |
1334 } | |
1335 | |
1336 /** Deserialize [message] (or simulate deserialization). */ | |
1337 _deserializeMessage(message) { | |
1338 if (_globalState.needSerialization) { | |
1339 return new _JsDeserializer().deserialize(message); | |
1340 } else { | |
1341 // Nothing more to do. | |
1342 return message; | |
1343 } | |
1344 } | |
1345 | |
1346 class _JsSerializer extends _Serializer { | |
1347 | |
1348 _JsSerializer() : super() { _visited = new _JsVisitedMap(); } | |
1349 | |
1350 visitSendPort(SendPort x) { | |
1351 if (x is _NativeJsSendPort) return visitNativeJsSendPort(x); | |
1352 if (x is _WorkerSendPort) return visitWorkerSendPort(x); | |
1353 throw "Illegal underlying port $x"; | |
1354 } | |
1355 | |
1356 visitCapability(Capability x) { | |
1357 if (x is CapabilityImpl) { | |
1358 return ['capability', x._id]; | |
1359 } | |
1360 throw "Capability not serializable: $x"; | |
1361 } | |
1362 | |
1363 visitNativeJsSendPort(_NativeJsSendPort port) { | |
1364 return ['sendport', _globalState.currentManagerId, | |
1365 port._isolateId, port._receivePort._id]; | |
1366 } | |
1367 | |
1368 visitWorkerSendPort(_WorkerSendPort port) { | |
1369 return ['sendport', port._workerId, port._isolateId, port._receivePortId]; | |
1370 } | |
1371 | |
1372 visitFunction(Function topLevelFunction) { | |
1373 final name = IsolateNatives._getJSFunctionName(topLevelFunction); | |
1374 if (name == null) { | |
1375 throw new UnsupportedError( | |
1376 "only top-level functions can be sent."); | |
1377 } | |
1378 return ['function', name]; | |
1379 } | |
1380 } | |
1381 | |
1382 | |
1383 class _JsCopier extends _Copier { | |
1384 | |
1385 _JsCopier() : super() { _visited = new _JsVisitedMap(); } | |
1386 | |
1387 visitSendPort(SendPort x) { | |
1388 if (x is _NativeJsSendPort) return visitNativeJsSendPort(x); | |
1389 if (x is _WorkerSendPort) return visitWorkerSendPort(x); | |
1390 throw "Illegal underlying port $x"; | |
1391 } | |
1392 | |
1393 visitCapability(Capability x) { | |
1394 if (x is CapabilityImpl) { | |
1395 return new CapabilityImpl._internal(x._id); | |
1396 } | |
1397 throw "Capability not serializable: $x"; | |
1398 } | |
1399 | |
1400 SendPort visitNativeJsSendPort(_NativeJsSendPort port) { | |
1401 return new _NativeJsSendPort(port._receivePort, port._isolateId); | |
1402 } | |
1403 | |
1404 SendPort visitWorkerSendPort(_WorkerSendPort port) { | |
1405 return new _WorkerSendPort( | |
1406 port._workerId, port._isolateId, port._receivePortId); | |
1407 } | |
1408 | |
1409 Function visitFunction(Function topLevelFunction) { | |
1410 final name = IsolateNatives._getJSFunctionName(topLevelFunction); | |
1411 if (name == null) { | |
1412 throw new UnsupportedError( | |
1413 "only top-level functions can be sent."); | |
1414 } | |
1415 // Is this getting it from the correct isolate? Is it just topLevelFunction? | |
1416 return IsolateNatives._getJSFunctionFromName(name); | |
1417 } | |
1418 } | |
1419 | |
1420 class _JsDeserializer extends _Deserializer { | |
1421 | |
1422 SendPort deserializeSendPort(List list) { | |
1423 int managerId = list[1]; | |
1424 int isolateId = list[2]; | |
1425 int receivePortId = list[3]; | |
1426 // If two isolates are in the same manager, we use NativeJsSendPorts to | |
1427 // deliver messages directly without using postMessage. | |
1428 if (managerId == _globalState.currentManagerId) { | |
1429 var isolate = _globalState.isolates[isolateId]; | |
1430 if (isolate == null) return null; // Isolate has been closed. | |
1431 var receivePort = isolate.lookup(receivePortId); | |
1432 if (receivePort == null) return null; // Port has been closed. | |
1433 return new _NativeJsSendPort(receivePort, isolateId); | |
1434 } else { | |
1435 return new _WorkerSendPort(managerId, isolateId, receivePortId); | |
1436 } | |
1437 } | |
1438 | |
1439 Capability deserializeCapability(List list) { | |
1440 return new CapabilityImpl._internal(list[1]); | |
1441 } | |
1442 | |
1443 Function deserializeFunction(List list) { | |
1444 return IsolateNatives._getJSFunctionFromName(list[1]); | |
1445 } | |
1446 } | |
1447 | |
1448 class _JsVisitedMap implements _MessageTraverserVisitedMap { | |
1449 List tagged; | |
1450 | |
1451 /** Retrieves any information stored in the native object [object]. */ | |
1452 operator[](var object) { | |
1453 return _getAttachedInfo(object); | |
1454 } | |
1455 | |
1456 /** Injects some information into the native [object]. */ | |
1457 void operator[]=(var object, var info) { | |
1458 tagged.add(object); | |
1459 _setAttachedInfo(object, info); | |
1460 } | |
1461 | |
1462 /** Get ready to rumble. */ | |
1463 void reset() { | |
1464 assert(tagged == null); | |
1465 tagged = new List(); | |
1466 } | |
1467 | |
1468 /** Remove all information injected in the native objects. */ | |
1469 void cleanup() { | |
1470 for (int i = 0, length = tagged.length; i < length; i++) { | |
1471 _clearAttachedInfo(tagged[i]); | |
1472 } | |
1473 tagged = null; | |
1474 } | |
1475 | |
1476 void _clearAttachedInfo(var o) { | |
1477 JS("void", "#['__MessageTraverser__attached_info__'] = #", o, null); | |
1478 } | |
1479 | |
1480 void _setAttachedInfo(var o, var info) { | |
1481 JS("void", "#['__MessageTraverser__attached_info__'] = #", o, info); | |
1482 } | |
1483 | |
1484 _getAttachedInfo(var o) { | |
1485 return JS("", "#['__MessageTraverser__attached_info__']", o); | |
1486 } | |
1487 } | |
1488 | |
1489 // only visible for testing purposes | |
1490 // TODO(sigmund): remove once we can disable privacy for testing (bug #1882) | |
1491 class TestingOnly { | |
1492 static copy(x) { | |
1493 return new _JsCopier().traverse(x); | |
1494 } | |
1495 | |
1496 // only visible for testing purposes | |
1497 static serialize(x) { | |
1498 _Serializer serializer = new _JsSerializer(); | |
1499 _Deserializer deserializer = new _JsDeserializer(); | |
1500 return deserializer.deserialize(serializer.traverse(x)); | |
1501 } | |
1502 } | |
1503 | |
1504 /******************************************************** | |
1505 Inserted from lib/isolate/serialization.dart | |
1506 ********************************************************/ | |
1507 | |
1508 class _MessageTraverserVisitedMap { | |
1509 | |
1510 operator[](var object) => null; | |
1511 void operator[]=(var object, var info) { } | |
1512 | |
1513 void reset() { } | |
1514 void cleanup() { } | |
1515 | |
1516 } | |
1517 | |
1518 /** Abstract visitor for dart objects that can be sent as isolate messages. */ | |
1519 abstract class _MessageTraverser { | |
1520 | |
1521 _MessageTraverserVisitedMap _visited; | |
1522 _MessageTraverser() : _visited = new _MessageTraverserVisitedMap(); | |
1523 | |
1524 /** Visitor's entry point. */ | |
1525 traverse(var x) { | |
1526 if (isPrimitive(x)) return visitPrimitive(x); | |
1527 _visited.reset(); | |
1528 var result; | |
1529 try { | |
1530 result = _dispatch(x); | |
1531 } finally { | |
1532 _visited.cleanup(); | |
1533 } | |
1534 return result; | |
1535 } | |
1536 | |
1537 _dispatch(var x) { | |
1538 // This code likely fails for user classes implementing | |
1539 // SendPort and Capability because it assumes the internal classes. | |
1540 if (isPrimitive(x)) return visitPrimitive(x); | |
1541 if (x is List) return visitList(x); | |
1542 if (x is Map) return visitMap(x); | |
1543 if (x is SendPort) return visitSendPort(x); | |
1544 if (x is Capability) return visitCapability(x); | |
1545 if (x is Function) return visitFunction(x); | |
1546 | |
1547 // Overridable fallback. | |
1548 return visitObject(x); | |
1549 } | |
1550 | |
1551 visitPrimitive(x); | |
1552 visitList(List x); | |
1553 visitMap(Map x); | |
1554 visitSendPort(SendPort x); | |
1555 visitCapability(Capability x); | |
1556 visitFunction(Function f); | |
1557 | |
1558 visitObject(Object x) { | |
1559 // TODO(floitsch): make this a real exception. (which one)? | |
1560 throw "Message serialization: Illegal value $x passed"; | |
1561 } | |
1562 | |
1563 static bool isPrimitive(x) { | |
1564 return (x == null) || (x is String) || (x is num) || (x is bool); | |
1565 } | |
1566 } | |
1567 | |
1568 | |
1569 /** A visitor that recursively copies a message. */ | |
1570 class _Copier extends _MessageTraverser { | |
1571 | |
1572 visitPrimitive(x) => x; | |
1573 | |
1574 List visitList(List list) { | |
1575 List copy = _visited[list]; | |
1576 if (copy != null) return copy; | |
1577 | |
1578 int len = list.length; | |
1579 | |
1580 // TODO(floitsch): we loose the generic type of the List. | |
1581 copy = new List(len); | |
1582 _visited[list] = copy; | |
1583 for (int i = 0; i < len; i++) { | |
1584 copy[i] = _dispatch(list[i]); | |
1585 } | |
1586 return copy; | |
1587 } | |
1588 | |
1589 Map visitMap(Map map) { | |
1590 Map copy = _visited[map]; | |
1591 if (copy != null) return copy; | |
1592 | |
1593 // TODO(floitsch): we loose the generic type of the map. | |
1594 copy = new Map(); | |
1595 _visited[map] = copy; | |
1596 map.forEach((key, val) { | |
1597 copy[_dispatch(key)] = _dispatch(val); | |
1598 }); | |
1599 return copy; | |
1600 } | |
1601 | |
1602 visitFunction(Function f) => throw new UnimplementedError(); | |
1603 | |
1604 visitSendPort(SendPort x) => throw new UnimplementedError(); | |
1605 | |
1606 visitCapability(Capability x) => throw new UnimplementedError(); | |
1607 } | |
1608 | |
1609 /** Visitor that serializes a message as a JSON array. */ | |
1610 class _Serializer extends _MessageTraverser { | |
1611 int _nextFreeRefId = 0; | |
1612 | |
1613 visitPrimitive(x) => x; | |
1614 | |
1615 visitList(List list) { | |
1616 int copyId = _visited[list]; | |
1617 if (copyId != null) return ['ref', copyId]; | |
1618 | |
1619 int id = _nextFreeRefId++; | |
1620 _visited[list] = id; | |
1621 var jsArray = _serializeList(list); | |
1622 // TODO(floitsch): we are losing the generic type. | |
1623 return ['list', id, jsArray]; | |
1624 } | |
1625 | |
1626 visitMap(Map map) { | |
1627 int copyId = _visited[map]; | |
1628 if (copyId != null) return ['ref', copyId]; | |
1629 | |
1630 int id = _nextFreeRefId++; | |
1631 _visited[map] = id; | |
1632 var keys = _serializeList(map.keys.toList()); | |
1633 var values = _serializeList(map.values.toList()); | |
1634 // TODO(floitsch): we are losing the generic type. | |
1635 return ['map', id, keys, values]; | |
1636 } | |
1637 | |
1638 _serializeList(List list) { | |
1639 int len = list.length; | |
1640 // Use a growable list because we do not add extra properties on | |
1641 // them. | |
1642 var result = new List()..length = len; | |
1643 for (int i = 0; i < len; i++) { | |
1644 result[i] = _dispatch(list[i]); | |
1645 } | |
1646 return result; | |
1647 } | |
1648 | |
1649 visitSendPort(SendPort x) => throw new UnimplementedError(); | |
1650 | |
1651 visitCapability(Capability x) => throw new UnimplementedError(); | |
1652 | |
1653 visitFunction(Function f) => throw new UnimplementedError(); | |
1654 } | |
1655 | |
1656 /** Deserializes arrays created with [_Serializer]. */ | |
1657 abstract class _Deserializer { | |
1658 Map<int, dynamic> _deserialized; | |
1659 | |
1660 _Deserializer(); | |
1661 | |
1662 static bool isPrimitive(x) { | |
1663 return (x == null) || (x is String) || (x is num) || (x is bool); | |
1664 } | |
1665 | |
1666 deserialize(x) { | |
1667 if (isPrimitive(x)) return x; | |
1668 // TODO(floitsch): this should be new HashMap<int, dynamic>() | |
1669 _deserialized = new HashMap(); | |
1670 return _deserializeHelper(x); | |
1671 } | |
1672 | |
1673 _deserializeHelper(x) { | |
1674 if (isPrimitive(x)) return x; | |
1675 assert(x is List); | |
1676 switch (x[0]) { | |
1677 case 'ref': return _deserializeRef(x); | |
1678 case 'list': return _deserializeList(x); | |
1679 case 'map': return _deserializeMap(x); | |
1680 case 'sendport': return deserializeSendPort(x); | |
1681 case 'capability': return deserializeCapability(x); | |
1682 case 'function' : return deserializeFunction(x); | |
1683 default: return deserializeObject(x); | |
1684 } | |
1685 } | |
1686 | |
1687 _deserializeRef(List x) { | |
1688 int id = x[1]; | |
1689 var result = _deserialized[id]; | |
1690 assert(result != null); | |
1691 return result; | |
1692 } | |
1693 | |
1694 List _deserializeList(List x) { | |
1695 int id = x[1]; | |
1696 // We rely on the fact that Dart-lists are directly mapped to Js-arrays. | |
1697 List dartList = x[2]; | |
1698 _deserialized[id] = dartList; | |
1699 int len = dartList.length; | |
1700 for (int i = 0; i < len; i++) { | |
1701 dartList[i] = _deserializeHelper(dartList[i]); | |
1702 } | |
1703 return dartList; | |
1704 } | |
1705 | |
1706 Map _deserializeMap(List x) { | |
1707 Map result = new Map(); | |
1708 int id = x[1]; | |
1709 _deserialized[id] = result; | |
1710 List keys = x[2]; | |
1711 List values = x[3]; | |
1712 int len = keys.length; | |
1713 assert(len == values.length); | |
1714 for (int i = 0; i < len; i++) { | |
1715 var key = _deserializeHelper(keys[i]); | |
1716 var value = _deserializeHelper(values[i]); | |
1717 result[key] = value; | |
1718 } | |
1719 return result; | |
1720 } | |
1721 | |
1722 deserializeFunction(List x); | |
1723 | |
1724 deserializeSendPort(List x); | |
1725 | |
1726 deserializeCapability(List x); | |
1727 | |
1728 deserializeObject(List x) { | |
1729 // TODO(floitsch): Use real exception (which one?). | |
1730 throw "Unexpected serialized object"; | |
1731 } | |
1732 } | |
1733 | |
1734 class TimerImpl implements Timer { | 1327 class TimerImpl implements Timer { |
1735 final bool _once; | 1328 final bool _once; |
1736 bool _inEventLoop = false; | 1329 bool _inEventLoop = false; |
1737 int _handle; | 1330 int _handle; |
1738 | 1331 |
1739 TimerImpl(int milliseconds, void callback()) | 1332 TimerImpl(int milliseconds, void callback()) |
1740 : _once = true { | 1333 : _once = true { |
1741 if (milliseconds == 0 && (!hasTimer() || _globalState.isWorker)) { | 1334 if (milliseconds == 0 && (!hasTimer() || _globalState.isWorker)) { |
1742 | 1335 |
1743 void internalCallback() { | 1336 void internalCallback() { |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1845 } | 1438 } |
1846 | 1439 |
1847 bool operator==(Object other) { | 1440 bool operator==(Object other) { |
1848 if (identical(other, this)) return true; | 1441 if (identical(other, this)) return true; |
1849 if (other is CapabilityImpl) { | 1442 if (other is CapabilityImpl) { |
1850 return identical(_id, other._id); | 1443 return identical(_id, other._id); |
1851 } | 1444 } |
1852 return false; | 1445 return false; |
1853 } | 1446 } |
1854 } | 1447 } |
OLD | NEW |