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

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

Issue 11574032: Make unit testing of the compiler work with the new isolate helper library. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 11 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:isolate'; 8 import 'dart:isolate';
9 9
10 ReceivePort lazyPort;
11
10 /** 12 /**
11 * Called by the compiler to support switching 13 * Called by the compiler to support switching
12 * between isolates when we get a callback from the DOM. 14 * between isolates when we get a callback from the DOM.
13 */ 15 */
14 void _callInIsolate(_IsolateContext isolate, Function function) { 16 void _callInIsolate(_IsolateContext isolate, Function function) {
15 isolate.eval(function); 17 isolate.eval(function);
16 _globalState.topEventLoop.run(); 18 _globalState.topEventLoop.run();
17 } 19 }
18 20
19 /** 21 /**
20 * Called by the compiler to fetch the current isolate context. 22 * Called by the compiler to fetch the current isolate context.
21 */ 23 */
22 _IsolateContext _currentIsolate() => _globalState.currentContext; 24 _IsolateContext _currentIsolate() => _globalState.currentContext;
23 25
24 /********************************************************
25 Inserted from lib/isolate/dart2js/compiler_hooks.dart
26 ********************************************************/
27
28 /** 26 /**
29 * Wrapper that takes the dart entry point and runs it within an isolate. The 27 * Wrapper that takes the dart entry point and runs it within an isolate. The
30 * dart2js compiler will inject a call of the form 28 * dart2js compiler will inject a call of the form
31 * [: startRootIsolate(main); :] when it determines that this wrapping 29 * [: startRootIsolate(main); :] when it determines that this wrapping
32 * is needed. For single-isolate applications (e.g. hello world), this 30 * is needed. For single-isolate applications (e.g. hello world), this
33 * call is not emitted. 31 * call is not emitted.
34 */ 32 */
35 void startRootIsolate(entry) { 33 void startRootIsolate(entry) {
36 _globalState = new _Manager(); 34 _globalState = new _Manager();
37 35
38 // Don't start the main loop again, if we are in a worker. 36 // Don't start the main loop again, if we are in a worker.
39 if (_globalState.isWorker) return; 37 if (_globalState.isWorker) return;
40 final rootContext = new _IsolateContext(); 38 final rootContext = new _IsolateContext();
41 _globalState.rootContext = rootContext; 39 _globalState.rootContext = rootContext;
42 _fillStatics(rootContext);
43 40
44 // BUG(5151491): Setting currentContext should not be necessary, but 41 // BUG(5151491): Setting currentContext should not be necessary, but
45 // because closures passed to the DOM as event handlers do not bind their 42 // because closures passed to the DOM as event handlers do not bind their
46 // isolate automatically we try to give them a reasonable context to live in 43 // isolate automatically we try to give them a reasonable context to live in
47 // by having a "default" isolate (the first one created). 44 // by having a "default" isolate (the first one created).
48 _globalState.currentContext = rootContext; 45 _globalState.currentContext = rootContext;
49 46
50 rootContext.eval(entry); 47 rootContext.eval(entry);
51 _globalState.topEventLoop.run(); 48 _globalState.topEventLoop.run();
52 } 49 }
(...skipping 22 matching lines...) Expand all
75 * A native object that is shared across isolates. This object is visible to all 72 * A native object that is shared across isolates. This object is visible to all
76 * isolates running under the same manager (either UI or background web worker). 73 * isolates running under the same manager (either UI or background web worker).
77 * 74 *
78 * This is code that is intended to 'escape' the isolate boundaries in order to 75 * This is code that is intended to 'escape' the isolate boundaries in order to
79 * implement the semantics of isolates in JavaScript. Without this we would have 76 * implement the semantics of isolates in JavaScript. Without this we would have
80 * been forced to implement more code (including the top-level event loop) in 77 * been forced to implement more code (including the top-level event loop) in
81 * JavaScript itself. 78 * JavaScript itself.
82 */ 79 */
83 // TODO(eub, sigmund): move the "manager" to be entirely in JS. 80 // TODO(eub, sigmund): move the "manager" to be entirely in JS.
84 // Running any Dart code outside the context of an isolate gives it 81 // Running any Dart code outside the context of an isolate gives it
85 // the change to break the isolate abstraction. 82 // the chance to break the isolate abstraction.
86 _Manager get _globalState => JS("_Manager", r"$globalState"); 83 _Manager get _globalState => JS("_Manager", r"$globalState");
84
87 set _globalState(_Manager val) { 85 set _globalState(_Manager val) {
88 JS("void", r"$globalState = #", val); 86 JS("void", r"$globalState = #", val);
89 } 87 }
90 88
91 void _fillStatics(context) {
92 JS("void", r"$globals = #.isolateStatics", context);
93 JS("void", r"$static_init()");
94 }
95
96 ReceivePort lazyPort;
97
98 /** State associated with the current manager. See [globalState]. */ 89 /** State associated with the current manager. See [globalState]. */
99 // TODO(sigmund): split in multiple classes: global, thread, main-worker states? 90 // TODO(sigmund): split in multiple classes: global, thread, main-worker states?
100 class _Manager { 91 class _Manager {
101 92
102 /** Next available isolate id within this [_Manager]. */ 93 /** Next available isolate id within this [_Manager]. */
103 int nextIsolateId = 0; 94 int nextIsolateId = 0;
104 95
105 /** id assigned to this [_Manager]. */ 96 /** id assigned to this [_Manager]. */
106 int currentManagerId = 0; 97 int currentManagerId = 0;
107 98
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 topEventLoop = new _EventLoop(); 151 topEventLoop = new _EventLoop();
161 isolates = new Map<int, _IsolateContext>(); 152 isolates = new Map<int, _IsolateContext>();
162 managers = new Map<int, _ManagerStub>(); 153 managers = new Map<int, _ManagerStub>();
163 if (isWorker) { // "if we are not the main manager ourself" is the intent. 154 if (isWorker) { // "if we are not the main manager ourself" is the intent.
164 mainManager = new _MainManagerStub(); 155 mainManager = new _MainManagerStub();
165 _nativeInitWorkerMessageHandler(); 156 _nativeInitWorkerMessageHandler();
166 } 157 }
167 } 158 }
168 159
169 void _nativeDetectEnvironment() { 160 void _nativeDetectEnvironment() {
170 isWorker = JS("bool", r"$isWorker"); 161 bool isWindowDefined = globalWindow != null;
171 supportsWorkers = JS("bool", r"$supportsWorkers"); 162 bool isWorkerDefined = globalWorker != null;
172 fromCommandLine = JS("bool", r"typeof(window) == 'undefined'"); 163
164 isWorker = !isWindowDefined && globalPostMessageDefined;
165 supportsWorkers = isWorker
166 || (isWorkerDefined && IsolateNatives.thisScript != null);
167 fromCommandLine = !isWindowDefined && !isWorker;
173 } 168 }
174 169
175 void _nativeInitWorkerMessageHandler() { 170 void _nativeInitWorkerMessageHandler() {
176 JS("void", r""" 171 var function = JS('',
177 $globalThis.onmessage = function (e) { 172 "function (e) { #(#, e); }",
178 IsolateNatives._processWorkerMessage(this.mainManager, e); 173 DART_CLOSURE_TO_JS(IsolateNatives._processWorkerMessage),
179 }"""); 174 mainManager);
175 JS("void", r"#.onmessage = #", globalThis, function);
176 // We define dartPrint so that the implementation of the Dart
177 // print method knows what to call.
178 // TODO(ngeoffray): Should we forward to the main isolate? What if
179 // it exited?
180 JS('void', r'#.dartPrint = function (object) {}', globalThis);
180 } 181 }
181 /*: TODO: check that _processWorkerMessage is not discarded while treeshaking.
182 """ {
183 IsolateNatives._processWorkerMessage(null, null);
184 }
185 */
186 182
187 183
188 /** Close the worker running this code if all isolates are done. */ 184 /** Close the worker running this code if all isolates are done. */
189 void maybeCloseWorker() { 185 void maybeCloseWorker() {
190 if (isolates.isEmpty) { 186 if (isolates.isEmpty) {
191 mainManager.postMessage(_serializeMessage({'command': 'close'})); 187 mainManager.postMessage(_serializeMessage({'command': 'close'}));
192 } 188 }
193 } 189 }
194 } 190 }
195 191
196 /** Context information tracked for each isolate. */ 192 /** Context information tracked for each isolate. */
197 class _IsolateContext { 193 class _IsolateContext {
198 /** Current isolate id. */ 194 /** Current isolate id. */
199 int id; 195 int id;
200 196
201 /** Registry of receive ports currently active on this isolate. */ 197 /** Registry of receive ports currently active on this isolate. */
202 Map<int, ReceivePort> ports; 198 Map<int, ReceivePort> ports;
203 199
204 /** Holds isolate globals (statics and top-level properties). */ 200 /** Holds isolate globals (statics and top-level properties). */
205 var isolateStatics; // native object containing all globals of an isolate. 201 var isolateStatics; // native object containing all globals of an isolate.
206 202
207 _IsolateContext() { 203 _IsolateContext() {
208 id = _globalState.nextIsolateId++; 204 id = _globalState.nextIsolateId++;
209 ports = new Map<int, ReceivePort>(); 205 ports = new Map<int, ReceivePort>();
210 initGlobals(); 206 isolateStatics = JS_CREATE_ISOLATE();
211 } 207 }
212 208
213 // these are filled lazily the first time the isolate starts running.
214 void initGlobals() { JS("void", r'$initGlobals(#)', this); }
215
216 /** 209 /**
217 * Run [code] in the context of the isolate represented by [this]. Note this 210 * Run [code] in the context of the isolate represented by [this]. Note this
218 * is called from JavaScript (see $wrap_call in corejs.dart). 211 * is called from JavaScript (see $wrap_call in corejs.dart).
219 */ 212 */
220 dynamic eval(Function code) { 213 dynamic eval(Function code) {
221 var old = _globalState.currentContext; 214 var old = _globalState.currentContext;
222 _globalState.currentContext = this; 215 _globalState.currentContext = this;
223 this._setGlobals(); 216 this._setGlobals();
224 var result = null; 217 var result = null;
225 try { 218 try {
226 result = code(); 219 result = code();
227 } finally { 220 } finally {
228 _globalState.currentContext = old; 221 _globalState.currentContext = old;
229 if (old != null) old._setGlobals(); 222 if (old != null) old._setGlobals();
230 } 223 }
231 return result; 224 return result;
232 } 225 }
233 226
234 void _setGlobals() { JS("void", r'$setGlobals(#)', this); } 227 void _setGlobals() {
228 JS_SET_CURRENT_ISOLATE(isolateStatics);
229 }
235 230
236 /** Lookup a port registered for this isolate. */ 231 /** Lookup a port registered for this isolate. */
237 ReceivePort lookup(int portId) => ports[portId]; 232 ReceivePort lookup(int portId) => ports[portId];
238 233
239 /** Register a port on this isolate. */ 234 /** Register a port on this isolate. */
240 void register(int portId, ReceivePort port) { 235 void register(int portId, ReceivePort port) {
241 if (ports.containsKey(portId)) { 236 if (ports.containsKey(portId)) {
242 throw new Exception("Registry: ports must be registered only once."); 237 throw new Exception("Registry: ports must be registered only once.");
243 } 238 }
244 ports[portId] = port; 239 ports[portId] = port;
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
293 } 288 }
294 event.process(); 289 event.process();
295 return true; 290 return true;
296 } 291 }
297 292
298 /** 293 /**
299 * Runs multiple iterations of the run-loop. If possible, each iteration is 294 * Runs multiple iterations of the run-loop. If possible, each iteration is
300 * run asynchronously. 295 * run asynchronously.
301 */ 296 */
302 void _runHelper() { 297 void _runHelper() {
303 if (JS('String', 'typeof window') != 'undefined') { 298 if (globalWindow != null) {
304 // Run each iteration from the browser's top event loop. 299 // Run each iteration from the browser's top event loop.
305 void next() { 300 void next() {
306 if (!runIteration()) return; 301 if (!runIteration()) return;
307 JS('void', 'window.setTimeout(#, 0)', convertDartClosureToJS(next, 0)); 302 JS('void', 'window.setTimeout(#, 0)', convertDartClosureToJS(next, 0));
308 } 303 }
309 next(); 304 next();
310 } else { 305 } else {
311 // Run synchronously until no more iterations are available. 306 // Run synchronously until no more iterations are available.
312 while (runIteration()) {} 307 while (runIteration()) {}
313 } 308 }
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
353 void terminate(); 348 void terminate();
354 } 349 }
355 350
356 /** A stub for interacting with the main manager. */ 351 /** A stub for interacting with the main manager. */
357 class _MainManagerStub implements _ManagerStub { 352 class _MainManagerStub implements _ManagerStub {
358 get id => 0; 353 get id => 0;
359 void set id(int i) { throw new UnimplementedError(); } 354 void set id(int i) { throw new UnimplementedError(); }
360 void set onmessage(f) { 355 void set onmessage(f) {
361 throw new Exception("onmessage should not be set on MainManagerStub"); 356 throw new Exception("onmessage should not be set on MainManagerStub");
362 } 357 }
363 void postMessage(msg) { JS("void", r"$globalThis.postMessage(#)", msg); } 358 void postMessage(msg) {
359 JS("void", r"#.postMessage(#)", globalThis, msg);
360 }
364 void terminate() {} // Nothing useful to do here. 361 void terminate() {} // Nothing useful to do here.
365 } 362 }
366 363
367 /** 364 /**
368 * A stub for interacting with a manager built on a web worker. This 365 * A stub for interacting with a manager built on a web worker. This
369 * definition uses a 'hidden' type (* prefix on the native name) to 366 * definition uses a 'hidden' type (* prefix on the native name) to
370 * enforce that the type is defined dynamically only when web workers 367 * enforce that the type is defined dynamically only when web workers
371 * are actually available. 368 * are actually available.
372 */ 369 */
373 // TODO(ngeoffray): We comment this annotation for now because the
374 // native feature uses a keyword that this file does not have access
375 // to. We should remove the comment once the native feature uses
376 // annotations.
377 // @Native("*Worker"); 370 // @Native("*Worker");
378 class _WorkerStub implements _ManagerStub { 371 class _WorkerStub implements _ManagerStub {
379 get id => JS("var", "#.id", this); 372 get id => JS("", "#.id", this);
380 void set id(i) { JS("void", "#.id = #", this, i); } 373 void set id(i) { JS("void", "#.id = #", this, i); }
381 void set onmessage(f) { JS("void", "#.onmessage = #", this, f); } 374 void set onmessage(f) { JS("void", "#.onmessage = #", this, f); }
382 void postMessage(msg) => JS("void", "#.postMessage(#)", this, msg); 375 void postMessage(msg) { JS("void", "#.postMessage(#)", this, msg); }
383 // terminate() is implemented by Worker. 376 void terminate() { JS("void", "#.terminate()", this); }
384 void terminate();
385 } 377 }
386 378
387 const String _SPAWNED_SIGNAL = "spawned"; 379 const String _SPAWNED_SIGNAL = "spawned";
388 380
389 var globalThis = JS('', 'function() { return this; }()'); 381 var globalThis = IsolateNatives.computeGlobalThis();
382 var globalWindow = JS('', "#['window']", globalThis);
383 var globalWorker = JS('', "#['Worker']", globalThis);
384 bool globalPostMessageDefined =
385 JS('', "#['postMessage'] !== (void 0)", globalThis);
390 386
391 class IsolateNatives { 387 class IsolateNatives {
392 388
389 static String thisScript = computeThisScript();
390
393 /** 391 /**
394 * The src url for the script tag that loaded this code. Used to create 392 * The src url for the script tag that loaded this code. Used to create
395 * JavaScript workers. 393 * JavaScript workers.
396 */ 394 */
397 static String get _thisScript => JS("String", r"$thisScriptUrl"); 395 static String computeThisScript() {
396 // TODO(7369): Find a cross-platform non-brittle way of getting the
397 // currently running script.
398 var scripts = JS('=List', r"document.getElementsByTagName('script')");
399 // The scripts variable only contains the scripts that have already been
400 // executed. The last one is the currently running script.
401 for (var script in scripts) {
402 var src = JS('String|Null', '# && #.src', script, script);
403 if (src != null
404 && !src.endsWith('test_controller.js')
405 && !new RegExp('client.dart\.js').hasMatch(src)) {
406 return src;
407 }
408 }
409 return null;
410 }
411
412 static computeGlobalThis() => JS('', 'function() { return this; }()');
398 413
399 /** Starts a new worker with the given URL. */ 414 /** Starts a new worker with the given URL. */
400 static _WorkerStub _newWorker(url) => JS("_WorkerStub", r"new Worker(#)", url) ; 415 static _WorkerStub _newWorker(url) => JS("_WorkerStub", r"new Worker(#)", url) ;
401 416
402 /** 417 /**
403 * Assume that [e] is a browser message event and extract its message data. 418 * Assume that [e] is a browser message event and extract its message data.
404 * We don't import the dom explicitly so, when workers are disabled, this 419 * We don't import the dom explicitly so, when workers are disabled, this
405 * library can also run on top of nodejs. 420 * library can also run on top of nodejs.
406 */ 421 */
407 //static _getEventData(e) => JS("Object", "#.data", e);
408 static _getEventData(e) => JS("", "#.data", e); 422 static _getEventData(e) => JS("", "#.data", e);
409 423
410 /** 424 /**
411 * Process messages on a worker, either to control the worker instance or to 425 * Process messages on a worker, either to control the worker instance or to
412 * pass messages along to the isolate running in the worker. 426 * pass messages along to the isolate running in the worker.
413 */ 427 */
414 static void _processWorkerMessage(sender, e) { 428 static void _processWorkerMessage(sender, e) {
415 var msg = _deserializeMessage(_getEventData(e)); 429 var msg = _deserializeMessage(_getEventData(e));
416 switch (msg['command']) { 430 switch (msg['command']) {
417 case 'start': 431 case 'start':
418 _globalState.currentManagerId = msg['id']; 432 _globalState.currentManagerId = msg['id'];
419 Function entryPoint = _getJSFunctionFromName(msg['functionName']); 433 Function entryPoint = _getJSFunctionFromName(msg['functionName']);
420 var replyTo = _deserializeMessage(msg['replyTo']); 434 var replyTo = _deserializeMessage(msg['replyTo']);
421 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() { 435 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() {
422 _startIsolate(entryPoint, replyTo); 436 _startIsolate(entryPoint, replyTo);
423 }, 'worker-start'); 437 }, 'worker-start');
424 _globalState.topEventLoop.run(); 438 _globalState.topEventLoop.run();
425 break; 439 break;
426 case 'spawn-worker': 440 case 'spawn-worker':
427 _spawnWorker(msg['functionName'], msg['uri'], msg['replyPort']); 441 _spawnWorker(msg['functionName'], msg['uri'], msg['replyPort']);
428 break; 442 break;
429 case 'message': 443 case 'message':
430 msg['port'].send(msg['msg'], msg['replyTo']); 444 SendPort port = msg['port'];
445 // If the port has been closed, we ignore the message.
446 if (port != null) {
447 msg['port'].send(msg['msg'], msg['replyTo']);
448 }
431 _globalState.topEventLoop.run(); 449 _globalState.topEventLoop.run();
432 break; 450 break;
433 case 'close': 451 case 'close':
434 _log("Closing Worker"); 452 _log("Closing Worker");
435 _globalState.managers.remove(sender.id); 453 _globalState.managers.remove(sender.id);
436 sender.terminate(); 454 sender.terminate();
437 _globalState.topEventLoop.run(); 455 _globalState.topEventLoop.run();
438 break; 456 break;
439 case 'log': 457 case 'log':
440 _log(msg['msg']); 458 _log(msg['msg']);
(...skipping 19 matching lines...) Expand all
460 } else { 478 } else {
461 try { 479 try {
462 _consoleLog(msg); 480 _consoleLog(msg);
463 } catch (e, trace) { 481 } catch (e, trace) {
464 throw new Exception(trace); 482 throw new Exception(trace);
465 } 483 }
466 } 484 }
467 } 485 }
468 486
469 static void _consoleLog(msg) { 487 static void _consoleLog(msg) {
470 JS("void", r"$globalThis.console.log(#)", msg); 488 JS("void", r"#.console.log(#)", globalThis, msg);
471 } 489 }
472 490
473 /** 491 /**
474 * Extract the constructor of runnable, so it can be allocated in another 492 * Extract the constructor of runnable, so it can be allocated in another
475 * isolate. 493 * isolate.
476 */ 494 */
477 static dynamic _getJSConstructor(Isolate runnable) { 495 static dynamic _getJSConstructor(Isolate runnable) {
478 return JS("Object", "#.constructor", runnable); 496 return JS("", "#.constructor", runnable);
479 } 497 }
480 498
481 /** Extract the constructor name of a runnable */ 499 /** Extract the constructor name of a runnable */
482 // TODO(sigmund): find a browser-generic way to support this. 500 // TODO(sigmund): find a browser-generic way to support this.
483 // TODO(floitsch): is this function still used? If yes, should we use 501 // TODO(floitsch): is this function still used? If yes, should we use
484 // Primitives.objectTypeName instead? 502 // Primitives.objectTypeName instead?
485 static dynamic _getJSConstructorName(Isolate runnable) { 503 static dynamic _getJSConstructorName(Isolate runnable) {
486 return JS("Object", "#.constructor.name", runnable); 504 return JS("", "#.constructor.name", runnable);
487 } 505 }
488 506
489 /** Find a constructor given its name. */ 507 /** Find a constructor given its name. */
490 static dynamic _getJSConstructorFromName(String factoryName) { 508 static dynamic _getJSConstructorFromName(String factoryName) {
491 return JS("Object", r"$globalThis[#]", factoryName); 509 return JS("", r"$[#]", factoryName);
492 } 510 }
493 511
494 static dynamic _getJSFunctionFromName(String functionName) { 512 static dynamic _getJSFunctionFromName(String functionName) {
495 return JS("Object", r"$globalThis[#]", functionName); 513 return JS("", r"$[#]", functionName);
496 } 514 }
497 515
498 /** 516 /**
499 * Get a string name for the function, if possible. The result for 517 * Get a string name for the function, if possible. The result for
500 * anonymous functions is browser-dependent -- it may be "" or "anonymous" 518 * anonymous functions is browser-dependent -- it may be "" or "anonymous"
501 * but you should probably not count on this. 519 * but you should probably not count on this.
502 */ 520 */
503 static String _getJSFunctionName(Function f) { 521 static String _getJSFunctionName(Function f) {
504 return JS("Object", r"(#.$name || #)", f, null); 522 return JS("String|Null", r"(#.$name || #)", f, null);
505 } 523 }
506 524
507 /** Create a new JavaScript object instance given its constructor. */ 525 /** Create a new JavaScript object instance given its constructor. */
508 static dynamic _allocate(var ctor) { 526 static dynamic _allocate(var ctor) {
509 return JS("Object", "new #()", ctor); 527 return JS("", "new #()", ctor);
510 } 528 }
511 529
512 static SendPort spawnFunction(void topLevelFunction()) { 530 static SendPort spawnFunction(void topLevelFunction()) {
513 final name = _getJSFunctionName(topLevelFunction); 531 final name = _getJSFunctionName(topLevelFunction);
514 if (name == null) { 532 if (name == null) {
515 throw new UnsupportedError( 533 throw new UnsupportedError(
516 "only top-level functions can be spawned."); 534 "only top-level functions can be spawned.");
517 } 535 }
518 return spawn(name, null, false); 536 return spawn(name, null, false);
519 } 537 }
520 538
539 static SendPort spawnDomFunction(void topLevelFunction()) {
540 final name = _getJSFunctionName(topLevelFunction);
541 if (name == null) {
542 throw new UnsupportedError(
543 "only top-level functions can be spawned.");
544 }
545 return spawn(name, null, true);
546 }
547
521 // TODO(sigmund): clean up above, after we make the new API the default: 548 // TODO(sigmund): clean up above, after we make the new API the default:
522 549
523 static SendPort spawn(String functionName, String uri, bool isLight) { 550 static spawn(String functionName, String uri, bool isLight) {
524 Completer<SendPort> completer = new Completer<SendPort>(); 551 Completer<SendPort> completer = new Completer<SendPort>();
525 ReceivePort port = new ReceivePort(); 552 ReceivePort port = new ReceivePort();
526 port.receive((msg, SendPort replyPort) { 553 port.receive((msg, SendPort replyPort) {
527 port.close(); 554 port.close();
528 assert(msg == _SPAWNED_SIGNAL); 555 assert(msg == _SPAWNED_SIGNAL);
529 completer.complete(replyPort); 556 completer.complete(replyPort);
530 }); 557 });
531 558
532 SendPort signalReply = port.toSendPort(); 559 SendPort signalReply = port.toSendPort();
533 560
(...skipping 24 matching lines...) Expand all
558 // TODO(eub): support IE9 using an iframe -- Dart issue 1702. 585 // TODO(eub): support IE9 using an iframe -- Dart issue 1702.
559 if (uri != null) throw new UnsupportedError( 586 if (uri != null) throw new UnsupportedError(
560 "Currently spawnUri is not supported without web workers."); 587 "Currently spawnUri is not supported without web workers.");
561 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() { 588 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() {
562 final func = _getJSFunctionFromName(functionName); 589 final func = _getJSFunctionFromName(functionName);
563 _startIsolate(func, replyPort); 590 _startIsolate(func, replyPort);
564 }, 'nonworker start'); 591 }, 'nonworker start');
565 } 592 }
566 593
567 static void _startIsolate(Function topLevel, SendPort replyTo) { 594 static void _startIsolate(Function topLevel, SendPort replyTo) {
568 _fillStatics(_globalState.currentContext);
569 lazyPort = new ReceivePort(); 595 lazyPort = new ReceivePort();
570 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); 596 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort());
571
572 topLevel(); 597 topLevel();
573 } 598 }
574 599
575 /** 600 /**
576 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor 601 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor
577 * name for the isolate entry point class. 602 * name for the isolate entry point class.
578 */ 603 */
579 static void _spawnWorker(functionName, uri, replyPort) { 604 static void _spawnWorker(functionName, uri, replyPort) {
580 if (functionName == null) functionName = 'main'; 605 if (functionName == null) functionName = 'main';
581 if (uri == null) uri = _thisScript; 606 if (uri == null) uri = thisScript;
582 final worker = _newWorker(uri); 607 final worker = _newWorker(uri);
583 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; 608 worker.onmessage = JS('',
609 'function(e) { #(#, e); }',
610 DART_CLOSURE_TO_JS(_processWorkerMessage),
611 worker);
584 var workerId = _globalState.nextManagerId++; 612 var workerId = _globalState.nextManagerId++;
585 // We also store the id on the worker itself so that we can unregister it. 613 // We also store the id on the worker itself so that we can unregister it.
586 worker.id = workerId; 614 worker.id = workerId;
587 _globalState.managers[workerId] = worker; 615 _globalState.managers[workerId] = worker;
588 worker.postMessage(_serializeMessage({ 616 worker.postMessage(_serializeMessage({
589 'command': 'start', 617 'command': 'start',
590 'id': workerId, 618 'id': workerId,
591 // Note: we serialize replyPort twice because the child worker needs to 619 // Note: we serialize replyPort twice because the child worker needs to
592 // first deserialize the worker id, before it can correctly deserialize 620 // first deserialize the worker id, before it can correctly deserialize
593 // the port (port deserialization is sensitive to what is the current 621 // the port (port deserialization is sensitive to what is the current
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after
939 SendPort deserializeSendPort(List x) { 967 SendPort deserializeSendPort(List x) {
940 int managerId = x[1]; 968 int managerId = x[1];
941 int isolateId = x[2]; 969 int isolateId = x[2];
942 int receivePortId = x[3]; 970 int receivePortId = x[3];
943 // If two isolates are in the same manager, we use NativeJsSendPorts to 971 // If two isolates are in the same manager, we use NativeJsSendPorts to
944 // deliver messages directly without using postMessage. 972 // deliver messages directly without using postMessage.
945 if (managerId == _globalState.currentManagerId) { 973 if (managerId == _globalState.currentManagerId) {
946 var isolate = _globalState.isolates[isolateId]; 974 var isolate = _globalState.isolates[isolateId];
947 if (isolate == null) return null; // Isolate has been closed. 975 if (isolate == null) return null; // Isolate has been closed.
948 var receivePort = isolate.lookup(receivePortId); 976 var receivePort = isolate.lookup(receivePortId);
977 if (receivePort == null) return null; // Port has been closed.
949 return new _NativeJsSendPort(receivePort, isolateId); 978 return new _NativeJsSendPort(receivePort, isolateId);
950 } else { 979 } else {
951 return new _WorkerSendPort(managerId, isolateId, receivePortId); 980 return new _WorkerSendPort(managerId, isolateId, receivePortId);
952 } 981 }
953 } 982 }
954 983
955 } 984 }
956 985
957 class _JsVisitedMap implements _MessageTraverserVisitedMap { 986 class _JsVisitedMap implements _MessageTraverserVisitedMap {
958 List tagged; 987 List tagged;
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after
1240 void cancel() { 1269 void cancel() {
1241 if (_once) { 1270 if (_once) {
1242 JS('void', '#.clearTimeout(#)', globalThis, _handle); 1271 JS('void', '#.clearTimeout(#)', globalThis, _handle);
1243 } else { 1272 } else {
1244 JS('void', '#.clearInterval(#)', globalThis, _handle); 1273 JS('void', '#.clearInterval(#)', globalThis, _handle);
1245 } 1274 }
1246 } 1275 }
1247 } 1276 }
1248 1277
1249 bool hasTimer() => JS('', '#.setTimeout', globalThis) != null; 1278 bool hasTimer() => JS('', '#.setTimeout', globalThis) != null;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698