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

Side by Side Diff: pkg/dev_compiler/tool/input_sdk/private/isolate_helper.dart

Issue 2752163002: Format all dart dev compiler files (Closed)
Patch Set: Created 3 years, 9 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
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 dart._isolate_helper; 5 library dart._isolate_helper;
6 6
7 import 'dart:_js_embedded_names' show 7 import 'dart:_js_embedded_names'
8 CLASS_ID_EXTRACTOR, 8 show
9 CLASS_FIELDS_EXTRACTOR, 9 CLASS_ID_EXTRACTOR,
10 CURRENT_SCRIPT, 10 CLASS_FIELDS_EXTRACTOR,
11 GLOBAL_FUNCTIONS, 11 CURRENT_SCRIPT,
12 INITIALIZE_EMPTY_INSTANCE, 12 GLOBAL_FUNCTIONS,
13 INSTANCE_FROM_CLASS_ID; 13 INITIALIZE_EMPTY_INSTANCE,
14 INSTANCE_FROM_CLASS_ID;
14 15
15 import 'dart:async'; 16 import 'dart:async';
16 import 'dart:collection' show Queue, HashMap; 17 import 'dart:collection' show Queue, HashMap;
17 import 'dart:isolate'; 18 import 'dart:isolate';
18 import 'dart:_native_typed_data' show NativeByteBuffer, NativeTypedData; 19 import 'dart:_native_typed_data' show NativeByteBuffer, NativeTypedData;
19 20
20 import 'dart:_js_helper' show 21 import 'dart:_js_helper' show InternalMap, Null, Primitives, random64;
21 InternalMap,
22 Null,
23 Primitives,
24 random64;
25 22
26 import 'dart:_foreign_helper' show JS, 23 import 'dart:_foreign_helper'
27 JS_CREATE_ISOLATE, 24 show
28 JS_CURRENT_ISOLATE_CONTEXT, 25 JS,
29 JS_CURRENT_ISOLATE, 26 JS_CREATE_ISOLATE,
30 JS_EMBEDDED_GLOBAL, 27 JS_CURRENT_ISOLATE_CONTEXT,
31 JS_SET_CURRENT_ISOLATE, 28 JS_CURRENT_ISOLATE,
32 IsolateContext; 29 JS_EMBEDDED_GLOBAL,
30 JS_SET_CURRENT_ISOLATE,
31 IsolateContext;
33 32
34 import 'dart:_interceptors' show Interceptor, 33 import 'dart:_interceptors'
35 JSArray, 34 show
36 JSExtendableArray, 35 Interceptor,
37 JSFixedArray, 36 JSArray,
38 JSIndexable, 37 JSExtendableArray,
39 JSMutableArray, 38 JSFixedArray,
40 JSObject; 39 JSIndexable,
41 40 JSMutableArray,
41 JSObject;
42 42
43 part 'isolate_serialization.dart'; 43 part 'isolate_serialization.dart';
44 44
45 /** 45 /**
46 * Called by the compiler to support switching 46 * Called by the compiler to support switching
47 * between isolates when we get a callback from the DOM. 47 * between isolates when we get a callback from the DOM.
48 */ 48 */
49 _callInIsolate(_IsolateContext isolate, Function function) { 49 _callInIsolate(_IsolateContext isolate, Function function) {
50 var result = isolate.eval(function); 50 var result = isolate.eval(function);
51 _globalState.topEventLoop.run(); 51 _globalState.topEventLoop.run();
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 if (_globalState.isWorker) return; 103 if (_globalState.isWorker) return;
104 final rootContext = new _IsolateContext(); 104 final rootContext = new _IsolateContext();
105 _globalState.rootContext = rootContext; 105 _globalState.rootContext = rootContext;
106 106
107 // BUG(5151491): Setting currentContext should not be necessary, but 107 // BUG(5151491): Setting currentContext should not be necessary, but
108 // because closures passed to the DOM as event handlers do not bind their 108 // because closures passed to the DOM as event handlers do not bind their
109 // isolate automatically we try to give them a reasonable context to live in 109 // isolate automatically we try to give them a reasonable context to live in
110 // by having a "default" isolate (the first one created). 110 // by having a "default" isolate (the first one created).
111 _globalState.currentContext = rootContext; 111 _globalState.currentContext = rootContext;
112 if (entry is _MainFunctionArgs) { 112 if (entry is _MainFunctionArgs) {
113 rootContext.eval(() { entry(args); }); 113 rootContext.eval(() {
114 entry(args);
115 });
114 } else if (entry is _MainFunctionArgsMessage) { 116 } else if (entry is _MainFunctionArgsMessage) {
115 rootContext.eval(() { entry(args, null); }); 117 rootContext.eval(() {
118 entry(args, null);
119 });
116 } else { 120 } else {
117 rootContext.eval(entry); 121 rootContext.eval(entry);
118 } 122 }
119 _globalState.topEventLoop.run(); 123 _globalState.topEventLoop.run();
120 } 124 }
121 125
122 /******************************************************** 126 /********************************************************
123 Inserted from lib/isolate/dart2js/isolateimpl.dart 127 Inserted from lib/isolate/dart2js/isolateimpl.dart
124 ********************************************************/ 128 ********************************************************/
125 129
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
159 163
160 set _globalState(_Manager val) { 164 set _globalState(_Manager val) {
161 // TODO(vsm): This was changed from init.globalState. 165 // TODO(vsm): This was changed from init.globalState.
162 // See: https://github.com/dart-lang/dev_compiler/issues/164 166 // See: https://github.com/dart-lang/dev_compiler/issues/164
163 JS("void", "dart.globalState = #", val); 167 JS("void", "dart.globalState = #", val);
164 } 168 }
165 169
166 /** State associated with the current manager. See [globalState]. */ 170 /** State associated with the current manager. See [globalState]. */
167 // TODO(sigmund): split in multiple classes: global, thread, main-worker states? 171 // TODO(sigmund): split in multiple classes: global, thread, main-worker states?
168 class _Manager { 172 class _Manager {
169
170 /** Next available isolate id within this [_Manager]. */ 173 /** Next available isolate id within this [_Manager]. */
171 int nextIsolateId = 0; 174 int nextIsolateId = 0;
172 175
173 /** id assigned to this [_Manager]. */ 176 /** id assigned to this [_Manager]. */
174 int currentManagerId = 0; 177 int currentManagerId = 0;
175 178
176 /** 179 /**
177 * Next available manager id. Only used by the main manager to assign a unique 180 * Next available manager id. Only used by the main manager to assign a unique
178 * id to each manager created by it. 181 * id to each manager created by it.
179 */ 182 */
(...skipping 27 matching lines...) Expand all
207 * Registry of isolates. Isolates must be registered if, and only if, receive 210 * Registry of isolates. Isolates must be registered if, and only if, receive
208 * ports are alive. Normally no open receive-ports means that the isolate is 211 * ports are alive. Normally no open receive-ports means that the isolate is
209 * dead, but DOM callbacks could resurrect it. 212 * dead, but DOM callbacks could resurrect it.
210 */ 213 */
211 Map<int, _IsolateContext> isolates; 214 Map<int, _IsolateContext> isolates;
212 215
213 /** Reference to the main [_Manager]. Null in the main [_Manager] itself. */ 216 /** Reference to the main [_Manager]. Null in the main [_Manager] itself. */
214 _MainManagerStub mainManager; 217 _MainManagerStub mainManager;
215 218
216 /// Registry of active Web Workers. Only used in the main [_Manager]. 219 /// Registry of active Web Workers. Only used in the main [_Manager].
217 Map<int, dynamic /* Worker */> managers; 220 Map<int, dynamic /* Worker */ > managers;
218 221
219 /** The entry point given by [startRootIsolate]. */ 222 /** The entry point given by [startRootIsolate]. */
220 final Function entry; 223 final Function entry;
221 224
222 _Manager(this.entry) { 225 _Manager(this.entry) {
223 _nativeDetectEnvironment(); 226 _nativeDetectEnvironment();
224 topEventLoop = new _EventLoop(); 227 topEventLoop = new _EventLoop();
225 isolates = new Map<int, _IsolateContext>(); 228 isolates = new Map<int, _IsolateContext>();
226 managers = new Map<int, dynamic>(); 229 managers = new Map<int, dynamic>();
227 if (isWorker) { // "if we are not the main manager ourself" is the intent. 230 if (isWorker) {
231 // "if we are not the main manager ourself" is the intent.
228 mainManager = new _MainManagerStub(); 232 mainManager = new _MainManagerStub();
229 _nativeInitWorkerMessageHandler(); 233 _nativeInitWorkerMessageHandler();
230 } 234 }
231 } 235 }
232 236
233 void _nativeDetectEnvironment() { 237 void _nativeDetectEnvironment() {
234 bool isWindowDefined = globalWindow != null; 238 bool isWindowDefined = globalWindow != null;
235 bool isWorkerDefined = globalWorker != null; 239 bool isWorkerDefined = globalWorker != null;
236 240
237 isWorker = !isWindowDefined && globalPostMessageDefined; 241 isWorker = !isWindowDefined && globalPostMessageDefined;
238 supportsWorkers = isWorker 242 supportsWorkers =
239 || (isWorkerDefined && IsolateNatives.thisScript != null); 243 isWorker || (isWorkerDefined && IsolateNatives.thisScript != null);
240 fromCommandLine = !isWindowDefined && !isWorker; 244 fromCommandLine = !isWindowDefined && !isWorker;
241 } 245 }
242 246
243 void _nativeInitWorkerMessageHandler() { 247 void _nativeInitWorkerMessageHandler() {
244 var function = JS('', 248 var function = JS(
249 '',
245 "(function (f, a) { return function (e) { f(a, e); }})(#, #)", 250 "(function (f, a) { return function (e) { f(a, e); }})(#, #)",
246 IsolateNatives._processWorkerMessage, 251 IsolateNatives._processWorkerMessage,
247 mainManager); 252 mainManager);
248 JS("void", r"#.onmessage = #", global, function); 253 JS("void", r"#.onmessage = #", global, function);
249 // We ensure dartPrint is defined so that the implementation of the Dart 254 // We ensure dartPrint is defined so that the implementation of the Dart
250 // print method knows what to call. 255 // print method knows what to call.
251 JS('', '''#.dartPrint = #.dartPrint || (function(serialize) { 256 JS(
257 '',
258 '''#.dartPrint = #.dartPrint || (function(serialize) {
252 return function (object) { 259 return function (object) {
253 var _self = #; 260 var _self = #;
254 if (_self.console && _self.console.log) { 261 if (_self.console && _self.console.log) {
255 _self.console.log(object) 262 _self.console.log(object)
256 } else { 263 } else {
257 _self.postMessage(serialize(object)); 264 _self.postMessage(serialize(object));
258 } 265 }
259 } 266 }
260 })(#)''', global, global, global, _serializePrintMessage); 267 })(#)''',
268 global,
269 global,
270 global,
271 _serializePrintMessage);
261 } 272 }
262 273
263 static _serializePrintMessage(object) { 274 static _serializePrintMessage(object) {
264 return _serializeMessage({"command": "print", "msg": object}); 275 return _serializeMessage({"command": "print", "msg": object});
265 } 276 }
266 277
267 /** 278 /**
268 * Close the worker running this code if all isolates are done and 279 * Close the worker running this code if all isolates are done and
269 * there are no active async JavaScript tasks still running. 280 * there are no active async JavaScript tasks still running.
270 */ 281 */
271 void maybeCloseWorker() { 282 void maybeCloseWorker() {
272 if (isWorker 283 if (isWorker && isolates.isEmpty && topEventLoop._activeJsAsyncCount == 0) {
273 && isolates.isEmpty
274 && topEventLoop._activeJsAsyncCount == 0) {
275 mainManager.postMessage(_serializeMessage({'command': 'close'})); 284 mainManager.postMessage(_serializeMessage({'command': 'close'}));
276 } 285 }
277 } 286 }
278 } 287 }
279 288
280 /** Context information tracked for each isolate. */ 289 /** Context information tracked for each isolate. */
281 class _IsolateContext implements IsolateContext { 290 class _IsolateContext implements IsolateContext {
282 /** Current isolate id. */ 291 /** Current isolate id. */
283 final int id = _globalState.nextIsolateId++; 292 final int id = _globalState.nextIsolateId++;
284 293
285 /** Registry of receive ports currently active on this isolate. */ 294 /** Registry of receive ports currently active on this isolate. */
286 final Map<int, RawReceivePortImpl> ports = new Map<int, RawReceivePortImpl>(); 295 final Map<int, RawReceivePortImpl> ports = new Map<int, RawReceivePortImpl>();
287 296
288 /** Registry of weak receive ports currently active on this isolate. */ 297 /** Registry of weak receive ports currently active on this isolate. */
289 final Set<int> weakPorts = new Set<int>(); 298 final Set<int> weakPorts = new Set<int>();
290 299
291 /** Holds isolate globals (statics and top-level properties). */ 300 /** Holds isolate globals (statics and top-level properties). */
292 // native object containing all globals of an isolate. 301 // native object containing all globals of an isolate.
293 final isolateStatics = JS_CREATE_ISOLATE(); 302 final isolateStatics = JS_CREATE_ISOLATE();
294 303
295 final RawReceivePortImpl controlPort = new RawReceivePortImpl._controlPort(); 304 final RawReceivePortImpl controlPort = new RawReceivePortImpl._controlPort();
296 305
297 final Capability pauseCapability = new Capability(); 306 final Capability pauseCapability = new Capability();
298 final Capability terminateCapability = new Capability(); // License to kill. 307 final Capability terminateCapability = new Capability(); // License to kill.
299 308
300 /// Boolean flag set when the initial method of the isolate has been executed. 309 /// Boolean flag set when the initial method of the isolate has been executed.
301 /// 310 ///
302 /// Used to avoid considering the isolate dead when it has no open 311 /// Used to avoid considering the isolate dead when it has no open
303 /// receive ports and no scheduled timers, because it hasn't had time to 312 /// receive ports and no scheduled timers, because it hasn't had time to
304 /// create them yet. 313 /// create them yet.
305 bool initialized = false; 314 bool initialized = false;
306 315
307 // TODO(lrn): Store these in single "PauseState" object, so they don't take 316 // TODO(lrn): Store these in single "PauseState" object, so they don't take
308 // up as much room when not pausing. 317 // up as much room when not pausing.
(...skipping 29 matching lines...) Expand all
338 if (pauseTokens.add(resume) && !isPaused) { 347 if (pauseTokens.add(resume) && !isPaused) {
339 isPaused = true; 348 isPaused = true;
340 } 349 }
341 _updateGlobalState(); 350 _updateGlobalState();
342 } 351 }
343 352
344 void removePause(Capability resume) { 353 void removePause(Capability resume) {
345 if (!isPaused) return; 354 if (!isPaused) return;
346 pauseTokens.remove(resume); 355 pauseTokens.remove(resume);
347 if (pauseTokens.isEmpty) { 356 if (pauseTokens.isEmpty) {
348 while(delayedEvents.isNotEmpty) { 357 while (delayedEvents.isNotEmpty) {
349 _IsolateEvent event = delayedEvents.removeLast(); 358 _IsolateEvent event = delayedEvents.removeLast();
350 _globalState.topEventLoop.prequeue(event); 359 _globalState.topEventLoop.prequeue(event);
351 } 360 }
352 isPaused = false; 361 isPaused = false;
353 } 362 }
354 _updateGlobalState(); 363 _updateGlobalState();
355 } 364 }
356 365
357 void addDoneListener(SendPort responsePort) { 366 void addDoneListener(SendPort responsePort) {
358 if (doneHandlers == null) { 367 if (doneHandlers == null) {
(...skipping 10 matching lines...) Expand all
369 doneHandlers.remove(responsePort); 378 doneHandlers.remove(responsePort);
370 } 379 }
371 380
372 void setErrorsFatal(Capability authentification, bool errorsAreFatal) { 381 void setErrorsFatal(Capability authentification, bool errorsAreFatal) {
373 if (terminateCapability != authentification) return; 382 if (terminateCapability != authentification) return;
374 this.errorsAreFatal = errorsAreFatal; 383 this.errorsAreFatal = errorsAreFatal;
375 } 384 }
376 385
377 void handlePing(SendPort responsePort, int pingType) { 386 void handlePing(SendPort responsePort, int pingType) {
378 if (pingType == Isolate.IMMEDIATE || 387 if (pingType == Isolate.IMMEDIATE ||
379 (pingType == Isolate.BEFORE_NEXT_EVENT && 388 (pingType == Isolate.BEFORE_NEXT_EVENT && !_isExecutingEvent)) {
380 !_isExecutingEvent)) {
381 responsePort.send(null); 389 responsePort.send(null);
382 return; 390 return;
383 } 391 }
384 void respond() { responsePort.send(null); } 392 void respond() {
393 responsePort.send(null);
394 }
395
385 assert(pingType == Isolate.BEFORE_NEXT_EVENT); 396 assert(pingType == Isolate.BEFORE_NEXT_EVENT);
386 if (_scheduledControlEvents == null) { 397 if (_scheduledControlEvents == null) {
387 _scheduledControlEvents = new Queue(); 398 _scheduledControlEvents = new Queue();
388 } 399 }
389 _scheduledControlEvents.addLast(respond); 400 _scheduledControlEvents.addLast(respond);
390 } 401 }
391 402
392 void handleKill(Capability authentification, int priority) { 403 void handleKill(Capability authentification, int priority) {
393 if (this.terminateCapability != authentification) return; 404 if (this.terminateCapability != authentification) return;
394 if (priority == Isolate.IMMEDIATE || 405 if (priority == Isolate.IMMEDIATE ||
395 (priority == Isolate.BEFORE_NEXT_EVENT && 406 (priority == Isolate.BEFORE_NEXT_EVENT && !_isExecutingEvent)) {
396 !_isExecutingEvent)) {
397 kill(); 407 kill();
398 return; 408 return;
399 } 409 }
400 assert(priority == Isolate.BEFORE_NEXT_EVENT); 410 assert(priority == Isolate.BEFORE_NEXT_EVENT);
401 if (_scheduledControlEvents == null) { 411 if (_scheduledControlEvents == null) {
402 _scheduledControlEvents = new Queue(); 412 _scheduledControlEvents = new Queue();
403 } 413 }
404 _scheduledControlEvents.addLast(kill); 414 _scheduledControlEvents.addLast(kill);
405 } 415 }
406 416
(...skipping 17 matching lines...) Expand all
424 } 434 }
425 if (JS('bool', '#.console && #.console.error', global, global)) { 435 if (JS('bool', '#.console && #.console.error', global, global)) {
426 JS('void', '#.console.error(#, #)', global, error, stackTrace); 436 JS('void', '#.console.error(#, #)', global, error, stackTrace);
427 } else { 437 } else {
428 print(error); 438 print(error);
429 if (stackTrace != null) print(stackTrace); 439 if (stackTrace != null) print(stackTrace);
430 } 440 }
431 return; 441 return;
432 } 442 }
433 List message = new List(2) 443 List message = new List(2)
434 ..[0] = error.toString() 444 ..[0] = error.toString()
435 ..[1] = (stackTrace == null) ? null : stackTrace.toString(); 445 ..[1] = (stackTrace == null) ? null : stackTrace.toString();
436 for (SendPort port in errorPorts) port.send(message); 446 for (SendPort port in errorPorts) port.send(message);
437 } 447 }
438 448
439 /** 449 /**
440 * Run [code] in the context of the isolate represented by [this]. 450 * Run [code] in the context of the isolate represented by [this].
441 */ 451 */
442 dynamic eval(Function code) { 452 dynamic eval(Function code) {
443 var old = _globalState.currentContext; 453 var old = _globalState.currentContext;
444 _globalState.currentContext = this; 454 _globalState.currentContext = this;
445 this._setGlobals(); 455 this._setGlobals();
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 RawReceivePortImpl lookup(int portId) => ports[portId]; 527 RawReceivePortImpl lookup(int portId) => ports[portId];
518 528
519 void _addRegistration(int portId, RawReceivePortImpl port) { 529 void _addRegistration(int portId, RawReceivePortImpl port) {
520 if (ports.containsKey(portId)) { 530 if (ports.containsKey(portId)) {
521 throw new Exception("Registry: ports must be registered only once."); 531 throw new Exception("Registry: ports must be registered only once.");
522 } 532 }
523 ports[portId] = port; 533 ports[portId] = port;
524 } 534 }
525 535
526 /** Registers a port on this isolate. */ 536 /** Registers a port on this isolate. */
527 void register(int portId, RawReceivePortImpl port) { 537 void register(int portId, RawReceivePortImpl port) {
528 _addRegistration(portId, port); 538 _addRegistration(portId, port);
529 _updateGlobalState(); 539 _updateGlobalState();
530 } 540 }
531 541
532 /** 542 /**
533 * Registers a weak port on this isolate. 543 * Registers a weak port on this isolate.
534 * 544 *
535 * The port does not keep the isolate active. 545 * The port does not keep the isolate active.
536 */ 546 */
537 void registerWeak(int portId, RawReceivePortImpl port) { 547 void registerWeak(int portId, RawReceivePortImpl port) {
538 weakPorts.add(portId); 548 weakPorts.add(portId);
539 _addRegistration(portId, port); 549 _addRegistration(portId, port);
540 } 550 }
541 551
542 void _updateGlobalState() { 552 void _updateGlobalState() {
543 if (ports.length - weakPorts.length > 0 || isPaused || !initialized) { 553 if (ports.length - weakPorts.length > 0 || isPaused || !initialized) {
544 _globalState.isolates[id] = this; // indicate this isolate is active 554 _globalState.isolates[id] = this; // indicate this isolate is active
545 } else { 555 } else {
546 kill(); 556 kill();
547 } 557 }
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
600 void prequeue(_IsolateEvent event) { 610 void prequeue(_IsolateEvent event) {
601 events.addFirst(event); 611 events.addFirst(event);
602 } 612 }
603 613
604 _IsolateEvent dequeue() { 614 _IsolateEvent dequeue() {
605 if (events.isEmpty) return null; 615 if (events.isEmpty) return null;
606 return events.removeFirst(); 616 return events.removeFirst();
607 } 617 }
608 618
609 void checkOpenReceivePortsFromCommandLine() { 619 void checkOpenReceivePortsFromCommandLine() {
610 if (_globalState.rootContext != null 620 if (_globalState.rootContext != null &&
611 && _globalState.isolates.containsKey(_globalState.rootContext.id) 621 _globalState.isolates.containsKey(_globalState.rootContext.id) &&
612 && _globalState.fromCommandLine 622 _globalState.fromCommandLine &&
613 && _globalState.rootContext.ports.isEmpty) { 623 _globalState.rootContext.ports.isEmpty) {
614 // We want to reach here only on the main [_Manager] and only 624 // We want to reach here only on the main [_Manager] and only
615 // on the command-line. In the browser the isolate might 625 // on the command-line. In the browser the isolate might
616 // still be alive due to DOM callbacks, but the presumption is 626 // still be alive due to DOM callbacks, but the presumption is
617 // that on the command-line, no future events can be injected 627 // that on the command-line, no future events can be injected
618 // into the event queue once it's empty. Node has setTimeout 628 // into the event queue once it's empty. Node has setTimeout
619 // so this presumption is incorrect there. We think(?) that 629 // so this presumption is incorrect there. We think(?) that
620 // in d8 this assumption is valid. 630 // in d8 this assumption is valid.
621 throw new Exception("Program exited with open ReceivePorts."); 631 throw new Exception("Program exited with open ReceivePorts.");
622 } 632 }
623 } 633 }
(...skipping 14 matching lines...) Expand all
638 * Runs multiple iterations of the run-loop. If possible, each iteration is 648 * Runs multiple iterations of the run-loop. If possible, each iteration is
639 * run asynchronously. 649 * run asynchronously.
640 */ 650 */
641 void _runHelper() { 651 void _runHelper() {
642 if (globalWindow != null) { 652 if (globalWindow != null) {
643 // Run each iteration from the browser's top event loop. 653 // Run each iteration from the browser's top event loop.
644 next() { 654 next() {
645 if (!runIteration()) return; 655 if (!runIteration()) return;
646 Timer.run(next); 656 Timer.run(next);
647 } 657 }
658
648 next(); 659 next();
649 } else { 660 } else {
650 // Run synchronously until no more iterations are available. 661 // Run synchronously until no more iterations are available.
651 while (runIteration()) {} 662 while (runIteration()) {}
652 } 663 }
653 } 664 }
654 665
655 /** 666 /**
656 * Call [_runHelper] but ensure that worker exceptions are propragated. 667 * Call [_runHelper] but ensure that worker exceptions are propragated.
657 */ 668 */
658 void run() { 669 void run() {
659 if (!_globalState.isWorker) { 670 if (!_globalState.isWorker) {
660 _runHelper(); 671 _runHelper();
661 } else { 672 } else {
662 try { 673 try {
663 _runHelper(); 674 _runHelper();
664 } catch (e, trace) { 675 } catch (e, trace) {
665 _globalState.mainManager.postMessage(_serializeMessage( 676 _globalState.mainManager.postMessage(
666 {'command': 'error', 'msg': '$e\n$trace' })); 677 _serializeMessage({'command': 'error', 'msg': '$e\n$trace'}));
667 } 678 }
668 } 679 }
669 } 680 }
670 } 681 }
671 682
672 /** An event in the top-level event queue. */ 683 /** An event in the top-level event queue. */
673 class _IsolateEvent { 684 class _IsolateEvent {
674 _IsolateContext isolate; 685 _IsolateContext isolate;
675 Function fn; 686 Function fn;
676 String message; 687 String message;
677 688
678 _IsolateEvent(this.isolate, this.fn, this.message); 689 _IsolateEvent(this.isolate, this.fn, this.message);
679 690
680 void process() { 691 void process() {
681 if (isolate.isPaused) { 692 if (isolate.isPaused) {
682 isolate.delayedEvents.add(this); 693 isolate.delayedEvents.add(this);
683 return; 694 return;
684 } 695 }
685 isolate.eval(fn); 696 isolate.eval(fn);
686 } 697 }
687 } 698 }
688 699
689 // "self" is a way to refer to the global context object that 700 // "self" is a way to refer to the global context object that
690 // works in HTML pages and in Web Workers. It does not work in d8, iojs 701 // works in HTML pages and in Web Workers. It does not work in d8, iojs
691 // and Firefox jsshell, because that would have been too easy. In iojs 702 // and Firefox jsshell, because that would have been too easy. In iojs
692 // "global" works. 703 // "global" works.
693 // 704 //
694 // See: http://www.w3.org/TR/workers/#the-global-scope 705 // See: http://www.w3.org/TR/workers/#the-global-scope
695 // and: http://www.w3.org/TR/Window/#dfn-self-attribute 706 // and: http://www.w3.org/TR/Window/#dfn-self-attribute
696 final global = 707 final global = JS("", "typeof global == 'undefined' ? self : global");
697 JS("", "typeof global == 'undefined' ? self : global");
698 708
699 /** A stub for interacting with the main manager. */ 709 /** A stub for interacting with the main manager. */
700 class _MainManagerStub { 710 class _MainManagerStub {
701 void postMessage(msg) { 711 void postMessage(msg) {
702 JS("void", r"#.postMessage(#)", global, msg); 712 JS("void", r"#.postMessage(#)", global, msg);
703 } 713 }
704 } 714 }
705 715
706 const String _SPAWNED_SIGNAL = "spawned"; 716 const String _SPAWNED_SIGNAL = "spawned";
707 const String _SPAWN_FAILED_SIGNAL = "spawn failed"; 717 const String _SPAWN_FAILED_SIGNAL = "spawn failed";
708 718
709 get globalWindow { 719 get globalWindow {
710 return JS('', "#.window", global); 720 return JS('', "#.window", global);
711 } 721 }
712 722
713 get globalWorker { 723 get globalWorker {
714 return JS('', "#.Worker", global); 724 return JS('', "#.Worker", global);
715 } 725 }
726
716 bool get globalPostMessageDefined { 727 bool get globalPostMessageDefined {
717 return JS('bool', "!!#.postMessage", global); 728 return JS('bool', "!!#.postMessage", global);
718 } 729 }
719 730
720 typedef _MainFunction(); 731 typedef _MainFunction();
721 typedef _MainFunctionArgs(args); 732 typedef _MainFunctionArgs(args);
722 typedef _MainFunctionArgsMessage(args, message); 733 typedef _MainFunctionArgsMessage(args, message);
723 734
724 /// Note: IsolateNatives depends on _globalState which is only set up correctly 735 /// Note: IsolateNatives depends on _globalState which is only set up correctly
725 /// when 'dart:isolate' has been imported. 736 /// when 'dart:isolate' has been imported.
726 class IsolateNatives { 737 class IsolateNatives {
727
728 // We set [enableSpawnWorker] to true (not null) when calling isolate 738 // We set [enableSpawnWorker] to true (not null) when calling isolate
729 // primitives that require support for spawning workers. The field starts out 739 // primitives that require support for spawning workers. The field starts out
730 // by being null, and dart2js' type inference will track if it can have a 740 // by being null, and dart2js' type inference will track if it can have a
731 // non-null value. So by testing if this value is not null, we generate code 741 // non-null value. So by testing if this value is not null, we generate code
732 // that dart2js knows is dead when worker support isn't needed. 742 // that dart2js knows is dead when worker support isn't needed.
733 // TODO(herhut): Initialize this to false when able to track compile-time 743 // TODO(herhut): Initialize this to false when able to track compile-time
734 // constants. 744 // constants.
735 static var enableSpawnWorker; 745 static var enableSpawnWorker;
736 746
737 static String thisScript = computeThisScript(); 747 static String thisScript = computeThisScript();
(...skipping 28 matching lines...) Expand all
766 // TODO(ahe): The following is for supporting D8. We should move this code 776 // TODO(ahe): The following is for supporting D8. We should move this code
767 // to a helper library that is only loaded when testing on D8. 777 // to a helper library that is only loaded when testing on D8.
768 static String computeThisScriptD8() => computeThisScriptFromTrace(); 778 static String computeThisScriptD8() => computeThisScriptFromTrace();
769 779
770 static String computeThisScriptFromTrace() { 780 static String computeThisScriptFromTrace() {
771 var stack = JS('String|Null', 'new Error().stack'); 781 var stack = JS('String|Null', 'new Error().stack');
772 if (stack == null) { 782 if (stack == null) {
773 // According to Internet Explorer documentation, the stack 783 // According to Internet Explorer documentation, the stack
774 // property is not set until the exception is thrown. The stack 784 // property is not set until the exception is thrown. The stack
775 // property was not provided until IE10. 785 // property was not provided until IE10.
776 stack = JS('String|Null', 786 stack = JS(
777 '(function() {' 787 'String|Null',
778 'try { throw new Error() } catch(e) { return e.stack }' 788 '(function() {'
779 '})()'); 789 'try { throw new Error() } catch(e) { return e.stack }'
790 '})()');
780 if (stack == null) throw new UnsupportedError('No stack trace'); 791 if (stack == null) throw new UnsupportedError('No stack trace');
781 } 792 }
782 var pattern, matches; 793 var pattern, matches;
783 794
784 // This pattern matches V8, Chrome, and Internet Explorer stack 795 // This pattern matches V8, Chrome, and Internet Explorer stack
785 // traces that look like this: 796 // traces that look like this:
786 // Error 797 // Error
787 // at methodName (URI:LINE:COLUMN) 798 // at methodName (URI:LINE:COLUMN)
788 pattern = JS('', 799 pattern =
789 r'new RegExp("^ *at [^(]*\\((.*):[0-9]*:[0-9]*\\)$", "m")'); 800 JS('', r'new RegExp("^ *at [^(]*\\((.*):[0-9]*:[0-9]*\\)$", "m")');
790
791 801
792 matches = JS('JSExtendableArray|Null', '#.match(#)', stack, pattern); 802 matches = JS('JSExtendableArray|Null', '#.match(#)', stack, pattern);
793 if (matches != null) return JS('String', '#[1]', matches); 803 if (matches != null) return JS('String', '#[1]', matches);
794 804
795 // This pattern matches Firefox stack traces that look like this: 805 // This pattern matches Firefox stack traces that look like this:
796 // methodName@URI:LINE 806 // methodName@URI:LINE
797 pattern = JS('', r'new RegExp("^[^@]*@(.*):[0-9]*$", "m")'); 807 pattern = JS('', r'new RegExp("^[^@]*@(.*):[0-9]*$", "m")');
798 808
799 matches = JS('JSExtendableArray|Null', '#.match(#)', stack, pattern); 809 matches = JS('JSExtendableArray|Null', '#.match(#)', stack, pattern);
800 if (matches != null) return JS('String', '#[1]', matches); 810 if (matches != null) return JS('String', '#[1]', matches);
(...skipping 21 matching lines...) Expand all
822 Function entryPoint = (functionName == null) 832 Function entryPoint = (functionName == null)
823 ? _globalState.entry 833 ? _globalState.entry
824 : _getJSFunctionFromName(functionName); 834 : _getJSFunctionFromName(functionName);
825 var args = msg['args']; 835 var args = msg['args'];
826 var message = _deserializeMessage(msg['msg']); 836 var message = _deserializeMessage(msg['msg']);
827 var isSpawnUri = msg['isSpawnUri']; 837 var isSpawnUri = msg['isSpawnUri'];
828 var startPaused = msg['startPaused']; 838 var startPaused = msg['startPaused'];
829 var replyTo = _deserializeMessage(msg['replyTo']); 839 var replyTo = _deserializeMessage(msg['replyTo']);
830 var context = new _IsolateContext(); 840 var context = new _IsolateContext();
831 _globalState.topEventLoop.enqueue(context, () { 841 _globalState.topEventLoop.enqueue(context, () {
832 _startIsolate(entryPoint, args, message, 842 _startIsolate(
833 isSpawnUri, startPaused, replyTo); 843 entryPoint, args, message, isSpawnUri, startPaused, replyTo);
834 }, 'worker-start'); 844 }, 'worker-start');
835 // Make sure we always have a current context in this worker. 845 // Make sure we always have a current context in this worker.
836 // TODO(7907): This is currently needed because we're using 846 // TODO(7907): This is currently needed because we're using
837 // Timers to implement Futures, and this isolate library 847 // Timers to implement Futures, and this isolate library
838 // implementation uses Futures. We should either stop using 848 // implementation uses Futures. We should either stop using
839 // Futures in this library, or re-adapt if Futures get a 849 // Futures in this library, or re-adapt if Futures get a
840 // different implementation. 850 // different implementation.
841 _globalState.currentContext = context; 851 _globalState.currentContext = context;
842 _globalState.topEventLoop.run(); 852 _globalState.topEventLoop.run();
843 break; 853 break;
(...skipping 11 matching lines...) Expand all
855 case 'close': 865 case 'close':
856 _globalState.managers.remove(workerIds[sender]); 866 _globalState.managers.remove(workerIds[sender]);
857 JS('void', '#.terminate()', sender); 867 JS('void', '#.terminate()', sender);
858 _globalState.topEventLoop.run(); 868 _globalState.topEventLoop.run();
859 break; 869 break;
860 case 'log': 870 case 'log':
861 _log(msg['msg']); 871 _log(msg['msg']);
862 break; 872 break;
863 case 'print': 873 case 'print':
864 if (_globalState.isWorker) { 874 if (_globalState.isWorker) {
865 _globalState.mainManager.postMessage( 875 _globalState.mainManager
866 _serializeMessage({'command': 'print', 'msg': msg})); 876 .postMessage(_serializeMessage({'command': 'print', 'msg': msg}));
867 } else { 877 } else {
868 print(msg['msg']); 878 print(msg['msg']);
869 } 879 }
870 break; 880 break;
871 case 'error': 881 case 'error':
872 throw msg['msg']; 882 throw msg['msg'];
873 } 883 }
874 } 884 }
875 885
876 static handleSpawnWorkerRequest(msg) { 886 static handleSpawnWorkerRequest(msg) {
877 var replyPort = msg['replyPort']; 887 var replyPort = msg['replyPort'];
878 spawn(msg['functionName'], msg['uri'], 888 spawn(msg['functionName'], msg['uri'], msg['args'], msg['msg'], false,
879 msg['args'], msg['msg'], 889 msg['isSpawnUri'], msg['startPaused']).then((msg) {
880 false, msg['isSpawnUri'], msg['startPaused']).then((msg) {
881 replyPort.send(msg); 890 replyPort.send(msg);
882 }, onError: (String errorMessage) { 891 }, onError: (String errorMessage) {
883 replyPort.send([_SPAWN_FAILED_SIGNAL, errorMessage]); 892 replyPort.send([_SPAWN_FAILED_SIGNAL, errorMessage]);
884 }); 893 });
885 } 894 }
886 895
887 /** Log a message, forwarding to the main [_Manager] if appropriate. */ 896 /** Log a message, forwarding to the main [_Manager] if appropriate. */
888 static _log(msg) { 897 static _log(msg) {
889 if (_globalState.isWorker) { 898 if (_globalState.isWorker) {
890 _globalState.mainManager.postMessage( 899 _globalState.mainManager
891 _serializeMessage({'command': 'log', 'msg': msg })); 900 .postMessage(_serializeMessage({'command': 'log', 'msg': msg}));
892 } else { 901 } else {
893 try { 902 try {
894 _consoleLog(msg); 903 _consoleLog(msg);
895 } catch (e, trace) { 904 } catch (e, trace) {
896 throw new Exception(trace); 905 throw new Exception(trace);
897 } 906 }
898 } 907 }
899 } 908 }
900 909
901 static void _consoleLog(msg) { 910 static void _consoleLog(msg) {
(...skipping 12 matching lines...) Expand all
914 */ 923 */
915 static String _getJSFunctionName(Function f) { 924 static String _getJSFunctionName(Function f) {
916 return JS("String|Null", r'#.$name', f); 925 return JS("String|Null", r'#.$name', f);
917 } 926 }
918 927
919 /** Create a new JavaScript object instance given its constructor. */ 928 /** Create a new JavaScript object instance given its constructor. */
920 static dynamic _allocate(var ctor) { 929 static dynamic _allocate(var ctor) {
921 return JS("", "new #()", ctor); 930 return JS("", "new #()", ctor);
922 } 931 }
923 932
924 static Future<List> spawnFunction(void topLevelFunction(message), 933 static Future<List> spawnFunction(
925 var message, 934 void topLevelFunction(message), var message, bool startPaused) {
926 bool startPaused) {
927 IsolateNatives.enableSpawnWorker = true; 935 IsolateNatives.enableSpawnWorker = true;
928 final name = _getJSFunctionName(topLevelFunction); 936 final name = _getJSFunctionName(topLevelFunction);
929 if (name == null) { 937 if (name == null) {
930 throw new UnsupportedError( 938 throw new UnsupportedError("only top-level functions can be spawned.");
931 "only top-level functions can be spawned.");
932 } 939 }
933 bool isLight = false; 940 bool isLight = false;
934 bool isSpawnUri = false; 941 bool isSpawnUri = false;
935 return spawn(name, null, null, message, isLight, isSpawnUri, startPaused); 942 return spawn(name, null, null, message, isLight, isSpawnUri, startPaused);
936 } 943 }
937 944
938 static Future<List> spawnUri(Uri uri, List<String> args, var message, 945 static Future<List> spawnUri(
939 bool startPaused) { 946 Uri uri, List<String> args, var message, bool startPaused) {
940 IsolateNatives.enableSpawnWorker = true; 947 IsolateNatives.enableSpawnWorker = true;
941 bool isLight = false; 948 bool isLight = false;
942 bool isSpawnUri = true; 949 bool isSpawnUri = true;
943 return spawn(null, uri.toString(), args, message, 950 return spawn(
944 isLight, isSpawnUri, startPaused); 951 null, uri.toString(), args, message, isLight, isSpawnUri, startPaused);
945 } 952 }
946 953
947 // TODO(sigmund): clean up above, after we make the new API the default: 954 // TODO(sigmund): clean up above, after we make the new API the default:
948 955
949 /// If [uri] is `null` it is replaced with the current script. 956 /// If [uri] is `null` it is replaced with the current script.
950 static Future<List> spawn(String functionName, String uri, 957 static Future<List> spawn(String functionName, String uri, List<String> args,
951 List<String> args, message, 958 message, bool isLight, bool isSpawnUri, bool startPaused) {
952 bool isLight, bool isSpawnUri, bool startPaused) {
953 // Assume that the compiled version of the Dart file lives just next to the 959 // Assume that the compiled version of the Dart file lives just next to the
954 // dart file. 960 // dart file.
955 // TODO(floitsch): support precompiled version of dart2js output. 961 // TODO(floitsch): support precompiled version of dart2js output.
956 if (uri != null && uri.endsWith(".dart")) uri += ".js"; 962 if (uri != null && uri.endsWith(".dart")) uri += ".js";
957 963
958 ReceivePort port = new ReceivePort(); 964 ReceivePort port = new ReceivePort();
959 Completer<List> completer = new Completer(); 965 Completer<List> completer = new Completer();
960 port.first.then((msg) { 966 port.first.then((msg) {
961 if (msg[0] == _SPAWNED_SIGNAL) { 967 if (msg[0] == _SPAWNED_SIGNAL) {
962 completer.complete(msg); 968 completer.complete(msg);
963 } else { 969 } else {
964 assert(msg[0] == _SPAWN_FAILED_SIGNAL); 970 assert(msg[0] == _SPAWN_FAILED_SIGNAL);
965 completer.completeError(msg[1]); 971 completer.completeError(msg[1]);
966 } 972 }
967 }); 973 });
968 974
969 SendPort signalReply = port.sendPort; 975 SendPort signalReply = port.sendPort;
970 976
971 if (_globalState.useWorkers && !isLight) { 977 if (_globalState.useWorkers && !isLight) {
972 _startWorker( 978 _startWorker(functionName, uri, args, message, isSpawnUri, startPaused,
973 functionName, uri, args, message, isSpawnUri, startPaused,
974 signalReply, (String message) => completer.completeError(message)); 979 signalReply, (String message) => completer.completeError(message));
975 } else { 980 } else {
976 _startNonWorker( 981 _startNonWorker(functionName, uri, args, message, isSpawnUri, startPaused,
977 functionName, uri, args, message, isSpawnUri, startPaused,
978 signalReply); 982 signalReply);
979 } 983 }
980 return completer.future; 984 return completer.future;
981 } 985 }
982 986
983 static void _startWorker( 987 static void _startWorker(
984 String functionName, String uri, 988 String functionName,
985 List<String> args, message, 989 String uri,
990 List<String> args,
991 message,
986 bool isSpawnUri, 992 bool isSpawnUri,
987 bool startPaused, 993 bool startPaused,
988 SendPort replyPort, 994 SendPort replyPort,
989 void onError(String message)) { 995 void onError(String message)) {
990 // Make sure that the args list is a fresh generic list. A newly spawned 996 // Make sure that the args list is a fresh generic list. A newly spawned
991 // isolate should be able to assume that the arguments list is an 997 // isolate should be able to assume that the arguments list is an
992 // extendable list. 998 // extendable list.
993 if (args != null) args = new List<String>.from(args); 999 if (args != null) args = new List<String>.from(args);
994 if (_globalState.isWorker) { 1000 if (_globalState.isWorker) {
995 _globalState.mainManager.postMessage(_serializeMessage({ 1001 _globalState.mainManager.postMessage(_serializeMessage({
996 'command': 'spawn-worker', 1002 'command': 'spawn-worker',
997 'functionName': functionName, 1003 'functionName': functionName,
998 'args': args, 1004 'args': args,
999 'msg': message, 1005 'msg': message,
1000 'uri': uri, 1006 'uri': uri,
1001 'isSpawnUri': isSpawnUri, 1007 'isSpawnUri': isSpawnUri,
1002 'startPaused': startPaused, 1008 'startPaused': startPaused,
1003 'replyPort': replyPort})); 1009 'replyPort': replyPort
1010 }));
1004 } else { 1011 } else {
1005 _spawnWorker(functionName, uri, args, message, 1012 _spawnWorker(functionName, uri, args, message, isSpawnUri, startPaused,
1006 isSpawnUri, startPaused, replyPort, onError); 1013 replyPort, onError);
1007 } 1014 }
1008 } 1015 }
1009 1016
1010 static void _startNonWorker( 1017 static void _startNonWorker(
1011 String functionName, String uri, 1018 String functionName,
1012 List<String> args, var message, 1019 String uri,
1020 List<String> args,
1021 var message,
1013 bool isSpawnUri, 1022 bool isSpawnUri,
1014 bool startPaused, 1023 bool startPaused,
1015 SendPort replyPort) { 1024 SendPort replyPort) {
1016 // TODO(eub): support IE9 using an iframe -- Dart issue 1702. 1025 // TODO(eub): support IE9 using an iframe -- Dart issue 1702.
1017 if (uri != null) { 1026 if (uri != null) {
1018 throw new UnsupportedError( 1027 throw new UnsupportedError(
1019 "Currently spawnUri is not supported without web workers."); 1028 "Currently spawnUri is not supported without web workers.");
1020 } 1029 }
1021 // Clone the message to enforce the restrictions we have on isolate 1030 // Clone the message to enforce the restrictions we have on isolate
1022 // messages. 1031 // messages.
1023 message = _clone(message); 1032 message = _clone(message);
1024 // Make sure that the args list is a fresh generic list. A newly spawned 1033 // Make sure that the args list is a fresh generic list. A newly spawned
1025 // isolate should be able to assume that the arguments list is an 1034 // isolate should be able to assume that the arguments list is an
1026 // extendable list. 1035 // extendable list.
1027 if (args != null) args = new List<String>.from(args); 1036 if (args != null) args = new List<String>.from(args);
1028 _globalState.topEventLoop.enqueue(new _IsolateContext(), () { 1037 _globalState.topEventLoop.enqueue(new _IsolateContext(), () {
1029 final func = _getJSFunctionFromName(functionName); 1038 final func = _getJSFunctionFromName(functionName);
1030 _startIsolate(func, args, message, isSpawnUri, startPaused, replyPort); 1039 _startIsolate(func, args, message, isSpawnUri, startPaused, replyPort);
1031 }, 'nonworker start'); 1040 }, 'nonworker start');
1032 } 1041 }
1033 1042
1034 static Isolate get currentIsolate { 1043 static Isolate get currentIsolate {
1035 _IsolateContext context = JS_CURRENT_ISOLATE_CONTEXT(); 1044 _IsolateContext context = JS_CURRENT_ISOLATE_CONTEXT();
1036 return new Isolate(context.controlPort.sendPort, 1045 return new Isolate(context.controlPort.sendPort,
1037 pauseCapability: context.pauseCapability, 1046 pauseCapability: context.pauseCapability,
1038 terminateCapability: context.terminateCapability); 1047 terminateCapability: context.terminateCapability);
1039 } 1048 }
1040 1049
1041 static void _startIsolate(Function topLevel, 1050 static void _startIsolate(Function topLevel, List<String> args, message,
1042 List<String> args, message, 1051 bool isSpawnUri, bool startPaused, SendPort replyTo) {
1043 bool isSpawnUri,
1044 bool startPaused,
1045 SendPort replyTo) {
1046 _IsolateContext context = JS_CURRENT_ISOLATE_CONTEXT(); 1052 _IsolateContext context = JS_CURRENT_ISOLATE_CONTEXT();
1047 Primitives.initializeStatics(context.id); 1053 Primitives.initializeStatics(context.id);
1048 // The isolate's port does not keep the isolate open. 1054 // The isolate's port does not keep the isolate open.
1049 replyTo.send([_SPAWNED_SIGNAL, 1055 replyTo.send([
1050 context.controlPort.sendPort, 1056 _SPAWNED_SIGNAL,
1051 context.pauseCapability, 1057 context.controlPort.sendPort,
1052 context.terminateCapability]); 1058 context.pauseCapability,
1059 context.terminateCapability
1060 ]);
1053 1061
1054 void runStartFunction() { 1062 void runStartFunction() {
1055 context.initialized = true; 1063 context.initialized = true;
1056 if (!isSpawnUri) { 1064 if (!isSpawnUri) {
1057 topLevel(message); 1065 topLevel(message);
1058 } else if (topLevel is _MainFunctionArgsMessage) { 1066 } else if (topLevel is _MainFunctionArgsMessage) {
1059 topLevel(args, message); 1067 topLevel(args, message);
1060 } else if (topLevel is _MainFunctionArgs) { 1068 } else if (topLevel is _MainFunctionArgs) {
1061 topLevel(args); 1069 topLevel(args);
1062 } else { 1070 } else {
1063 topLevel(); 1071 topLevel();
1064 } 1072 }
1065 } 1073 }
1066 1074
1067 if (startPaused) { 1075 if (startPaused) {
1068 context.addPause(context.pauseCapability, context.pauseCapability); 1076 context.addPause(context.pauseCapability, context.pauseCapability);
1069 _globalState.topEventLoop.enqueue(context, runStartFunction, 1077 _globalState.topEventLoop
1070 'start isolate'); 1078 .enqueue(context, runStartFunction, 'start isolate');
1071 } else { 1079 } else {
1072 runStartFunction(); 1080 runStartFunction();
1073 } 1081 }
1074 } 1082 }
1075 1083
1076 /** 1084 /**
1077 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor 1085 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor
1078 * name for the isolate entry point class. 1086 * name for the isolate entry point class.
1079 */ 1087 */
1080 static void _spawnWorker(functionName, String uri, 1088 static void _spawnWorker(
1081 List<String> args, message, 1089 functionName,
1082 bool isSpawnUri, 1090 String uri,
1083 bool startPaused, 1091 List<String> args,
1084 SendPort replyPort, 1092 message,
1085 void onError(String message)) { 1093 bool isSpawnUri,
1094 bool startPaused,
1095 SendPort replyPort,
1096 void onError(String message)) {
1086 if (uri == null) uri = thisScript; 1097 if (uri == null) uri = thisScript;
1087 final worker = JS('var', 'new Worker(#)', uri); 1098 final worker = JS('var', 'new Worker(#)', uri);
1088 // Trampolines are used when wanting to call a Dart closure from 1099 // Trampolines are used when wanting to call a Dart closure from
1089 // JavaScript. The helper function DART_CLOSURE_TO_JS only accepts 1100 // JavaScript. The helper function DART_CLOSURE_TO_JS only accepts
1090 // top-level or static methods, and the trampoline allows us to capture 1101 // top-level or static methods, and the trampoline allows us to capture
1091 // arguments and values which can be passed to a static method. 1102 // arguments and values which can be passed to a static method.
1092 final onerrorTrampoline = JS( 1103 final onerrorTrampoline = JS(
1093 '', 1104 '',
1094 ''' 1105 '''
1095 (function (f, u, c) { 1106 (function (f, u, c) {
1096 return function(e) { 1107 return function(e) {
1097 return f(e, u, c) 1108 return f(e, u, c)
1098 } 1109 }
1099 })(#, #, #)''', 1110 })(#, #, #)''',
1100 workerOnError, uri, onError); 1111 workerOnError,
1112 uri,
1113 onError);
1101 JS('void', '#.onerror = #', worker, onerrorTrampoline); 1114 JS('void', '#.onerror = #', worker, onerrorTrampoline);
1102 1115
1103 var processWorkerMessageTrampoline = JS( 1116 var processWorkerMessageTrampoline = JS(
1104 '', 1117 '',
1105 """ 1118 """
1106 (function (f, a) { 1119 (function (f, a) {
1107 return function (e) { 1120 return function (e) {
1108 // We can stop listening for errors when the first message is received as 1121 // We can stop listening for errors when the first message is received as
1109 // we only listen for messages to determine if the uri was bad. 1122 // we only listen for messages to determine if the uri was bad.
1110 e.onerror = null; 1123 e.onerror = null;
1111 return f(a, e); 1124 return f(a, e);
1112 } 1125 }
1113 })(#, #)""", 1126 })(#, #)""",
1114 _processWorkerMessage, 1127 _processWorkerMessage,
1115 worker); 1128 worker);
1116 JS('void', '#.onmessage = #', worker, processWorkerMessageTrampoline); 1129 JS('void', '#.onmessage = #', worker, processWorkerMessageTrampoline);
1117 var workerId = _globalState.nextManagerId++; 1130 var workerId = _globalState.nextManagerId++;
1118 // We also store the id on the worker itself so that we can unregister it. 1131 // We also store the id on the worker itself so that we can unregister it.
1119 workerIds[worker] = workerId; 1132 workerIds[worker] = workerId;
1120 _globalState.managers[workerId] = worker; 1133 _globalState.managers[workerId] = worker;
1121 JS('void', '#.postMessage(#)', worker, _serializeMessage({ 1134 JS(
1122 'command': 'start', 1135 'void',
1123 'id': workerId, 1136 '#.postMessage(#)',
1124 // Note: we serialize replyPort twice because the child worker needs to 1137 worker,
1125 // first deserialize the worker id, before it can correctly deserialize 1138 _serializeMessage({
1126 // the port (port deserialization is sensitive to what is the current 1139 'command': 'start',
1127 // workerId). 1140 'id': workerId,
1128 'replyTo': _serializeMessage(replyPort), 1141 // Note: we serialize replyPort twice because the child worker needs t o
1129 'args': args, 1142 // first deserialize the worker id, before it can correctly deserializ e
1130 'msg': _serializeMessage(message), 1143 // the port (port deserialization is sensitive to what is the current
1131 'isSpawnUri': isSpawnUri, 1144 // workerId).
1132 'startPaused': startPaused, 1145 'replyTo': _serializeMessage(replyPort),
1133 'functionName': functionName })); 1146 'args': args,
1147 'msg': _serializeMessage(message),
1148 'isSpawnUri': isSpawnUri,
1149 'startPaused': startPaused,
1150 'functionName': functionName
1151 }));
1134 } 1152 }
1135 1153
1136 static bool workerOnError( 1154 static bool workerOnError(
1137 /* Event */ event, 1155 /* Event */ event,
1138 String uri, 1156 String uri,
1139 void onError(String message)) { 1157 void onError(String message)) {
1140 // Attempt to shut up the browser, as the error has been handled. Chrome 1158 // Attempt to shut up the browser, as the error has been handled. Chrome
1141 // ignores this :-( 1159 // ignores this :-(
1142 JS('void', '#.preventDefault()', event); 1160 JS('void', '#.preventDefault()', event);
1143 String message = JS('String|Null', '#.message', event); 1161 String message = JS('String|Null', '#.message', event);
(...skipping 14 matching lines...) Expand all
1158 ********************************************************/ 1176 ********************************************************/
1159 1177
1160 /** Common functionality to all send ports. */ 1178 /** Common functionality to all send ports. */
1161 abstract class _BaseSendPort implements SendPort { 1179 abstract class _BaseSendPort implements SendPort {
1162 /** Id for the destination isolate. */ 1180 /** Id for the destination isolate. */
1163 final int _isolateId; 1181 final int _isolateId;
1164 1182
1165 const _BaseSendPort(this._isolateId); 1183 const _BaseSendPort(this._isolateId);
1166 1184
1167 void _checkReplyTo(SendPort replyTo) { 1185 void _checkReplyTo(SendPort replyTo) {
1168 if (replyTo != null 1186 if (replyTo != null &&
1169 && replyTo is! _NativeJsSendPort 1187 replyTo is! _NativeJsSendPort &&
1170 && replyTo is! _WorkerSendPort) { 1188 replyTo is! _WorkerSendPort) {
1171 throw new Exception("SendPort.send: Illegal replyTo port type"); 1189 throw new Exception("SendPort.send: Illegal replyTo port type");
1172 } 1190 }
1173 } 1191 }
1174 1192
1175 void send(var message); 1193 void send(var message);
1176 bool operator ==(var other); 1194 bool operator ==(var other);
1177 int get hashCode; 1195 int get hashCode;
1178 } 1196 }
1179 1197
1180 /** A send port that delivers messages in-memory via native JavaScript calls. */ 1198 /** A send port that delivers messages in-memory via native JavaScript calls. */
(...skipping 14 matching lines...) Expand all
1195 isolate.handleControlMessage(msg); 1213 isolate.handleControlMessage(msg);
1196 return; 1214 return;
1197 } 1215 }
1198 _globalState.topEventLoop.enqueue(isolate, () { 1216 _globalState.topEventLoop.enqueue(isolate, () {
1199 if (!_receivePort._isClosed) { 1217 if (!_receivePort._isClosed) {
1200 _receivePort._add(msg); 1218 _receivePort._add(msg);
1201 } 1219 }
1202 }, 'receive $message'); 1220 }, 'receive $message');
1203 } 1221 }
1204 1222
1205 bool operator ==(var other) => (other is _NativeJsSendPort) && 1223 bool operator ==(var other) =>
1206 (_receivePort == other._receivePort); 1224 (other is _NativeJsSendPort) && (_receivePort == other._receivePort);
1207 1225
1208 int get hashCode => _receivePort._id; 1226 int get hashCode => _receivePort._id;
1209 } 1227 }
1210 1228
1211 /** A send port that delivers messages via worker.postMessage. */ 1229 /** A send port that delivers messages via worker.postMessage. */
1212 // TODO(eub): abstract this for iframes. 1230 // TODO(eub): abstract this for iframes.
1213 class _WorkerSendPort extends _BaseSendPort implements SendPort { 1231 class _WorkerSendPort extends _BaseSendPort implements SendPort {
1214 final int _workerId; 1232 final int _workerId;
1215 final int _receivePortId; 1233 final int _receivePortId;
1216 1234
1217 const _WorkerSendPort(this._workerId, int isolateId, this._receivePortId) 1235 const _WorkerSendPort(this._workerId, int isolateId, this._receivePortId)
1218 : super(isolateId); 1236 : super(isolateId);
1219 1237
1220 void send(var message) { 1238 void send(var message) {
1221 final workerMessage = _serializeMessage({ 1239 final workerMessage =
1222 'command': 'message', 1240 _serializeMessage({'command': 'message', 'port': this, 'msg': message});
1223 'port': this,
1224 'msg': message});
1225 1241
1226 if (_globalState.isWorker) { 1242 if (_globalState.isWorker) {
1227 // Communication from one worker to another go through the 1243 // Communication from one worker to another go through the
1228 // main worker. 1244 // main worker.
1229 _globalState.mainManager.postMessage(workerMessage); 1245 _globalState.mainManager.postMessage(workerMessage);
1230 } else { 1246 } else {
1231 // Deliver the message only if the worker is still alive. 1247 // Deliver the message only if the worker is still alive.
1232 /* Worker */ var manager = _globalState.managers[_workerId]; 1248 /* Worker */ var manager = _globalState.managers[_workerId];
1233 if (manager != null) { 1249 if (manager != null) {
1234 JS('void', '#.postMessage(#)', manager, workerMessage); 1250 JS('void', '#.postMessage(#)', manager, workerMessage);
(...skipping 25 matching lines...) Expand all
1260 _globalState.currentContext.register(_id, this); 1276 _globalState.currentContext.register(_id, this);
1261 } 1277 }
1262 1278
1263 RawReceivePortImpl.weak(this._handler) : _id = _nextFreeId++ { 1279 RawReceivePortImpl.weak(this._handler) : _id = _nextFreeId++ {
1264 _globalState.currentContext.registerWeak(_id, this); 1280 _globalState.currentContext.registerWeak(_id, this);
1265 } 1281 }
1266 1282
1267 // Creates the control port of an isolate. 1283 // Creates the control port of an isolate.
1268 // This is created before the isolate context object itself, 1284 // This is created before the isolate context object itself,
1269 // so it cannot access the static _nextFreeId field. 1285 // so it cannot access the static _nextFreeId field.
1270 RawReceivePortImpl._controlPort() : _handler = null, _id = 0; 1286 RawReceivePortImpl._controlPort()
1287 : _handler = null,
1288 _id = 0;
1271 1289
1272 void set handler(Function newHandler) { 1290 void set handler(Function newHandler) {
1273 _handler = newHandler; 1291 _handler = newHandler;
1274 } 1292 }
1275 1293
1276 // Close the port without unregistering it. 1294 // Close the port without unregistering it.
1277 // Used by an isolate context to close all ports when shutting down. 1295 // Used by an isolate context to close all ports when shutting down.
1278 void _close() { 1296 void _close() {
1279 _isClosed = true; 1297 _isClosed = true;
1280 _handler = null; 1298 _handler = null;
(...skipping 24 matching lines...) Expand all
1305 1323
1306 ReceivePortImpl.weak() 1324 ReceivePortImpl.weak()
1307 : this.fromRawReceivePort(new RawReceivePortImpl.weak(null)); 1325 : this.fromRawReceivePort(new RawReceivePortImpl.weak(null));
1308 1326
1309 ReceivePortImpl.fromRawReceivePort(this._rawPort) { 1327 ReceivePortImpl.fromRawReceivePort(this._rawPort) {
1310 _controller = new StreamController(onCancel: close, sync: true); 1328 _controller = new StreamController(onCancel: close, sync: true);
1311 _rawPort.handler = _controller.add; 1329 _rawPort.handler = _controller.add;
1312 } 1330 }
1313 1331
1314 StreamSubscription listen(void onData(var event), 1332 StreamSubscription listen(void onData(var event),
1315 {Function onError, 1333 {Function onError, void onDone(), bool cancelOnError}) {
1316 void onDone(), 1334 return _controller.stream.listen(onData,
1317 bool cancelOnError}) { 1335 onError: onError, onDone: onDone, cancelOnError: cancelOnError);
1318 return _controller.stream.listen(onData, onError: onError, onDone: onDone,
1319 cancelOnError: cancelOnError);
1320 } 1336 }
1321 1337
1322 void close() { 1338 void close() {
1323 _rawPort.close(); 1339 _rawPort.close();
1324 _controller.close(); 1340 _controller.close();
1325 } 1341 }
1326 1342
1327 SendPort get sendPort => _rawPort.sendPort; 1343 SendPort get sendPort => _rawPort.sendPort;
1328 } 1344 }
1329 1345
1330 class TimerImpl implements Timer { 1346 class TimerImpl implements Timer {
1331 final bool _once; 1347 final bool _once;
1332 bool _inEventLoop = false; 1348 bool _inEventLoop = false;
1333 int _handle; 1349 int _handle;
1334 1350
1335 TimerImpl(int milliseconds, void callback()) 1351 TimerImpl(int milliseconds, void callback()) : _once = true {
1336 : _once = true {
1337 if (milliseconds == 0 && (!hasTimer() || _globalState.isWorker)) { 1352 if (milliseconds == 0 && (!hasTimer() || _globalState.isWorker)) {
1338
1339 void internalCallback() { 1353 void internalCallback() {
1340 _handle = null; 1354 _handle = null;
1341 callback(); 1355 callback();
1342 } 1356 }
1343 1357
1344 // Setting _handle to something different from null indicates that the 1358 // Setting _handle to something different from null indicates that the
1345 // callback has not been run. Hence, the choice of 1 is arbitrary. 1359 // callback has not been run. Hence, the choice of 1 is arbitrary.
1346 _handle = 1; 1360 _handle = 1;
1347 1361
1348 // This makes a dependency between the async library and the 1362 // This makes a dependency between the async library and the
1349 // event loop of the isolate library. The compiler makes sure 1363 // event loop of the isolate library. The compiler makes sure
1350 // that the event loop is compiled if [Timer] is used. 1364 // that the event loop is compiled if [Timer] is used.
1351 // TODO(7907): In case of web workers, we need to use the event 1365 // TODO(7907): In case of web workers, we need to use the event
1352 // loop instead of setTimeout, to make sure the futures get executed in 1366 // loop instead of setTimeout, to make sure the futures get executed in
1353 // order. 1367 // order.
1354 _globalState.topEventLoop.enqueue( 1368 _globalState.topEventLoop
1355 _globalState.currentContext, internalCallback, 'timer'); 1369 .enqueue(_globalState.currentContext, internalCallback, 'timer');
1356 _inEventLoop = true; 1370 _inEventLoop = true;
1357 } else if (hasTimer()) { 1371 } else if (hasTimer()) {
1358
1359 void internalCallback() { 1372 void internalCallback() {
1360 _handle = null; 1373 _handle = null;
1361 leaveJsAsync(); 1374 leaveJsAsync();
1362 callback(); 1375 callback();
1363 } 1376 }
1364 1377
1365 enterJsAsync(); 1378 enterJsAsync();
1366 1379
1367 _handle = JS( 1380 _handle = JS(
1368 'int', '#.setTimeout(#, #)', global, internalCallback, milliseconds); 1381 'int', '#.setTimeout(#, #)', global, internalCallback, milliseconds);
1369 } else { 1382 } else {
1370 assert(milliseconds > 0); 1383 assert(milliseconds > 0);
1371 throw new UnsupportedError("Timer greater than 0."); 1384 throw new UnsupportedError("Timer greater than 0.");
1372 } 1385 }
1373 } 1386 }
1374 1387
1375 TimerImpl.periodic(int milliseconds, void callback(Timer timer)) 1388 TimerImpl.periodic(int milliseconds, void callback(Timer timer))
1376 : _once = false { 1389 : _once = false {
1377 if (hasTimer()) { 1390 if (hasTimer()) {
1378 enterJsAsync(); 1391 enterJsAsync();
1379 _handle = JS('int', '#.setInterval(#, #)', 1392 _handle = JS('int', '#.setInterval(#, #)', global, () {
1380 global, () { callback(this); }, milliseconds); 1393 callback(this);
1394 }, milliseconds);
1381 } else { 1395 } else {
1382 throw new UnsupportedError("Periodic timer."); 1396 throw new UnsupportedError("Periodic timer.");
1383 } 1397 }
1384 } 1398 }
1385 1399
1386 void cancel() { 1400 void cancel() {
1387 if (hasTimer()) { 1401 if (hasTimer()) {
1388 if (_inEventLoop) { 1402 if (_inEventLoop) {
1389 throw new UnsupportedError("Timer in event loop cannot be canceled."); 1403 throw new UnsupportedError("Timer in event loop cannot be canceled.");
1390 } 1404 }
(...skipping 10 matching lines...) Expand all
1401 } 1415 }
1402 } 1416 }
1403 1417
1404 bool get isActive => _handle != null; 1418 bool get isActive => _handle != null;
1405 } 1419 }
1406 1420
1407 bool hasTimer() { 1421 bool hasTimer() {
1408 return JS('', '#.setTimeout', global) != null; 1422 return JS('', '#.setTimeout', global) != null;
1409 } 1423 }
1410 1424
1411
1412 /** 1425 /**
1413 * Implementation class for [Capability]. 1426 * Implementation class for [Capability].
1414 * 1427 *
1415 * It has the same name to make it harder for users to distinguish. 1428 * It has the same name to make it harder for users to distinguish.
1416 */ 1429 */
1417 class CapabilityImpl implements Capability { 1430 class CapabilityImpl implements Capability {
1418 /** Internal random secret identifying the capability. */ 1431 /** Internal random secret identifying the capability. */
1419 final int _id; 1432 final int _id;
1420 1433
1421 CapabilityImpl() : this._internal(random64()); 1434 CapabilityImpl() : this._internal(random64());
1422 1435
1423 CapabilityImpl._internal(this._id); 1436 CapabilityImpl._internal(this._id);
1424 1437
1425 int get hashCode { 1438 int get hashCode {
1426 // Thomas Wang 32 bit Mix. 1439 // Thomas Wang 32 bit Mix.
1427 // http://www.concentric.net/~Ttwang/tech/inthash.htm 1440 // http://www.concentric.net/~Ttwang/tech/inthash.htm
1428 // (via https://gist.github.com/badboy/6267743) 1441 // (via https://gist.github.com/badboy/6267743)
1429 int hash = _id; 1442 int hash = _id;
1430 hash = (hash >> 0) ^ (hash ~/ 0x100000000); // To 32 bit from ~64. 1443 hash = (hash >> 0) ^ (hash ~/ 0x100000000); // To 32 bit from ~64.
1431 hash = (~hash + (hash << 15)) & 0xFFFFFFFF; 1444 hash = (~hash + (hash << 15)) & 0xFFFFFFFF;
1432 hash ^= hash >> 12; 1445 hash ^= hash >> 12;
1433 hash = (hash * 5) & 0xFFFFFFFF; 1446 hash = (hash * 5) & 0xFFFFFFFF;
1434 hash ^= hash >> 4; 1447 hash ^= hash >> 4;
1435 hash = (hash * 2057) & 0xFFFFFFFF; 1448 hash = (hash * 2057) & 0xFFFFFFFF;
1436 hash ^= hash >> 16; 1449 hash ^= hash >> 16;
1437 return hash; 1450 return hash;
1438 } 1451 }
1439 1452
1440 bool operator==(Object other) { 1453 bool operator ==(Object other) {
1441 if (identical(other, this)) return true; 1454 if (identical(other, this)) return true;
1442 if (other is CapabilityImpl) { 1455 if (other is CapabilityImpl) {
1443 return identical(_id, other._id); 1456 return identical(_id, other._id);
1444 } 1457 }
1445 return false; 1458 return false;
1446 } 1459 }
1447 } 1460 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698