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

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

Powered by Google App Engine
This is Rietveld 408576698