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

Side by Side Diff: dart/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart

Issue 15132006: Remove _WorkerStub hack to make benefit closing an isolate. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Fix type errors Created 7 years, 7 months 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
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 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection' show Queue, HashMap; 8 import 'dart:collection' show Queue, HashMap;
9 import 'dart:isolate'; 9 import 'dart:isolate';
10 import 'dart:_js_helper' show convertDartClosureToJS, 10 import 'dart:_js_helper' show convertDartClosureToJS,
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 * "manager" - A manager contains one or more isolates, schedules their 100 * "manager" - A manager contains one or more isolates, schedules their
101 * execution, and performs other plumbing on their behalf. The isolate 101 * execution, and performs other plumbing on their behalf. The isolate
102 * present at the creation of the manager is designated as its "root isolate". 102 * present at the creation of the manager is designated as its "root isolate".
103 * A manager may, for example, be implemented on a web Worker. 103 * A manager may, for example, be implemented on a web Worker.
104 * 104 *
105 * [_Manager] - State present within a manager (exactly once, as a global). 105 * [_Manager] - State present within a manager (exactly once, as a global).
106 * 106 *
107 * [_ManagerStub] - A handle held within one manager that allows interaction 107 * [_ManagerStub] - A handle held within one manager that allows interaction
108 * with another manager. A target manager may be addressed by zero or more 108 * with another manager. A target manager may be addressed by zero or more
109 * [_ManagerStub]s. 109 * [_ManagerStub]s.
110 * 110 * TODO(ahe): The _ManagerStub concept is broken. It was an attempt
111 * to create a common interface between the native Worker class and
112 * _MainManagerStub.
111 */ 113 */
112 114
113 /** 115 /**
114 * A native object that is shared across isolates. This object is visible to all 116 * A native object that is shared across isolates. This object is visible to all
115 * isolates running under the same manager (either UI or background web worker). 117 * isolates running under the same manager (either UI or background web worker).
116 * 118 *
117 * This is code that is intended to 'escape' the isolate boundaries in order to 119 * This is code that is intended to 'escape' the isolate boundaries in order to
118 * implement the semantics of isolates in JavaScript. Without this we would have 120 * implement the semantics of isolates in JavaScript. Without this we would have
119 * been forced to implement more code (including the top-level event loop) in 121 * been forced to implement more code (including the top-level event loop) in
120 * JavaScript itself. 122 * JavaScript itself.
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
176 bool get needSerialization => useWorkers; 178 bool get needSerialization => useWorkers;
177 179
178 /** 180 /**
179 * Registry of isolates. Isolates must be registered if, and only if, receive 181 * Registry of isolates. Isolates must be registered if, and only if, receive
180 * ports are alive. Normally no open receive-ports means that the isolate is 182 * ports are alive. Normally no open receive-ports means that the isolate is
181 * dead, but DOM callbacks could resurrect it. 183 * dead, but DOM callbacks could resurrect it.
182 */ 184 */
183 Map<int, _IsolateContext> isolates; 185 Map<int, _IsolateContext> isolates;
184 186
185 /** Reference to the main [_Manager]. Null in the main [_Manager] itself. */ 187 /** Reference to the main [_Manager]. Null in the main [_Manager] itself. */
186 _ManagerStub mainManager; 188 _MainManagerStub mainManager;
187 189
188 /** Registry of active [_ManagerStub]s. Only used in the main [_Manager]. */ 190 /// Registry of active Web Workers. Only used in the main [_Manager].
189 Map<int, _ManagerStub> managers; 191 Map<int, dynamic /* Worker */> managers;
190 192
191 /** The entry point given by [startRootIsolate]. */ 193 /** The entry point given by [startRootIsolate]. */
192 final Function entry; 194 final Function entry;
193 195
194 _Manager(this.entry) { 196 _Manager(this.entry) {
195 _nativeDetectEnvironment(); 197 _nativeDetectEnvironment();
196 topEventLoop = new _EventLoop(); 198 topEventLoop = new _EventLoop();
197 isolates = new Map<int, _IsolateContext>(); 199 isolates = new Map<int, _IsolateContext>();
198 managers = new Map<int, _ManagerStub>(); 200 managers = new Map<int, dynamic>();
199 if (isWorker) { // "if we are not the main manager ourself" is the intent. 201 if (isWorker) { // "if we are not the main manager ourself" is the intent.
200 mainManager = new _MainManagerStub(); 202 mainManager = new _MainManagerStub();
201 _nativeInitWorkerMessageHandler(); 203 _nativeInitWorkerMessageHandler();
202 } 204 }
203 } 205 }
204 206
205 void _nativeDetectEnvironment() { 207 void _nativeDetectEnvironment() {
206 bool isWindowDefined = globalWindow != null; 208 bool isWindowDefined = globalWindow != null;
207 bool isWorkerDefined = globalWorker != null; 209 bool isWorkerDefined = globalWorker != null;
208 210
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 Function fn; 385 Function fn;
384 String message; 386 String message;
385 387
386 _IsolateEvent(this.isolate, this.fn, this.message); 388 _IsolateEvent(this.isolate, this.fn, this.message);
387 389
388 void process() { 390 void process() {
389 isolate.eval(fn); 391 isolate.eval(fn);
390 } 392 }
391 } 393 }
392 394
393 /** An interface for a stub used to interact with a manager. */
394 abstract class _ManagerStub {
395 get id;
396 void set id(int i);
397 void set onmessage(Function f);
398 void postMessage(msg);
399 void terminate();
400 }
401
402 /** A stub for interacting with the main manager. */ 395 /** A stub for interacting with the main manager. */
403 class _MainManagerStub implements _ManagerStub { 396 class _MainManagerStub {
404 get id => 0; 397 void postMessage(msg) {
405 void set id(int i) { throw new UnimplementedError(); } 398 JS("void", r"self.postMessage(#)", msg);
ngeoffray 2013/05/15 08:33:10 What's 'self'?
ahe 2013/05/15 09:06:30 self is a way to refer to the global context objec
ngeoffray 2013/05/15 09:09:56 Thanks for the explanation, could you add it to th
ahe 2013/05/15 09:19:08 I'd like to get rid of globalThis, and I'd like to
406 void set onmessage(f) {
407 throw new Exception("onmessage should not be set on MainManagerStub");
408 } 399 }
409 void postMessage(msg) {
410 JS("void", r"#.postMessage(#)", globalThis, msg);
411 }
412 void terminate() {} // Nothing useful to do here.
413 }
414
415 /**
416 * A stub for interacting with a manager built on a web worker. This
417 * definition uses a 'hidden' type (* prefix on the native name) to
418 * enforce that the type is defined dynamically only when web workers
419 * are actually available.
420 */
421 // @Native("*Worker");
422 class _WorkerStub implements _ManagerStub {
423 get id => JS("", "#.id", this);
424 void set id(i) { JS("void", "#.id = #", this, i); }
425 void set onmessage(f) { JS("void", "#.onmessage = #", this, f); }
426 void postMessage(msg) { JS("void", "#.postMessage(#)", this, msg); }
427 void terminate() { JS("void", "#.terminate()", this); }
428 } 400 }
429 401
430 const String _SPAWNED_SIGNAL = "spawned"; 402 const String _SPAWNED_SIGNAL = "spawned";
431 403
432 var globalThis = IsolateNatives.computeGlobalThis(); 404 var globalThis = IsolateNatives.computeGlobalThis();
433 var globalWindow = JS('', "#.window", globalThis); 405 var globalWindow = JS('', "#.window", globalThis);
434 var globalWorker = JS('', "#.Worker", globalThis); 406 var globalWorker = JS('', "#.Worker", globalThis);
435 bool globalPostMessageDefined = 407 bool globalPostMessageDefined =
436 JS('', "#.postMessage !== (void 0)", globalThis); 408 JS('', "#.postMessage !== (void 0)", globalThis);
437 409
438 class IsolateNatives { 410 class IsolateNatives {
439 411
440 static String thisScript = computeThisScript(); 412 static String thisScript = computeThisScript();
441 413
414 /// Associates an ID with a native worker object.
415 static final Expando<int> workerIds = new Expando<int>();
416
442 /** 417 /**
443 * The src url for the script tag that loaded this code. Used to create 418 * The src url for the script tag that loaded this code. Used to create
444 * JavaScript workers. 419 * JavaScript workers.
445 */ 420 */
446 static String computeThisScript() { 421 static String computeThisScript() {
447 var currentScript = JS('', r'$.$currentScript'); 422 var currentScript = JS('', r'$.$currentScript');
448 if (currentScript != null) { 423 if (currentScript != null) {
449 return JS('String', 'String(#.src)', currentScript); 424 return JS('String', 'String(#.src)', currentScript);
450 } 425 }
451 426
(...skipping 29 matching lines...) Expand all
481 pattern = JS('', r'new RegExp("^[^@]*@(.*):[0-9]*$", "m")'); 456 pattern = JS('', r'new RegExp("^[^@]*@(.*):[0-9]*$", "m")');
482 457
483 matches = JS('=List|Null', '#.match(#)', stack, pattern); 458 matches = JS('=List|Null', '#.match(#)', stack, pattern);
484 if (matches != null) return JS('String', '#[1]', matches); 459 if (matches != null) return JS('String', '#[1]', matches);
485 460
486 throw new UnsupportedError('Cannot extract URI from "$stack"'); 461 throw new UnsupportedError('Cannot extract URI from "$stack"');
487 } 462 }
488 463
489 static computeGlobalThis() => JS('', 'function() { return this; }()'); 464 static computeGlobalThis() => JS('', 'function() { return this; }()');
490 465
491 /** Starts a new worker with the given URL. */
492 static _WorkerStub _newWorker(url) => JS("_WorkerStub", r"new Worker(#)", url) ;
493
494 /** 466 /**
495 * Assume that [e] is a browser message event and extract its message data. 467 * Assume that [e] is a browser message event and extract its message data.
496 * We don't import the dom explicitly so, when workers are disabled, this 468 * We don't import the dom explicitly so, when workers are disabled, this
497 * library can also run on top of nodejs. 469 * library can also run on top of nodejs.
498 */ 470 */
499 static _getEventData(e) => JS("", "#.data", e); 471 static _getEventData(e) => JS("", "#.data", e);
500 472
501 /** 473 /**
502 * Process messages on a worker, either to control the worker instance or to 474 * Process messages on a worker, either to control the worker instance or to
503 * pass messages along to the isolate running in the worker. 475 * pass messages along to the isolate running in the worker.
504 */ 476 */
505 static void _processWorkerMessage(sender, e) { 477 static void _processWorkerMessage(/* Worker */ sender, e) {
506 var msg = _deserializeMessage(_getEventData(e)); 478 var msg = _deserializeMessage(_getEventData(e));
507 switch (msg['command']) { 479 switch (msg['command']) {
508 case 'start': 480 case 'start':
509 _globalState.currentManagerId = msg['id']; 481 _globalState.currentManagerId = msg['id'];
510 String functionName = msg['functionName']; 482 String functionName = msg['functionName'];
511 Function entryPoint = (functionName == null) 483 Function entryPoint = (functionName == null)
512 ? _globalState.entry 484 ? _globalState.entry
513 : _getJSFunctionFromName(functionName); 485 : _getJSFunctionFromName(functionName);
514 var replyTo = _deserializeMessage(msg['replyTo']); 486 var replyTo = _deserializeMessage(msg['replyTo']);
515 var context = new _IsolateContext(); 487 var context = new _IsolateContext();
(...skipping 14 matching lines...) Expand all
530 break; 502 break;
531 case 'message': 503 case 'message':
532 SendPort port = msg['port']; 504 SendPort port = msg['port'];
533 // If the port has been closed, we ignore the message. 505 // If the port has been closed, we ignore the message.
534 if (port != null) { 506 if (port != null) {
535 msg['port'].send(msg['msg'], msg['replyTo']); 507 msg['port'].send(msg['msg'], msg['replyTo']);
536 } 508 }
537 _globalState.topEventLoop.run(); 509 _globalState.topEventLoop.run();
538 break; 510 break;
539 case 'close': 511 case 'close':
540 _log("Closing Worker"); 512 _globalState.managers.remove(workerIds[sender]);
541 _globalState.managers.remove(sender.id); 513 JS('void', '#.terminate()', sender);
542 sender.terminate();
543 _globalState.topEventLoop.run(); 514 _globalState.topEventLoop.run();
544 break; 515 break;
545 case 'log': 516 case 'log':
546 _log(msg['msg']); 517 _log(msg['msg']);
547 break; 518 break;
548 case 'print': 519 case 'print':
549 if (_globalState.isWorker) { 520 if (_globalState.isWorker) {
550 _globalState.mainManager.postMessage( 521 _globalState.mainManager.postMessage(
551 _serializeMessage({'command': 'print', 'msg': msg})); 522 _serializeMessage({'command': 'print', 'msg': msg}));
552 } else { 523 } else {
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
668 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); 639 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort());
669 topLevel(); 640 topLevel();
670 } 641 }
671 642
672 /** 643 /**
673 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor 644 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor
674 * name for the isolate entry point class. 645 * name for the isolate entry point class.
675 */ 646 */
676 static void _spawnWorker(functionName, uri, replyPort) { 647 static void _spawnWorker(functionName, uri, replyPort) {
677 if (uri == null) uri = thisScript; 648 if (uri == null) uri = thisScript;
678 final worker = _newWorker(uri); 649 final worker = JS('var', 'new Worker(#)', uri);
679 worker.onmessage = JS('', 650
680 'function(e) { #(#, e); }', 651 var processWorkerMessageTrampoline =
681 DART_CLOSURE_TO_JS(_processWorkerMessage), 652 JS('', 'function(e) { #(#, e); }',
682 worker); 653 DART_CLOSURE_TO_JS(_processWorkerMessage),
654 worker);
655 JS('void', '#.onmessage = #', worker, processWorkerMessageTrampoline);
683 var workerId = _globalState.nextManagerId++; 656 var workerId = _globalState.nextManagerId++;
684 // We also store the id on the worker itself so that we can unregister it. 657 // We also store the id on the worker itself so that we can unregister it.
ngeoffray 2013/05/15 08:33:10 Update comment?
ahe 2013/05/15 09:06:30 I actually think the comment still applies, I'm ju
ngeoffray 2013/05/15 09:09:56 Fine by me.
685 worker.id = workerId; 658 workerIds[worker] = workerId;
686 _globalState.managers[workerId] = worker; 659 _globalState.managers[workerId] = worker;
687 worker.postMessage(_serializeMessage({ 660 JS('void', '#.postMessage(#)', worker, _serializeMessage({
688 'command': 'start', 661 'command': 'start',
689 'id': workerId, 662 'id': workerId,
690 // Note: we serialize replyPort twice because the child worker needs to 663 // Note: we serialize replyPort twice because the child worker needs to
691 // first deserialize the worker id, before it can correctly deserialize 664 // first deserialize the worker id, before it can correctly deserialize
692 // the port (port deserialization is sensitive to what is the current 665 // the port (port deserialization is sensitive to what is the current
693 // workerId). 666 // workerId).
694 'replyTo': _serializeMessage(replyPort), 667 'replyTo': _serializeMessage(replyPort),
695 'functionName': functionName })); 668 'functionName': functionName }));
696 } 669 }
697 } 670 }
698 671
699 /******************************************************** 672 /********************************************************
700 Inserted from lib/isolate/dart2js/ports.dart 673 Inserted from lib/isolate/dart2js/ports.dart
701 ********************************************************/ 674 ********************************************************/
702 675
703 /** Common functionality to all send ports. */ 676 /** Common functionality to all send ports. */
704 class _BaseSendPort implements SendPort { 677 class _BaseSendPort implements SendPort {
705 /** Id for the destination isolate. */ 678 /** Id for the destination isolate. */
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
800 'port': this, 773 'port': this,
801 'msg': message, 774 'msg': message,
802 'replyTo': replyTo}); 775 'replyTo': replyTo});
803 776
804 if (_globalState.isWorker) { 777 if (_globalState.isWorker) {
805 // Communication from one worker to another go through the 778 // Communication from one worker to another go through the
806 // main worker. 779 // main worker.
807 _globalState.mainManager.postMessage(workerMessage); 780 _globalState.mainManager.postMessage(workerMessage);
808 } else { 781 } else {
809 // Deliver the message only if the worker is still alive. 782 // Deliver the message only if the worker is still alive.
810 _ManagerStub manager = _globalState.managers[_workerId]; 783 /* Worker */ var manager = _globalState.managers[_workerId];
811 if (manager != null) { 784 if (manager != null) {
812 manager.postMessage(workerMessage); 785 JS('void', '#.postMessage(#)', manager, workerMessage);
813 } 786 }
814 } 787 }
815 }); 788 });
816 } 789 }
817 790
818 bool operator ==(var other) { 791 bool operator ==(var other) {
819 return (other is _WorkerSendPort) && 792 return (other is _WorkerSendPort) &&
820 (_workerId == other._workerId) && 793 (_workerId == other._workerId) &&
821 (_isolateId == other._isolateId) && 794 (_isolateId == other._isolateId) &&
822 (_receivePortId == other._receivePortId); 795 (_receivePortId == other._receivePortId);
(...skipping 608 matching lines...) Expand 10 before | Expand all | Expand 10 after
1431 JS('void', '#.clearInterval(#)', globalThis, _handle); 1404 JS('void', '#.clearInterval(#)', globalThis, _handle);
1432 } 1405 }
1433 _handle = null; 1406 _handle = null;
1434 } else { 1407 } else {
1435 throw new UnsupportedError("Canceling a timer."); 1408 throw new UnsupportedError("Canceling a timer.");
1436 } 1409 }
1437 } 1410 }
1438 } 1411 }
1439 1412
1440 bool hasTimer() => JS('', '#.setTimeout', globalThis) != null; 1413 bool hasTimer() => JS('', '#.setTimeout', globalThis) != null;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698