| OLD | NEW |
| 1 // Copyright (c) 2011, 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 /** | 5 /** |
| 6 * A native object that is shared across isolates. This object is visible to all | 6 * A native object that is shared across isolates. This object is visible to all |
| 7 * isolates running on the same worker (either UI or background web worker). | 7 * isolates running on the same worker (either UI or background web worker). |
| 8 * | 8 * |
| 9 * This is code that is intended to 'escape' the isolate boundaries in order to | 9 * This is code that is intended to 'escape' the isolate boundaries in order to |
| 10 * implement the semantics of friendly isolates in JavaScript. Without this we | 10 * implement the semantics of friendly isolates in JavaScript. Without this we |
| 11 * would have been forced to implement more code (including the top-level event | 11 * would have been forced to implement more code (including the top-level event |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 | 155 |
| 156 _deserializeMessage(message) { | 156 _deserializeMessage(message) { |
| 157 if (_globalState.needSerialization) { | 157 if (_globalState.needSerialization) { |
| 158 return new Deserializer().deserialize(message); | 158 return new Deserializer().deserialize(message); |
| 159 } else { | 159 } else { |
| 160 // Nothing more to do. | 160 // Nothing more to do. |
| 161 return message; | 161 return message; |
| 162 } | 162 } |
| 163 } | 163 } |
| 164 | 164 |
| 165 /** Wait until all ports in a message are resolved. */ |
| 166 _waitForPendingPorts(var message, void callback()) { |
| 167 final finder = new PendingSendPortFinder(); |
| 168 finder.traverse(message); |
| 169 Futures.wait(finder.ports).then((_) => callback()); |
| 170 } |
| 171 |
| 165 /** Default worker. */ | 172 /** Default worker. */ |
| 166 class MainWorker { | 173 class MainWorker { |
| 167 int id = 0; | 174 int id = 0; |
| 168 void postMessage(msg) native "return \$globalThis.postMessage(msg);"; | 175 void postMessage(msg) native "return \$globalThis.postMessage(msg);"; |
| 169 void set onmessage(f) native "\$globalThis.onmessage = f;"; | 176 void set onmessage(f) native "\$globalThis.onmessage = f;"; |
| 170 void terminate() {} | 177 void terminate() {} |
| 171 } | 178 } |
| 172 | 179 |
| 173 /** | 180 /** |
| 174 * A web worker. This type is also defined in 'dart:dom', but we define it here | 181 * A web worker. This type is also defined in 'dart:dom', but we define it here |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 | 340 |
| 334 BaseSendPort(this._isolateId); | 341 BaseSendPort(this._isolateId); |
| 335 | 342 |
| 336 ReceivePortSingleShotImpl call(var message) { | 343 ReceivePortSingleShotImpl call(var message) { |
| 337 final result = new ReceivePortSingleShotImpl(); | 344 final result = new ReceivePortSingleShotImpl(); |
| 338 this.send(message, result.toSendPort()); | 345 this.send(message, result.toSendPort()); |
| 339 return result; | 346 return result; |
| 340 } | 347 } |
| 341 | 348 |
| 342 static void checkReplyTo(SendPort replyTo) { | 349 static void checkReplyTo(SendPort replyTo) { |
| 343 if (replyTo !== null && replyTo is! NativeJsSendPort | 350 if (replyTo !== null |
| 344 && replyTo is! WorkerSendPort) { | 351 && replyTo is! NativeJsSendPort |
| 345 throw "SendPort.send: Illegal replyTo port type."; | 352 && replyTo is! WorkerSendPort |
| 353 && replyTo is! BufferingSendPort) { |
| 354 throw new Exception("SendPort.send: Illegal replyTo port type"); |
| 346 } | 355 } |
| 347 } | 356 } |
| 348 | 357 |
| 349 // TODO(sigmund): replace the current SendPort.call with the following: | 358 // TODO(sigmund): replace the current SendPort.call with the following: |
| 350 //Future call(var message) { | 359 //Future call(var message) { |
| 351 // final completer = new Completer(); | 360 // final completer = new Completer(); |
| 352 // final port = new ReceivePort.singleShot(); | 361 // final port = new ReceivePort.singleShot(); |
| 353 // send(message, port.toSendPort()); | 362 // send(message, port.toSendPort()); |
| 354 // port.receive((value, ignoreReplyTo) { | 363 // port.receive((value, ignoreReplyTo) { |
| 355 // if (value is Exception) { | 364 // if (value is Exception) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 366 abstract int hashCode(); | 375 abstract int hashCode(); |
| 367 } | 376 } |
| 368 | 377 |
| 369 /** A send port that delivers messages in-memory via native JavaScript calls. */ | 378 /** A send port that delivers messages in-memory via native JavaScript calls. */ |
| 370 class NativeJsSendPort extends BaseSendPort implements SendPort { | 379 class NativeJsSendPort extends BaseSendPort implements SendPort { |
| 371 final ReceivePortImpl _receivePort; | 380 final ReceivePortImpl _receivePort; |
| 372 | 381 |
| 373 const NativeJsSendPort(this._receivePort, int isolateId) : super(isolateId); | 382 const NativeJsSendPort(this._receivePort, int isolateId) : super(isolateId); |
| 374 | 383 |
| 375 void send(var message, [SendPort replyTo = null]) { | 384 void send(var message, [SendPort replyTo = null]) { |
| 376 checkReplyTo(replyTo); | 385 _waitForPendingPorts([message, replyTo], () { |
| 377 // Check that the isolate still runs and the port is still open | 386 checkReplyTo(replyTo); |
| 378 final isolate = _globalState.isolates[_isolateId]; | 387 // Check that the isolate still runs and the port is still open |
| 379 if (isolate == null) return; | 388 final isolate = _globalState.isolates[_isolateId]; |
| 380 if (_receivePort._callback == null) return; | 389 if (isolate == null) return; |
| 390 if (_receivePort._callback == null) return; |
| 381 | 391 |
| 382 // We force serialization/deserialization as a simple way to ensure isolate | 392 // We force serialization/deserialization as a simple way to ensure |
| 383 // communication restrictions are respected between isolates that live in | 393 // isolate communication restrictions are respected between isolates that |
| 384 // the same worker. NativeJsSendPort delivers both messages from the same | 394 // live in the same worker. NativeJsSendPort delivers both messages from |
| 385 // worker and messages from other workers. In particular, messages sent from | 395 // the same worker and messages from other workers. In particular, |
| 386 // a worker via a WorkerSendPort are received at [_processWorkerMessage] and | 396 // messages sent from a worker via a WorkerSendPort are received at |
| 387 // forwarded to a native port. In such cases, here we'll see | 397 // [_processWorkerMessage] and forwarded to a native port. In such cases, |
| 388 // [_globalState.currentContext == null]. | 398 // here we'll see [_globalState.currentContext == null]. |
| 389 final shouldSerialize = _globalState.currentContext != null | 399 final shouldSerialize = _globalState.currentContext != null |
| 390 && _globalState.currentContext.id != _isolateId; | 400 && _globalState.currentContext.id != _isolateId; |
| 391 var msg = message; | 401 var msg = message; |
| 392 var reply = replyTo; | 402 var reply = replyTo; |
| 393 if (shouldSerialize) { | 403 if (shouldSerialize) { |
| 394 msg = _serializeMessage(msg); | 404 msg = _serializeMessage(msg); |
| 395 reply = _serializeMessage(reply); | 405 reply = _serializeMessage(reply); |
| 396 } | 406 } |
| 397 _globalState.topEventLoop.enqueue(isolate, () { | 407 _globalState.topEventLoop.enqueue(isolate, () { |
| 398 if (_receivePort._callback != null) { | 408 if (_receivePort._callback != null) { |
| 399 if (shouldSerialize) { | 409 if (shouldSerialize) { |
| 400 msg = _deserializeMessage(msg); | 410 msg = _deserializeMessage(msg); |
| 401 reply = _deserializeMessage(reply); | 411 reply = _deserializeMessage(reply); |
| 412 } |
| 413 _receivePort._callback(msg, reply); |
| 402 } | 414 } |
| 403 _receivePort._callback(msg, reply); | 415 }, 'receive ' + message); |
| 404 } | 416 }); |
| 405 }, 'receive ' + message); | |
| 406 } | 417 } |
| 407 | 418 |
| 408 bool operator ==(var other) => (other is NativeJsSendPort) && | 419 bool operator ==(var other) => (other is NativeJsSendPort) && |
| 409 (_receivePort == other._receivePort); | 420 (_receivePort == other._receivePort); |
| 410 | 421 |
| 411 int hashCode() => _receivePort._id; | 422 int hashCode() => _receivePort._id; |
| 412 } | 423 } |
| 413 | 424 |
| 414 /** A send port that delivers messages via worker.postMessage. */ | 425 /** A send port that delivers messages via worker.postMessage. */ |
| 415 class WorkerSendPort extends BaseSendPort implements SendPort { | 426 class WorkerSendPort extends BaseSendPort implements SendPort { |
| 416 final int _workerId; | 427 final int _workerId; |
| 417 final int _receivePortId; | 428 final int _receivePortId; |
| 418 | 429 |
| 419 const WorkerSendPort(this._workerId, int isolateId, this._receivePortId) | 430 const WorkerSendPort(this._workerId, int isolateId, this._receivePortId) |
| 420 : super(isolateId); | 431 : super(isolateId); |
| 421 | 432 |
| 422 void send(var message, [SendPort replyTo = null]) { | 433 void send(var message, [SendPort replyTo = null]) { |
| 423 checkReplyTo(replyTo); | 434 _waitForPendingPorts([message, replyTo], () { |
| 424 final workerMessage = _serializeMessage({ | 435 checkReplyTo(replyTo); |
| 425 'command': 'message', | 436 final workerMessage = _serializeMessage({ |
| 426 'port': this, | 437 'command': 'message', |
| 427 'msg': message, | 438 'port': this, |
| 428 'replyTo': replyTo}); | 439 'msg': message, |
| 440 'replyTo': replyTo}); |
| 429 | 441 |
| 430 if (_globalState.isWorker) { | 442 if (_globalState.isWorker) { |
| 431 // communication from one worker to another go through the main worker: | 443 // communication from one worker to another go through the main worker: |
| 432 _globalState.mainWorker.postMessage(workerMessage); | 444 _globalState.mainWorker.postMessage(workerMessage); |
| 433 } else { | 445 } else { |
| 434 _globalState.workers[_workerId].postMessage(workerMessage); | 446 _globalState.workers[_workerId].postMessage(workerMessage); |
| 435 } | 447 } |
| 448 }); |
| 436 } | 449 } |
| 437 | 450 |
| 438 bool operator ==(var other) { | 451 bool operator ==(var other) { |
| 439 return (other is WorkerSendPort) && | 452 return (other is WorkerSendPort) && |
| 440 (_workerId == other._workerId) && | 453 (_workerId == other._workerId) && |
| 441 (_isolateId == other._isolateId) && | 454 (_isolateId == other._isolateId) && |
| 442 (_receivePortId == other._receivePortId); | 455 (_receivePortId == other._receivePortId); |
| 443 } | 456 } |
| 444 | 457 |
| 445 int hashCode() { | 458 int hashCode() { |
| 446 // TODO(sigmund): use a standard hash when we get one available in corelib. | 459 // TODO(sigmund): use a standard hash when we get one available in corelib. |
| 447 return (_workerId << 16) ^ (_isolateId << 8) ^ _receivePortId; | 460 return (_workerId << 16) ^ (_isolateId << 8) ^ _receivePortId; |
| 448 } | 461 } |
| 449 } | 462 } |
| 450 | 463 |
| 464 /** A port that buffers messages until an underlying port gets resolved. */ |
| 465 class BufferingSendPort extends BaseSendPort implements SendPort { |
| 466 /** Internal counter to assign unique ids to each port. */ |
| 467 static int _idCount = 0; |
| 468 |
| 469 /** For implementing equals and hashcode. */ |
| 470 final int _id; |
| 471 |
| 472 /** Underlying port, when resolved. */ |
| 473 SendPort _port; |
| 474 |
| 475 /** |
| 476 * Future of the underlying port, so that we can detect when this port can be |
| 477 * sent on messages. |
| 478 */ |
| 479 Future<SendPort> _futurePort; |
| 480 |
| 481 /** Pending messages (and reply ports). */ |
| 482 List pending; |
| 483 |
| 484 BufferingSendPort(isolateId, this._futurePort) |
| 485 : super(isolateId), _id = _idCount, pending = [] { |
| 486 _idCount++; |
| 487 _futurePort.then((p) { |
| 488 _port = p; |
| 489 for (final item in pending) { |
| 490 p.send(item['message'], item['replyTo']); |
| 491 } |
| 492 pending = null; |
| 493 }); |
| 494 } |
| 495 |
| 496 BufferingSendPort.fromPort(isolateId, this._port) |
| 497 : super(isolateId), _id = _idCount { |
| 498 _idCount++; |
| 499 } |
| 500 |
| 501 void send(var message, [SendPort replyTo]) { |
| 502 if (_port != null) { |
| 503 _port.send(message, replyTo); |
| 504 } else { |
| 505 pending.add({'message': message, 'replyTo': replyTo}); |
| 506 } |
| 507 } |
| 508 |
| 509 bool operator ==(var other) => other is BufferingSendPort && _id == other._id; |
| 510 int hashCode() => _id; |
| 511 } |
| 512 |
| 451 /** Default factory for receive ports. */ | 513 /** Default factory for receive ports. */ |
| 452 class ReceivePortFactory { | 514 class ReceivePortFactory { |
| 453 | 515 |
| 454 factory ReceivePort() { | 516 factory ReceivePort() { |
| 455 return new ReceivePortImpl(); | 517 return new ReceivePortImpl(); |
| 456 } | 518 } |
| 457 | 519 |
| 458 factory ReceivePort.singleShot() { | 520 factory ReceivePort.singleShot() { |
| 459 return new ReceivePortSingleShotImpl(); | 521 return new ReceivePortSingleShotImpl(); |
| 460 } | 522 } |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 529 | 591 |
| 530 return completer.future; | 592 return completer.future; |
| 531 } | 593 } |
| 532 | 594 |
| 533 static SendPort _startWorker(Isolate runnable, SendPort replyPort) { | 595 static SendPort _startWorker(Isolate runnable, SendPort replyPort) { |
| 534 var factoryName = _getJSConstructorName(runnable); | 596 var factoryName = _getJSConstructorName(runnable); |
| 535 if (_globalState.isWorker) { | 597 if (_globalState.isWorker) { |
| 536 _globalState.mainWorker.postMessage(_serializeMessage({ | 598 _globalState.mainWorker.postMessage(_serializeMessage({ |
| 537 'command': 'spawn-worker', | 599 'command': 'spawn-worker', |
| 538 'factoryName': factoryName, | 600 'factoryName': factoryName, |
| 539 'replyPort': replyPort})); | 601 'replyPort': _serializeMessage(replyPort)})); |
| 540 } else { | 602 } else { |
| 541 _spawnWorker(factoryName, _serializeMessage(replyPort)); | 603 _spawnWorker(factoryName, _serializeMessage(replyPort)); |
| 542 } | 604 } |
| 543 } | 605 } |
| 544 | 606 |
| 545 | |
| 546 /** | 607 /** |
| 547 * The src url for the script tag that loaded this code. Used to create | 608 * The src url for the script tag that loaded this code. Used to create |
| 548 * JavaScript workers. | 609 * JavaScript workers. |
| 549 */ | 610 */ |
| 550 static String get _thisScript() => | 611 static String get _thisScript() => |
| 551 _thisScriptCache != null ? _thisScriptCache : _computeThisScript(); | 612 _thisScriptCache != null ? _thisScriptCache : _computeThisScript(); |
| 552 | 613 |
| 553 static String _thisScriptCache; | 614 static String _thisScriptCache; |
| 554 | 615 |
| 555 // TODO(sigmund): fix - this code should be run synchronously when loading the | 616 // TODO(sigmund): fix - this code should be run synchronously when loading the |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 601 */ | 662 */ |
| 602 static _getEventData(e) native "return e.data"; | 663 static _getEventData(e) native "return e.data"; |
| 603 | 664 |
| 604 /** | 665 /** |
| 605 * Process messages on a worker, either to control the worker instance or to | 666 * Process messages on a worker, either to control the worker instance or to |
| 606 * pass messages along to the isolate running in the worker. | 667 * pass messages along to the isolate running in the worker. |
| 607 */ | 668 */ |
| 608 static void _processWorkerMessage(sender, e) { | 669 static void _processWorkerMessage(sender, e) { |
| 609 var msg = _deserializeMessage(_getEventData(e)); | 670 var msg = _deserializeMessage(_getEventData(e)); |
| 610 switch (msg['command']) { | 671 switch (msg['command']) { |
| 672 // TODO(sigmund): delete after we migrate to Isolate2 |
| 611 case 'start': | 673 case 'start': |
| 612 _globalState.currentWorkerId = msg['id']; | 674 _globalState.currentWorkerId = msg['id']; |
| 613 var runnerObject = | 675 var runnerObject = |
| 614 _allocate(_getJSConstructorFromName(msg['factoryName'])); | 676 _allocate(_getJSConstructorFromName(msg['factoryName'])); |
| 615 var serializedReplyTo = msg['replyTo']; | 677 var serializedReplyTo = msg['replyTo']; |
| 616 _globalState.topEventLoop.enqueue(new IsolateContext(), function() { | 678 _globalState.topEventLoop.enqueue(new IsolateContext(), function() { |
| 617 var replyTo = _deserializeMessage(serializedReplyTo); | 679 var replyTo = _deserializeMessage(serializedReplyTo); |
| 618 IsolateNatives._startIsolate(runnerObject, replyTo); | 680 _startIsolate(runnerObject, replyTo); |
| 619 }, 'worker-start'); | 681 }, 'worker-start'); |
| 620 _globalState.topEventLoop.run(); | 682 _globalState.topEventLoop.run(); |
| 621 break; | 683 break; |
| 684 case 'start2': |
| 685 _globalState.currentWorkerId = msg['id']; |
| 686 Function entryPoint = _getJSFunctionFromName(msg['functionName']); |
| 687 var replyTo = _deserializeMessage(msg['replyTo']); |
| 688 _globalState.topEventLoop.enqueue(new IsolateContext(), function() { |
| 689 _startIsolate2(entryPoint, replyTo); |
| 690 }, 'worker-start'); |
| 691 _globalState.topEventLoop.run(); |
| 692 break; |
| 693 // TODO(sigmund): delete after we migrate to Isolate2 |
| 622 case 'spawn-worker': | 694 case 'spawn-worker': |
| 623 _spawnWorker(msg['factoryName'], msg['replyPort']); | 695 _spawnWorker(msg['factoryName'], msg['replyPort']); |
| 624 break; | 696 break; |
| 697 case 'spawn-worker2': |
| 698 _spawnWorker2(msg['functionName'], msg['uri'], msg['replyPort']); |
| 699 break; |
| 625 case 'message': | 700 case 'message': |
| 626 msg['port'].send(msg['msg'], msg['replyTo']); | 701 msg['port'].send(msg['msg'], msg['replyTo']); |
| 627 _globalState.topEventLoop.run(); | 702 _globalState.topEventLoop.run(); |
| 628 break; | 703 break; |
| 629 case 'close': | 704 case 'close': |
| 630 _log("Closing Worker"); | 705 _log("Closing Worker"); |
| 631 _globalState.workers.remove(sender.id); | 706 _globalState.workers.remove(sender.id); |
| 632 sender.terminate(); | 707 sender.terminate(); |
| 633 _globalState.topEventLoop.run(); | 708 _globalState.topEventLoop.run(); |
| 634 break; | 709 break; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 677 // TODO(sigmund): find a browser-generic way to support this. | 752 // TODO(sigmund): find a browser-generic way to support this. |
| 678 static var _getJSConstructorName(Isolate runnable) native """ | 753 static var _getJSConstructorName(Isolate runnable) native """ |
| 679 return runnable.constructor.name; | 754 return runnable.constructor.name; |
| 680 """; | 755 """; |
| 681 | 756 |
| 682 /** Find a constructor given it's name. */ | 757 /** Find a constructor given it's name. */ |
| 683 static var _getJSConstructorFromName(String factoryName) native """ | 758 static var _getJSConstructorFromName(String factoryName) native """ |
| 684 return \$globalThis[factoryName]; | 759 return \$globalThis[factoryName]; |
| 685 """; | 760 """; |
| 686 | 761 |
| 762 static var _getJSFunctionFromName(String functionName) native """ |
| 763 return \$globalThis[functionName]; |
| 764 """; |
| 765 |
| 766 static String _getJSFunctionName(Function f) native "return f.name || null;"; |
| 767 |
| 687 /** Create a new JavasSript object instance given it's constructor. */ | 768 /** Create a new JavasSript object instance given it's constructor. */ |
| 688 static var _allocate(var ctor) native "return new ctor();"; | 769 static var _allocate(var ctor) native "return new ctor();"; |
| 689 | 770 |
| 690 /** Starts a non-worker isolate. */ | 771 /** Starts a non-worker isolate. */ |
| 691 static SendPort _startNonWorker(Isolate runnable, SendPort replyTo) { | 772 static SendPort _startNonWorker(Isolate runnable, SendPort replyTo) { |
| 692 // Spawn a new isolate and create the receive port in it. | 773 // Spawn a new isolate and create the receive port in it. |
| 693 final spawned = new IsolateContext(); | 774 final spawned = new IsolateContext(); |
| 694 | 775 |
| 695 // Instead of just running the provided runnable, we create a | 776 // Instead of just running the provided runnable, we create a |
| 696 // new cloned instance of it with a fresh state in the spawned | 777 // new cloned instance of it with a fresh state in the spawned |
| 697 // isolate. This way, we do not get cross-isolate references | 778 // isolate. This way, we do not get cross-isolate references |
| 698 // through the runnable. | 779 // through the runnable. |
| 699 final ctor = _getJSConstructor(runnable); | 780 final ctor = _getJSConstructor(runnable); |
| 700 _globalState.topEventLoop.enqueue(spawned, function() { | 781 _globalState.topEventLoop.enqueue(spawned, function() { |
| 701 _startIsolate(_allocate(ctor), replyTo); | 782 _startIsolate(_allocate(ctor), replyTo); |
| 702 }, 'nonworker start'); | 783 }, 'nonworker start'); |
| 703 } | 784 } |
| 704 | 785 |
| 705 /** Given a ready-to-start runnable, start running it. */ | 786 /** Given a ready-to-start runnable, start running it. */ |
| 706 static void _startIsolate(Isolate isolate, SendPort replyTo) { | 787 static void _startIsolate(Isolate isolate, SendPort replyTo) { |
| 707 _fillStatics(_globalState.currentContext); | 788 _fillStatics(_globalState.currentContext); |
| 708 ReceivePort port = new ReceivePort(); | 789 ReceivePort port = new ReceivePort(); |
| 709 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); | 790 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); |
| 710 isolate._run(port); | 791 isolate._run(port); |
| 711 } | 792 } |
| 793 |
| 794 // TODO(sigmund): clean up above, after we make the new API the default: |
| 795 |
| 796 static _spawn2(String functionName, String uri, bool isLight) { |
| 797 Completer<SendPort> completer = new Completer<SendPort>(); |
| 798 ReceivePort port = new ReceivePort.singleShot(); |
| 799 port.receive((msg, SendPort replyPort) { |
| 800 assert(msg == _SPAWNED_SIGNAL); |
| 801 completer.complete(replyPort); |
| 802 }); |
| 803 |
| 804 SendPort signalReply = port.toSendPort(); |
| 805 |
| 806 if (_globalState.useWorkers && !isLight) { |
| 807 _startWorker2(functionName, uri, signalReply); |
| 808 } else { |
| 809 _startNonWorker2(functionName, uri, signalReply); |
| 810 } |
| 811 return new BufferingSendPort( |
| 812 _globalState.currentContext.id, completer.future); |
| 813 } |
| 814 |
| 815 static SendPort _startWorker2( |
| 816 String functionName, String uri, SendPort replyPort) { |
| 817 if (_globalState.isWorker) { |
| 818 _globalState.mainWorker.postMessage(_serializeMessage({ |
| 819 'command': 'spawn-worker2', |
| 820 'functionName': functionName, |
| 821 'uri': uri, |
| 822 'replyPort': replyPort})); |
| 823 } else { |
| 824 _spawnWorker2(functionName, uri, replyPort); |
| 825 } |
| 826 } |
| 827 |
| 828 static SendPort _startNonWorker2( |
| 829 String functionName, String uri, SendPort replyPort) { |
| 830 _globalState.topEventLoop.enqueue(new IsolateContext(), function() { |
| 831 final func = _getJSFunctionFromName(functionName); |
| 832 _startIsolate2(func, replyPort); |
| 833 }, 'nonworker start'); |
| 834 } |
| 835 |
| 836 static void _startIsolate2(Function topLevel, SendPort replyTo) { |
| 837 _fillStatics(_globalState.currentContext); |
| 838 final port = new ReceivePort(); |
| 839 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); |
| 840 topLevel(port); |
| 841 } |
| 842 |
| 843 /** |
| 844 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor |
| 845 * name for the isolate entry point class. |
| 846 */ |
| 847 static void _spawnWorker2(functionName, uri, replyPort) { |
| 848 if (uri == null) uri = _thisScript; |
| 849 final worker = _newWorker(uri); |
| 850 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; |
| 851 var workerId = _globalState.nextWorkerId++; |
| 852 // We also store the id on the worker itself so that we can unregister it. |
| 853 worker.id = workerId; |
| 854 _globalState.workers[workerId] = worker; |
| 855 worker.postMessage(_serializeMessage({ |
| 856 'command': 'start2', |
| 857 'id': workerId, |
| 858 // Note: we serialize replyPort twice because the child worker needs to |
| 859 // first deserialize the worker id, before it can correctly deserialize |
| 860 // the port (port deserialization is sensitive to what is the current |
| 861 // workerId). |
| 862 'replyTo': _serializeMessage(replyPort), |
| 863 'functionName': functionName })); |
| 864 } |
| 712 } | 865 } |
| 866 |
| 867 class Isolate2Impl implements Isolate2 { |
| 868 SendPort sendPort; |
| 869 |
| 870 Isolate2Impl(this.sendPort); |
| 871 |
| 872 void stop() {} |
| 873 } |
| 874 |
| 875 class IsolateFactory implements Isolate2 { |
| 876 |
| 877 factory Isolate2.fromCode(Function topLevelFunction) { |
| 878 final name = IsolateNatives._getJSFunctionName(topLevelFunction); |
| 879 if (name == null) { |
| 880 throw new UnsupportedOperationException( |
| 881 "only top-level functions can be spawned."); |
| 882 } |
| 883 return new Isolate2Impl(IsolateNatives._spawn2(name, null, false)); |
| 884 } |
| 885 |
| 886 factory Isolate2.fromUri(String uri) { |
| 887 return new Isolate2Impl(IsolateNatives._spawn2(null, uri, false)); |
| 888 } |
| 889 } |
| OLD | NEW |