Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library _isolate_helper; | 5 library _isolate_helper; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection' show Queue, HashMap; | 8 import 'dart:collection' show Queue, HashMap; |
| 9 import 'dart:isolate'; | 9 import 'dart:isolate'; |
| 10 import 'dart:_js_helper' show | 10 import 'dart:_js_helper' show |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 25 /** | 25 /** |
| 26 * Called by the compiler to support switching | 26 * Called by the compiler to support switching |
| 27 * between isolates when we get a callback from the DOM. | 27 * between isolates when we get a callback from the DOM. |
| 28 */ | 28 */ |
| 29 _callInIsolate(_IsolateContext isolate, Function function) { | 29 _callInIsolate(_IsolateContext isolate, Function function) { |
| 30 var result = isolate.eval(function); | 30 var result = isolate.eval(function); |
| 31 _globalState.topEventLoop.run(); | 31 _globalState.topEventLoop.run(); |
| 32 return result; | 32 return result; |
| 33 } | 33 } |
| 34 | 34 |
| 35 /// Marks entering a javascript async operation to keep the worker alive. | |
| 36 /// Marks entering a JavaScript async operation to keep the worker alive. | 35 /// Marks entering a JavaScript async operation to keep the worker alive. |
| 37 /// | 36 /// |
| 38 /// To be called by library code before starting an async operation controlled | 37 /// To be called by library code before starting an async operation controlled |
| 39 /// by the JavaScript event handler. | 38 /// by the JavaScript event handler. |
| 40 /// | 39 /// |
| 41 /// Also call [leaveJsAsync] in all callback handlers marking the end of that | 40 /// Also call [leaveJsAsync] in all callback handlers marking the end of that |
| 42 /// async operation (also error handlers) so the worker can be released. | 41 /// async operation (also error handlers) so the worker can be released. |
| 43 /// | 42 /// |
| 44 /// These functions only has to be called for code that can be run from a | 43 /// These functions only has to be called for code that can be run from a |
| 45 /// worker-isolate (so not for general dom operations). | 44 /// worker-isolate (so not for general dom operations). |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 263 /** Registry of weak receive ports currently active on this isolate. */ | 262 /** Registry of weak receive ports currently active on this isolate. */ |
| 264 final Set<int> weakPorts = new Set<int>(); | 263 final Set<int> weakPorts = new Set<int>(); |
| 265 | 264 |
| 266 /** Holds isolate globals (statics and top-level properties). */ | 265 /** Holds isolate globals (statics and top-level properties). */ |
| 267 // native object containing all globals of an isolate. | 266 // native object containing all globals of an isolate. |
| 268 final isolateStatics = JS_CREATE_ISOLATE(); | 267 final isolateStatics = JS_CREATE_ISOLATE(); |
| 269 | 268 |
| 270 final RawReceivePortImpl controlPort = new RawReceivePortImpl._controlPort(); | 269 final RawReceivePortImpl controlPort = new RawReceivePortImpl._controlPort(); |
| 271 | 270 |
| 272 final Capability pauseCapability = new Capability(); | 271 final Capability pauseCapability = new Capability(); |
| 272 final Capability inspectCapability = new Capability(); | |
| 273 | 273 |
| 274 // TODO(lrn): Store these in single "PauseState" object, so they don't take | 274 // TODO(lrn): Store these in single "PauseState" object, so they don't take |
| 275 // up as much room when not pausing. | 275 // up as much room when not pausing. |
| 276 bool isPaused = false; | 276 bool isPaused = false; |
| 277 List<_IsolateEvent> delayedEvents = []; | 277 List<_IsolateEvent> delayedEvents = []; |
| 278 Set<Capability> pauseTokens = new Set(); | 278 Set<Capability> pauseTokens = new Set(); |
| 279 | 279 |
| 280 // Container with the "on exit" handler send-ports. | |
| 281 var doneHandlers; | |
| 282 | |
| 280 _IsolateContext() { | 283 _IsolateContext() { |
| 281 this.registerWeak(controlPort._id, controlPort); | 284 this.registerWeak(controlPort._id, controlPort); |
| 282 } | 285 } |
| 283 | 286 |
| 284 void addPause(Capability authentification, Capability resume) { | 287 void addPause(Capability authentification, Capability resume) { |
| 285 if (pauseCapability != authentification) return; | 288 if (pauseCapability != authentification) return; |
| 286 if (pauseTokens.add(resume) && !isPaused) { | 289 if (pauseTokens.add(resume) && !isPaused) { |
| 287 isPaused = true; | 290 isPaused = true; |
| 288 } | 291 } |
| 289 _updateGlobalState(); | 292 _updateGlobalState(); |
| 290 } | 293 } |
| 291 | 294 |
| 292 void removePause(Capability resume) { | 295 void removePause(Capability resume) { |
| 293 if (!isPaused) return; | 296 if (!isPaused) return; |
| 294 pauseTokens.remove(resume); | 297 pauseTokens.remove(resume); |
| 295 if (pauseTokens.isEmpty) { | 298 if (pauseTokens.isEmpty) { |
| 296 while(delayedEvents.isNotEmpty) { | 299 while(delayedEvents.isNotEmpty) { |
| 297 _IsolateEvent event = delayedEvents.removeLast(); | 300 _IsolateEvent event = delayedEvents.removeLast(); |
| 298 _globalState.topEventLoop.prequeue(event); | 301 _globalState.topEventLoop.prequeue(event); |
| 299 } | 302 } |
| 300 isPaused = false; | 303 isPaused = false; |
| 301 } | 304 } |
| 302 _updateGlobalState(); | 305 _updateGlobalState(); |
| 303 } | 306 } |
| 304 | 307 |
| 308 void addDoneListener(Capability inspect, SendPort response) { | |
| 309 if (inspectCapability != inspect) return; | |
| 310 if (doneHandlers == null) { | |
| 311 doneHandlers = []; | |
| 312 } | |
| 313 // If necessary, we can switch doneHandlers to a Set if it gets larget. | |
|
floitsch
2014/02/25 19:25:48
larger.
| |
| 314 // That is not expected to happen in practice. | |
| 315 if (doneHandlers.contains(response)) return; | |
| 316 doneHandlers.add(response); | |
| 317 } | |
| 318 | |
| 305 /** | 319 /** |
| 306 * Run [code] in the context of the isolate represented by [this]. | 320 * Run [code] in the context of the isolate represented by [this]. |
| 307 */ | 321 */ |
| 308 dynamic eval(Function code) { | 322 dynamic eval(Function code) { |
| 309 var old = _globalState.currentContext; | 323 var old = _globalState.currentContext; |
| 310 _globalState.currentContext = this; | 324 _globalState.currentContext = this; |
| 311 this._setGlobals(); | 325 this._setGlobals(); |
| 312 var result = null; | 326 var result = null; |
| 313 try { | 327 try { |
| 314 result = code(); | 328 result = code(); |
| 315 } finally { | 329 } finally { |
| 316 _globalState.currentContext = old; | 330 _globalState.currentContext = old; |
| 317 if (old != null) old._setGlobals(); | 331 if (old != null) old._setGlobals(); |
| 318 } | 332 } |
| 319 return result; | 333 return result; |
| 320 } | 334 } |
| 321 | 335 |
| 322 void _setGlobals() { | 336 void _setGlobals() { |
| 323 JS_SET_CURRENT_ISOLATE(isolateStatics); | 337 JS_SET_CURRENT_ISOLATE(isolateStatics); |
| 324 } | 338 } |
| 325 | 339 |
| 326 void handleControlMessage(message) { | 340 void handleControlMessage(message) { |
| 327 switch (message[0]) { | 341 switch (message[0]) { |
| 328 case "pause": | 342 case "pause": |
| 329 addPause(message[1], message[2]); | 343 addPause(message[1], message[2]); |
| 330 break; | 344 break; |
| 331 case "resume": | 345 case "resume": |
| 332 removePause(message[1]); | 346 removePause(message[1]); |
| 333 break; | 347 break; |
| 348 case 'ondone': | |
| 349 addDoneListener(message[1], message[2]); | |
| 350 break; | |
| 334 default: | 351 default: |
| 335 print("UNKOWN MESSAGE: $message"); | 352 print("UNKNOWN MESSAGE: $message"); |
| 336 } | 353 } |
| 337 } | 354 } |
| 338 | 355 |
| 339 /** Looks up a port registered for this isolate. */ | 356 /** Looks up a port registered for this isolate. */ |
| 340 RawReceivePortImpl lookup(int portId) => ports[portId]; | 357 RawReceivePortImpl lookup(int portId) => ports[portId]; |
| 341 | 358 |
| 342 void _addRegistration(int portId, RawReceivePortImpl port) { | 359 void _addRegistration(int portId, RawReceivePortImpl port) { |
| 343 if (ports.containsKey(portId)) { | 360 if (ports.containsKey(portId)) { |
| 344 throw new Exception("Registry: ports must be registered only once."); | 361 throw new Exception("Registry: ports must be registered only once."); |
| 345 } | 362 } |
| 346 ports[portId] = port; | 363 ports[portId] = port; |
| 347 } | 364 } |
| 348 | 365 |
| 349 /** Registers a port on this isolate. */ | 366 /** Registers a port on this isolate. */ |
| 350 void register(int portId, RawReceivePortImpl port) { | 367 void register(int portId, RawReceivePortImpl port) { |
| 351 _addRegistration(portId, port); | 368 _addRegistration(portId, port); |
| 352 _updateGlobalState(); | 369 _updateGlobalState(); |
| 353 } | 370 } |
| 354 | 371 |
| 355 /** | 372 /** |
| 356 * Registers a weak port on this isolate. | 373 * Registers a weak port on this isolate. |
| 357 * | 374 * |
| 358 * The port does not keep the isolate active. | 375 * The port does not keep the isolate active. |
| 359 */ | 376 */ |
| 360 void registerWeak(int portId, RawReceivePortImpl port) { | 377 void registerWeak(int portId, RawReceivePortImpl port) { |
| 361 weakPorts.add(portId); | 378 weakPorts.add(portId); |
| 362 _addRegistration(portId, port); | 379 _addRegistration(portId, port); |
| 363 } | 380 } |
| 364 | 381 |
| 365 _updateGlobalState() { | 382 void _updateGlobalState() { |
| 366 if (ports.length - weakPorts.length > 0 || isPaused) { | 383 if (ports.length - weakPorts.length > 0 || isPaused) { |
| 367 _globalState.isolates[id] = this; // indicate this isolate is active | 384 _globalState.isolates[id] = this; // indicate this isolate is active |
| 368 } else { | 385 } else { |
| 369 _globalState.isolates.remove(id); // indicate this isolate is not active | 386 _shutdown(); |
| 370 } | 387 } |
| 371 } | 388 } |
| 372 | 389 |
| 390 void _shutdown() { | |
| 391 _globalState.isolates.remove(id); // indicate this isolate is not active | |
|
floitsch
2014/02/25 19:25:48
"I"ndicate ... active"."
| |
| 392 // Send "done" event to all listeners. This must be done after deactivating | |
| 393 // the current isolate, or it may get events if listening to itself. | |
| 394 if (doneHandlers != null) { | |
| 395 for (SendPort port in doneHandlers) { | |
| 396 port.send(null); | |
| 397 } | |
| 398 } | |
| 399 } | |
| 400 | |
| 373 /** Unregister a port on this isolate. */ | 401 /** Unregister a port on this isolate. */ |
| 374 void unregister(int portId) { | 402 void unregister(int portId) { |
| 375 ports.remove(portId); | 403 ports.remove(portId); |
| 376 weakPorts.remove(portId); | 404 weakPorts.remove(portId); |
| 377 _updateGlobalState(); | 405 _updateGlobalState(); |
| 378 } | 406 } |
| 379 } | 407 } |
| 380 | 408 |
| 381 /** Represent the event loop on a javascript thread (DOM or worker). */ | 409 /** Represent the event loop on a javascript thread (DOM or worker). */ |
| 382 class _EventLoop { | 410 class _EventLoop { |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 513 /// Note: IsolateNatives depends on _globalState which is only set up correctly | 541 /// Note: IsolateNatives depends on _globalState which is only set up correctly |
| 514 /// when 'dart:isolate' has been imported. | 542 /// when 'dart:isolate' has been imported. |
| 515 class IsolateNatives { | 543 class IsolateNatives { |
| 516 | 544 |
| 517 static String thisScript = computeThisScript(); | 545 static String thisScript = computeThisScript(); |
| 518 | 546 |
| 519 /// Associates an ID with a native worker object. | 547 /// Associates an ID with a native worker object. |
| 520 static final Expando<int> workerIds = new Expando<int>(); | 548 static final Expando<int> workerIds = new Expando<int>(); |
| 521 | 549 |
| 522 /** | 550 /** |
| 523 * The src url for the script tag that loaded this code. Used to create | 551 * The src url for the script tag that loaded this Used to create |
|
floitsch
2014/02/25 19:25:48
missing ".".
| |
| 524 * JavaScript workers. | 552 * JavaScript workers. |
| 525 */ | 553 */ |
| 526 static String computeThisScript() { | 554 static String computeThisScript() { |
| 527 var currentScript = JS('', r'init.currentScript'); | 555 var currentScript = JS('', r'init.currentScript'); |
| 528 if (currentScript != null) { | 556 if (currentScript != null) { |
| 529 return JS('String', 'String(#.src)', currentScript); | 557 return JS('String', 'String(#.src)', currentScript); |
| 530 } | 558 } |
| 531 if (Primitives.isD8) return computeThisScriptD8(); | 559 if (Primitives.isD8) return computeThisScriptD8(); |
| 532 if (Primitives.isJsshell) return computeThisScriptJsshell(); | 560 if (Primitives.isJsshell) return computeThisScriptJsshell(); |
| 533 // A worker has no script tag - so get an url from a stack-trace. | 561 // A worker has no script tag - so get an url from a stack-trace. |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 781 static void _startIsolate(Function topLevel, | 809 static void _startIsolate(Function topLevel, |
| 782 List<String> args, message, | 810 List<String> args, message, |
| 783 bool isSpawnUri, | 811 bool isSpawnUri, |
| 784 bool startPaused, | 812 bool startPaused, |
| 785 SendPort replyTo) { | 813 SendPort replyTo) { |
| 786 _IsolateContext context = JS_CURRENT_ISOLATE_CONTEXT(); | 814 _IsolateContext context = JS_CURRENT_ISOLATE_CONTEXT(); |
| 787 Primitives.initializeStatics(context.id); | 815 Primitives.initializeStatics(context.id); |
| 788 // The isolate's port does not keep the isolate open. | 816 // The isolate's port does not keep the isolate open. |
| 789 replyTo.send([_SPAWNED_SIGNAL, | 817 replyTo.send([_SPAWNED_SIGNAL, |
| 790 context.controlPort.sendPort, | 818 context.controlPort.sendPort, |
| 791 context.pauseCapability]); | 819 context.pauseCapability, |
| 820 context.inspectCapability]); | |
| 792 | 821 |
| 793 void runStartFunction() { | 822 void runStartFunction() { |
| 794 if (!isSpawnUri) { | 823 if (!isSpawnUri) { |
| 795 topLevel(message); | 824 topLevel(message); |
| 796 } else if (topLevel is _MainFunctionArgsMessage) { | 825 } else if (topLevel is _MainFunctionArgsMessage) { |
| 797 topLevel(args, message); | 826 topLevel(args, message); |
| 798 } else if (topLevel is _MainFunctionArgs) { | 827 } else if (topLevel is _MainFunctionArgs) { |
| 799 topLevel(args); | 828 topLevel(args); |
| 800 } else { | 829 } else { |
| 801 topLevel(); | 830 topLevel(); |
| (...skipping 721 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1523 } | 1552 } |
| 1524 | 1553 |
| 1525 bool operator==(Object other) { | 1554 bool operator==(Object other) { |
| 1526 if (identical(other, this)) return true; | 1555 if (identical(other, this)) return true; |
| 1527 if (other is CapabilityImpl) { | 1556 if (other is CapabilityImpl) { |
| 1528 return identical(_id, other._id); | 1557 return identical(_id, other._id); |
| 1529 } | 1558 } |
| 1530 return false; | 1559 return false; |
| 1531 } | 1560 } |
| 1532 } | 1561 } |
| OLD | NEW |