Chromium Code Reviews| 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 isolat e |
|
eub
2012/02/10 22:46:19
Line length?
Siggi Cherem (dart-lang)
2012/02/10 23:42:22
Done.
| |
| 383 // communication restrictions are respected between isolates that live in | 393 // communication restrictions are respected between isolates that live in |
| 384 // the same worker. NativeJsSendPort delivers both messages from the same | 394 // the same worker. NativeJsSendPort delivers both messages from the same |
| 385 // worker and messages from other workers. In particular, messages sent from | 395 // worker and messages from other workers. In particular, messages sent fr om |
| 386 // a worker via a WorkerSendPort are received at [_processWorkerMessage] and | 396 // a worker via a WorkerSendPort are received at [_processWorkerMessage] a nd |
| 387 // forwarded to a native port. In such cases, here we'll see | 397 // forwarded to a native port. In such cases, here we'll see |
| 388 // [_globalState.currentContext == null]. | 398 // [_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': _serializeMessage(this), |
| 428 'replyTo': replyTo}); | 439 'msg': message, |
| 440 'replyTo': _serializeMessage(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 resolve. */ | |
|
eub
2012/02/10 22:46:19
("resolved")
Siggi Cherem (dart-lang)
2012/02/10 23:42:22
Done.
| |
| 465 class BufferingSendPort extends BaseSendPort implements SendPort { | |
| 466 static int _bufferingCount = 0; | |
|
eub
2012/02/10 22:46:19
A comment, please.
Siggi Cherem (dart-lang)
2012/02/10 23:42:22
Done.
| |
| 467 | |
| 468 /** For implementing equals and hashcode. */ | |
| 469 final int id; | |
|
eub
2012/02/10 22:46:19
Why public?
Siggi Cherem (dart-lang)
2012/02/10 23:42:22
no reason. done
| |
| 470 | |
| 471 /** Underlying port, when resolved. */ | |
| 472 SendPort _port; | |
| 473 | |
| 474 /** | |
| 475 * Future of the underlying port, so that we can detect when this port can be | |
| 476 * sent on messages. | |
| 477 */ | |
| 478 Future<SendPort> _futurePort; | |
| 479 | |
| 480 /** Pending messages (and reply ports). */ | |
| 481 List pending; | |
| 482 | |
| 483 BufferingSendPort(isolateId, this._futurePort) | |
| 484 : super(isolateId), id = _bufferingCount, pending = [] { | |
| 485 _bufferingCount++; | |
|
eub
2012/02/10 22:46:19
id = _bufferingCount++
?
or a static fn that expos
Siggi Cherem (dart-lang)
2012/02/10 23:42:22
Unfortunately, if I move the id initialization her
| |
| 486 _futurePort.then((p) { | |
| 487 _port = p; | |
| 488 for (final message in pending) { | |
| 489 p.send(message[0], message[1]); | |
|
eub
2012/02/10 22:46:19
Raw access to numeric indices is oogy.
Siggi Cherem (dart-lang)
2012/02/10 23:42:22
Done - made into a map record.
| |
| 490 } | |
| 491 pending = null; | |
| 492 }); | |
| 493 } | |
| 494 | |
| 495 BufferingSendPort.fromPort(isolateId, this._port) | |
| 496 : super(isolateId), id = _bufferingCount { | |
| 497 _bufferingCount++; | |
| 498 } | |
| 499 | |
| 500 void send(var message, [SendPort replyTo]) { | |
| 501 if (_port != null) { | |
| 502 _port.send(message, replyTo); | |
| 503 } else { | |
| 504 pending.add([message, replyTo]); | |
| 505 } | |
| 506 } | |
| 507 | |
| 508 bool operator ==(var other) => (other is BufferingSendPort && id == other.id); | |
| 509 int hashCode() => id; | |
| 510 } | |
| 511 | |
| 451 /** Default factory for receive ports. */ | 512 /** Default factory for receive ports. */ |
| 452 class ReceivePortFactory { | 513 class ReceivePortFactory { |
| 453 | 514 |
| 454 factory ReceivePort() { | 515 factory ReceivePort() { |
| 455 return new ReceivePortImpl(); | 516 return new ReceivePortImpl(); |
| 456 } | 517 } |
| 457 | 518 |
| 458 factory ReceivePort.singleShot() { | 519 factory ReceivePort.singleShot() { |
| 459 return new ReceivePortSingleShotImpl(); | 520 return new ReceivePortSingleShotImpl(); |
| 460 } | 521 } |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 529 | 590 |
| 530 return completer.future; | 591 return completer.future; |
| 531 } | 592 } |
| 532 | 593 |
| 533 static SendPort _startWorker(Isolate runnable, SendPort replyPort) { | 594 static SendPort _startWorker(Isolate runnable, SendPort replyPort) { |
| 534 var factoryName = _getJSConstructorName(runnable); | 595 var factoryName = _getJSConstructorName(runnable); |
| 535 if (_globalState.isWorker) { | 596 if (_globalState.isWorker) { |
| 536 _globalState.mainWorker.postMessage(_serializeMessage({ | 597 _globalState.mainWorker.postMessage(_serializeMessage({ |
| 537 'command': 'spawn-worker', | 598 'command': 'spawn-worker', |
| 538 'factoryName': factoryName, | 599 'factoryName': factoryName, |
| 539 'replyPort': replyPort})); | 600 'replyPort': _serializeMessage(replyPort)})); |
| 540 } else { | 601 } else { |
| 541 _spawnWorker(factoryName, _serializeMessage(replyPort)); | 602 _spawnWorker(factoryName, _serializeMessage(replyPort)); |
| 542 } | 603 } |
| 543 } | 604 } |
| 544 | 605 |
| 545 | |
| 546 /** | 606 /** |
| 547 * The src url for the script tag that loaded this code. Used to create | 607 * The src url for the script tag that loaded this code. Used to create |
| 548 * JavaScript workers. | 608 * JavaScript workers. |
| 549 */ | 609 */ |
| 550 static String get _thisScript() => | 610 static String get _thisScript() => |
| 551 _thisScriptCache != null ? _thisScriptCache : _computeThisScript(); | 611 _thisScriptCache != null ? _thisScriptCache : _computeThisScript(); |
| 552 | 612 |
| 553 static String _thisScriptCache; | 613 static String _thisScriptCache; |
| 554 | 614 |
| 555 // TODO(sigmund): fix - this code should be run synchronously when loading the | 615 // 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 */ | 661 */ |
| 602 static _getEventData(e) native "return e.data"; | 662 static _getEventData(e) native "return e.data"; |
| 603 | 663 |
| 604 /** | 664 /** |
| 605 * Process messages on a worker, either to control the worker instance or to | 665 * Process messages on a worker, either to control the worker instance or to |
| 606 * pass messages along to the isolate running in the worker. | 666 * pass messages along to the isolate running in the worker. |
| 607 */ | 667 */ |
| 608 static void _processWorkerMessage(sender, e) { | 668 static void _processWorkerMessage(sender, e) { |
| 609 var msg = _deserializeMessage(_getEventData(e)); | 669 var msg = _deserializeMessage(_getEventData(e)); |
| 610 switch (msg['command']) { | 670 switch (msg['command']) { |
| 671 // TODO(sigmund): delete after we migrate to Isolate2 | |
| 611 case 'start': | 672 case 'start': |
| 612 _globalState.currentWorkerId = msg['id']; | 673 _globalState.currentWorkerId = msg['id']; |
| 613 var runnerObject = | 674 var runnerObject = |
| 614 _allocate(_getJSConstructorFromName(msg['factoryName'])); | 675 _allocate(_getJSConstructorFromName(msg['factoryName'])); |
| 615 var serializedReplyTo = msg['replyTo']; | 676 var serializedReplyTo = msg['replyTo']; |
| 616 _globalState.topEventLoop.enqueue(new IsolateContext(), function() { | 677 _globalState.topEventLoop.enqueue(new IsolateContext(), function() { |
| 617 var replyTo = _deserializeMessage(serializedReplyTo); | 678 var replyTo = _deserializeMessage(serializedReplyTo); |
| 618 IsolateNatives._startIsolate(runnerObject, replyTo); | 679 _startIsolate(runnerObject, replyTo); |
| 619 }, 'worker-start'); | 680 }, 'worker-start'); |
| 620 _globalState.topEventLoop.run(); | 681 _globalState.topEventLoop.run(); |
| 621 break; | 682 break; |
| 683 case 'start2': | |
| 684 _globalState.currentWorkerId = msg['id']; | |
| 685 Function entryPoint = _getJSFunctionFromName(msg['functionName']); | |
| 686 var replyTo = _deserializeMessage(msg['replyTo']); | |
| 687 _globalState.topEventLoop.enqueue(new IsolateContext(), function() { | |
| 688 _startIsolate2(entryPoint, replyTo); | |
| 689 }, 'worker-start'); | |
| 690 _globalState.topEventLoop.run(); | |
| 691 break; | |
| 692 // TODO(sigmund): delete after we migrate to Isolate2 | |
| 622 case 'spawn-worker': | 693 case 'spawn-worker': |
| 623 _spawnWorker(msg['factoryName'], msg['replyPort']); | 694 _spawnWorker(msg['factoryName'], msg['replyPort']); |
| 624 break; | 695 break; |
| 696 case 'spawn-worker2': | |
| 697 _spawnWorker2(msg['functionName'], msg['uri'], msg['replyPort']); | |
| 698 break; | |
| 625 case 'message': | 699 case 'message': |
| 626 msg['port'].send(msg['msg'], msg['replyTo']); | 700 final iid = _globalState.currentContext == null ? '?' : '${_globalState. currentContext.id }'; |
|
eub
2012/02/10 22:46:19
Dead code?
Siggi Cherem (dart-lang)
2012/02/10 23:42:22
yep, done.
| |
| 701 final port = _deserializeMessage(msg['port']); | |
| 702 port.send(msg['msg'], _deserializeMessage(msg['replyTo'])); | |
| 627 _globalState.topEventLoop.run(); | 703 _globalState.topEventLoop.run(); |
| 628 break; | 704 break; |
| 629 case 'close': | 705 case 'close': |
| 630 _log("Closing Worker"); | 706 _log("Closing Worker"); |
| 631 _globalState.workers.remove(sender.id); | 707 _globalState.workers.remove(sender.id); |
| 632 sender.terminate(); | 708 sender.terminate(); |
| 633 _globalState.topEventLoop.run(); | 709 _globalState.topEventLoop.run(); |
| 634 break; | 710 break; |
| 635 case 'log': | 711 case 'log': |
| 636 _log(msg['msg']); | 712 _log(msg['msg']); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 677 // TODO(sigmund): find a browser-generic way to support this. | 753 // TODO(sigmund): find a browser-generic way to support this. |
| 678 static var _getJSConstructorName(Isolate runnable) native """ | 754 static var _getJSConstructorName(Isolate runnable) native """ |
| 679 return runnable.constructor.name; | 755 return runnable.constructor.name; |
| 680 """; | 756 """; |
| 681 | 757 |
| 682 /** Find a constructor given it's name. */ | 758 /** Find a constructor given it's name. */ |
| 683 static var _getJSConstructorFromName(String factoryName) native """ | 759 static var _getJSConstructorFromName(String factoryName) native """ |
| 684 return \$globalThis[factoryName]; | 760 return \$globalThis[factoryName]; |
| 685 """; | 761 """; |
| 686 | 762 |
| 763 static var _getJSFunctionFromName(String functionName) native """ | |
| 764 return \$globalThis[functionName]; | |
| 765 """; | |
| 766 | |
| 767 static String _getJSFunctionName(Function f) native "return f.name || null;"; | |
| 768 | |
| 687 /** Create a new JavasSript object instance given it's constructor. */ | 769 /** Create a new JavasSript object instance given it's constructor. */ |
| 688 static var _allocate(var ctor) native "return new ctor();"; | 770 static var _allocate(var ctor) native "return new ctor();"; |
| 689 | 771 |
| 690 /** Starts a non-worker isolate. */ | 772 /** Starts a non-worker isolate. */ |
| 691 static SendPort _startNonWorker(Isolate runnable, SendPort replyTo) { | 773 static SendPort _startNonWorker(Isolate runnable, SendPort replyTo) { |
| 692 // Spawn a new isolate and create the receive port in it. | 774 // Spawn a new isolate and create the receive port in it. |
| 693 final spawned = new IsolateContext(); | 775 final spawned = new IsolateContext(); |
| 694 | 776 |
| 695 // Instead of just running the provided runnable, we create a | 777 // Instead of just running the provided runnable, we create a |
| 696 // new cloned instance of it with a fresh state in the spawned | 778 // new cloned instance of it with a fresh state in the spawned |
| 697 // isolate. This way, we do not get cross-isolate references | 779 // isolate. This way, we do not get cross-isolate references |
| 698 // through the runnable. | 780 // through the runnable. |
| 699 final ctor = _getJSConstructor(runnable); | 781 final ctor = _getJSConstructor(runnable); |
| 700 _globalState.topEventLoop.enqueue(spawned, function() { | 782 _globalState.topEventLoop.enqueue(spawned, function() { |
| 701 _startIsolate(_allocate(ctor), replyTo); | 783 _startIsolate(_allocate(ctor), replyTo); |
| 702 }, 'nonworker start'); | 784 }, 'nonworker start'); |
| 703 } | 785 } |
| 704 | 786 |
| 705 /** Given a ready-to-start runnable, start running it. */ | 787 /** Given a ready-to-start runnable, start running it. */ |
| 706 static void _startIsolate(Isolate isolate, SendPort replyTo) { | 788 static void _startIsolate(Isolate isolate, SendPort replyTo) { |
| 707 _fillStatics(_globalState.currentContext); | 789 _fillStatics(_globalState.currentContext); |
| 708 ReceivePort port = new ReceivePort(); | 790 ReceivePort port = new ReceivePort(); |
| 709 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); | 791 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); |
| 710 isolate._run(port); | 792 isolate._run(port); |
| 711 } | 793 } |
| 794 | |
| 795 // TODO(sigmund): clean up above, after we make the new API the default: | |
| 796 | |
| 797 static _spawn2(String functionName, String uri, bool isLight) { | |
| 798 Completer<SendPort> completer = new Completer<SendPort>(); | |
| 799 ReceivePort port = new ReceivePort.singleShot(); | |
| 800 port.receive((msg, SendPort replyPort) { | |
| 801 assert(msg == _SPAWNED_SIGNAL); | |
| 802 completer.complete(replyPort); | |
| 803 }); | |
| 804 | |
| 805 SendPort signalReply = port.toSendPort(); | |
| 806 | |
| 807 if (_globalState.useWorkers && !isLight) { | |
| 808 _startWorker2(functionName, uri, signalReply); | |
| 809 } else { | |
| 810 _startNonWorker2(functionName, uri, signalReply); | |
| 811 } | |
| 812 return new BufferingSendPort( | |
| 813 _globalState.currentContext.id, completer.future); | |
| 814 } | |
| 815 | |
| 816 static SendPort _startWorker2( | |
| 817 String functionName, String uri, SendPort replyPort) { | |
| 818 if (_globalState.isWorker) { | |
| 819 _globalState.mainWorker.postMessage(_serializeMessage({ | |
| 820 'command': 'spawn-worker2', | |
| 821 'functionName': functionName, | |
| 822 'uri': uri, | |
| 823 'replyPort': replyPort})); | |
| 824 } else { | |
| 825 _spawnWorker2(functionName, uri, replyPort); | |
| 826 } | |
| 827 } | |
| 828 | |
| 829 static SendPort _startNonWorker2( | |
| 830 String functionName, String uri, SendPort replyPort) { | |
| 831 _globalState.topEventLoop.enqueue(new IsolateContext(), function() { | |
| 832 final func = _getJSFunctionFromName(functionName); | |
| 833 _startIsolate2(func, replyPort); | |
| 834 }, 'nonworker start'); | |
| 835 } | |
| 836 | |
| 837 static void _startIsolate2(Function topLevel, SendPort replyTo) { | |
| 838 _fillStatics(_globalState.currentContext); | |
| 839 final port = new ReceivePort(); | |
| 840 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); | |
| 841 topLevel(port); | |
| 842 } | |
| 843 | |
| 844 /** | |
| 845 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor | |
| 846 * name for the isolate entry point class. | |
| 847 */ | |
| 848 static void _spawnWorker2(functionName, uri, replyPort) { | |
| 849 if (uri == null) uri = _thisScript; | |
| 850 final worker = _newWorker(uri); | |
| 851 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; | |
| 852 var workerId = _globalState.nextWorkerId++; | |
| 853 // We also store the id on the worker itself so that we can unregister it. | |
| 854 worker.id = workerId; | |
| 855 _globalState.workers[workerId] = worker; | |
| 856 worker.postMessage(_serializeMessage({ | |
| 857 'command': 'start2', | |
| 858 'id': workerId, | |
| 859 // Note: we serialize replyPort twice because the child worker needs to | |
| 860 // first deserialize the worker id, before it can correctly deserialize | |
| 861 // the port (port deserialization is sensitive to what is the current | |
| 862 // workerId). | |
| 863 'replyTo': _serializeMessage(replyPort), | |
| 864 'functionName': functionName })); | |
| 865 } | |
| 712 } | 866 } |
| 867 | |
| 868 class Isolate2Impl implements Isolate2 { | |
| 869 SendPort sendPort; | |
| 870 | |
| 871 Isolate2Impl(this.sendPort); | |
| 872 | |
| 873 void stop() {} | |
| 874 } | |
| 875 | |
| 876 class IsolateFactory implements Isolate2 { | |
| 877 | |
| 878 factory Isolate2.fromCode(Function topLevelFunction) { | |
| 879 final name = IsolateNatives._getJSFunctionName(topLevelFunction); | |
| 880 if (name == null) { | |
| 881 throw new UnsupportedOperationException( | |
| 882 "only top-level functions can be spawned."); | |
| 883 } | |
| 884 return new Isolate2Impl(IsolateNatives._spawn2(name, null, false)); | |
| 885 } | |
| 886 | |
| 887 factory Isolate2.fromUri(String uri) { | |
| 888 return new Isolate2Impl(IsolateNatives._spawn2(null, uri, false)); | |
| 889 } | |
| 890 } | |
| OLD | NEW |