Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 /** | 5 /** |
| 6 * A native object that is shared across isolates. This object is visible to all | 6 * A native object that is shared across isolates. This object is visible to all |
| 7 * isolates running on the same worker (either UI or background web worker). | 7 * isolates running on the same worker (either UI or background web worker). |
| 8 * | 8 * |
| 9 * This is code that is intended to 'escape' the isolate boundaries in order to | 9 * This is code that is intended to 'escape' the isolate boundaries in order to |
| 10 * implement the semantics of friendly isolates in JavaScript. Without this we | 10 * implement the semantics of friendly isolates in JavaScript. Without this we |
| 11 * would have been forced to implement more code (including the top-level event | 11 * would have been forced to implement more code (including the top-level event |
| 12 * loop) in JavaScript itself. | 12 * loop) in JavaScript itself. |
| 13 */ | 13 */ |
| 14 GlobalState get _globalState() native "return \$globalState;"; | 14 GlobalState get _globalState() native "return \$globalState;"; |
| 15 set _globalState(GlobalState val) native "\$globalState = val;"; | 15 set _globalState(GlobalState val) native "\$globalState = val;"; |
| 16 | 16 |
| 17 /** | 17 /** |
| 18 * Wrapper that takes the dart entry point and runs it within an isolate. The | 18 * Wrapper that takes the dart entry point and runs it within an isolate. The |
| 19 * frog compiler will inject a call of the form [: startAsIsolate(main); :] when | 19 * frog compiler will inject a call of the form [: startRootIsolate(main); :] |
| 20 * it determines that this wrapping is needed. For single-isolate applications | 20 * when it determines that this wrapping is needed. For single-isolate |
| 21 * (e.g. hello world), this call is not emited. | 21 * applications (e.g. hello world), this call is not emitted. |
| 22 */ | 22 */ |
| 23 void startAsIsolate(entry) { | 23 void startRootIsolate(entry) { |
| 24 _globalState = new GlobalState(); | 24 _globalState = new GlobalState(); |
| 25 | 25 |
| 26 // Don't start the main loop again, if we are in a worker. | 26 // Don't start the main loop again, if we are in a worker. |
| 27 if (_globalState.inWorker) return; | 27 if (_globalState.isWorker) return; |
| 28 final entryIsolate = new IsolateContext(); | 28 final rootContext = new IsolateContext(); |
| 29 _globalState.rootIsolate = entryIsolate; | 29 _globalState.rootContext = rootContext; |
| 30 _fillStatics(rootContext); | |
| 30 | 31 |
| 31 // BUG(5151491): Setting _thisISolate should not be necessary, but because | 32 // BUG(5151491): Setting currentContext should not be necessary, but |
| 32 // closures passed to the DOM as event handlers do not bind their isolate | 33 // because closures passed to the DOM as event handlers do not bind their |
| 33 // automatically we try to give them a reasonable context to live in by having | 34 // isolate automatically we try to give them a reasonable context to live in |
| 34 // a "default" isolate (the first one created). | 35 // by having a "default" isolate (the first one created). |
| 35 _globalState.currentIsolate = entryIsolate; | 36 _globalState.currentContext = rootContext; |
| 36 | 37 |
| 37 entryIsolate.eval(entry); | 38 rootContext.eval(entry); |
| 38 _globalState.topEventLoop.run(); | 39 _globalState.topEventLoop.run(); |
| 39 } | 40 } |
| 40 | 41 |
| 42 void _fillStatics(context) native @""" | |
| 43 $globals = context.isolateStatics; | |
| 44 $static_init(); | |
| 45 """; | |
| 46 | |
| 41 /** Global state associated with the current worker. See [_globalState]. */ | 47 /** Global state associated with the current worker. See [_globalState]. */ |
| 48 // TODO(sigmund): split in multiple classes: global, thread, main-worker states? | |
| 42 class GlobalState { | 49 class GlobalState { |
| 43 | 50 |
| 44 /** Next available isolate id. */ | 51 /** Next available isolate id. */ |
| 45 int nextIsolateId = 0; | 52 int nextIsolateId = 0; |
| 46 | 53 |
| 47 /** Worker id associated with this worker. */ | 54 /** Worker id associated with this worker. */ |
| 48 int currentWorkerId = 0; | 55 int currentWorkerId = 0; |
| 49 | 56 |
| 50 /** | 57 /** |
| 51 * Next available worker id. Only used by the main worker to assign a unique | 58 * Next available worker id. Only used by the main worker to assign a unique |
| 52 * id to each worker created by it. | 59 * id to each worker created by it. |
| 53 */ | 60 */ |
| 54 int nextWorkerId = 1; | 61 int nextWorkerId = 1; |
| 55 | 62 |
| 56 /** Context for the currently running [Isolate]. */ | 63 /** Context for the currently running [Isolate]. */ |
| 57 IsolateContext currentIsolate = null; | 64 IsolateContext currentContext = null; |
| 58 | 65 |
| 59 /** Context for the root [Isolate] that first run in this worker. */ | 66 /** Context for the root [Isolate] that first run in this worker. */ |
| 60 IsolateContext rootIsolate = null; | 67 IsolateContext rootContext = null; |
| 61 | 68 |
| 62 /** The top-level event loop. */ | 69 /** The top-level event loop. */ |
| 63 EventLoop topEventLoop; | 70 EventLoop topEventLoop; |
| 64 | 71 |
| 65 /** Whether this program is running in a background worker. */ | 72 /** Whether this program is running in a background worker. */ |
| 66 bool inWorker; | 73 bool isWorker; |
| 67 | 74 |
| 68 /** Whether this program is running in a UI worker. */ | 75 /** Whether this program is running in a UI worker. */ |
| 69 bool inWindow; | 76 bool inWindow; |
| 70 | 77 |
| 71 /** Whether we support spawning workers. */ | 78 /** Whether we support spawning workers. */ |
| 72 bool supportsWorkers; | 79 bool supportsWorkers; |
| 73 | 80 |
| 74 /** | 81 /** |
| 75 * Whether to use web workers when implementing isolates. Set to false for | 82 * Whether to use web workers when implementing isolates. Set to false for |
| 76 * debugging/testing. | 83 * debugging/testing. |
| 77 */ | 84 */ |
| 78 bool get useWorkers() => supportsWorkers; | 85 bool get useWorkers() => supportsWorkers; |
| 79 | 86 |
| 80 /** | 87 /** |
| 81 * Whether to use the web-worker JSON-based message serialization protocol, | 88 * Whether to use the web-worker JSON-based message serialization protocol. By |
| 82 * even if not using web workers. Set to true to always use the web-worker | 89 * default this is only used with web workers. For debugging, you can force |
| 83 * JSON-based message serialization protocol, e.g. for testing purposes. | 90 * using this protocol by changing this field value to [true]. |
| 84 */ | 91 */ |
| 85 bool get useWorkerSerializationProtocol() => useWorkers; | 92 bool get needSerialization() => useWorkers; |
| 86 | 93 |
| 87 /** | 94 /** |
| 88 * Registry of isolates. Isolates must be registered if, and only if, receive | 95 * Registry of isolates. Isolates must be registered if, and only if, receive |
| 89 * ports are alive. Normally no open receive-ports means that the isolate is | 96 * ports are alive. Normally no open receive-ports means that the isolate is |
| 90 * dead, but DOM callbacks could resurrect it. | 97 * dead, but DOM callbacks could resurrect it. |
| 91 */ | 98 */ |
| 92 Map<int, IsolateContext> isolates; | 99 Map<int, IsolateContext> isolates; |
| 93 | 100 |
| 94 /** Reference to the main worker. */ | 101 /** Reference to the main worker. */ |
| 95 MainWorker mainWorker; | 102 MainWorker mainWorker; |
| 96 | 103 |
| 97 /** Registry of active workers. Only used in the main worker. */ | 104 /** Registry of active workers. Only used in the main worker. */ |
| 98 Map<int, var> workers; | 105 Map<int, var> workers; |
| 99 | 106 |
| 100 GlobalState() { | 107 GlobalState() { |
| 101 topEventLoop = new EventLoop(); | 108 topEventLoop = new EventLoop(); |
| 102 isolates = {}; | 109 isolates = {}; |
| 103 workers = {}; | 110 workers = {}; |
| 104 mainWorker = new MainWorker(); | 111 mainWorker = new MainWorker(); |
| 105 _nativeInit(); | 112 _nativeInit(); |
| 106 } | 113 } |
| 107 | 114 |
| 108 void _nativeInit() native @""" | 115 void _nativeInit() native @""" |
| 109 this.inWorker = typeof ($globalThis['importScripts']) != 'undefined'; | 116 this.isWorker = typeof ($globalThis['importScripts']) != 'undefined'; |
| 110 this.inWindow = typeof(window) !== 'undefined'; | 117 this.inWindow = typeof(window) !== 'undefined'; |
| 111 this.supportsWorkers = this.inWorker || | 118 this.supportsWorkers = this.isWorker || |
| 112 ((typeof $globalThis['Worker']) != 'undefined'); | 119 ((typeof $globalThis['Worker']) != 'undefined'); |
| 113 | 120 |
| 114 // if workers are supported, treat this as a main worker: | 121 // if workers are supported, treat this as a main worker: |
| 115 if (this.supportsWorkers) { | 122 if (this.supportsWorkers) { |
| 116 $globalThis.onmessage = function(e) { | 123 $globalThis.onmessage = function(e) { |
| 117 IsolateNatives._processWorkerMessage(this.mainWorker, e); | 124 IsolateNatives._processWorkerMessage(this.mainWorker, e); |
| 118 }; | 125 }; |
| 119 } | 126 } |
| 120 """; | 127 """; |
| 121 | 128 |
| 122 /** | 129 /** |
| 123 * Close the worker running this code, called when there is nothing else to | 130 * Close the worker running this code, called when there is nothing else to |
| 124 * run. | 131 * run. |
| 125 */ | 132 */ |
| 126 void closeWorker() { | 133 void closeWorker() { |
| 127 if (inWorker) { | 134 if (isWorker) { |
| 128 if (!isolates.isEmpty()) return; | 135 if (!isolates.isEmpty()) return; |
| 129 mainWorker.postMessage( | 136 mainWorker.postMessage( |
| 130 _serializeMessage({'command': 'close'})); | 137 _serializeMessage({'command': 'close'})); |
| 131 } else if (isolates.containsKey(rootIsolate.id) && workers.isEmpty() && | 138 } else if (isolates.containsKey(rootContext.id) && workers.isEmpty() && |
| 132 !supportsWorkers && !inWindow) { | 139 !supportsWorkers && !inWindow) { |
| 133 // This should only trigger when running on the command-line. | 140 // This should only trigger when running on the command-line. |
| 134 // We don't want this check to execute in the browser where the isolate | 141 // We don't want this check to execute in the browser where the isolate |
| 135 // might still be alive due to DOM callbacks. | 142 // might still be alive due to DOM callbacks. |
| 136 throw new Exception("Program exited with open ReceivePorts."); | 143 throw new Exception("Program exited with open ReceivePorts."); |
| 137 } | 144 } |
| 138 } | 145 } |
| 139 } | 146 } |
| 140 | 147 |
| 141 _serializeMessage(message) { | 148 _serializeMessage(message) { |
| 142 if (_globalState.useWorkerSerializationProtocol) { | 149 if (_globalState.needSerialization) { |
| 143 return new Serializer().traverse(message); | 150 return new Serializer().traverse(message); |
| 144 } else { | 151 } else { |
| 145 return new Copier().traverse(message); | 152 return new Copier().traverse(message); |
| 146 } | 153 } |
| 147 } | 154 } |
| 148 | 155 |
| 149 _deserializeMessage(message) { | 156 _deserializeMessage(message) { |
| 150 if (_globalState.useWorkerSerializationProtocol) { | 157 if (_globalState.needSerialization) { |
| 151 return new Deserializer().deserialize(message); | 158 return new Deserializer().deserialize(message); |
| 152 } else { | 159 } else { |
| 153 // Nothing more to do. | 160 // Nothing more to do. |
| 154 return message; | 161 return message; |
| 155 } | 162 } |
| 156 } | 163 } |
| 157 | 164 |
| 158 /** Default worker. */ | 165 /** Default worker. */ |
| 159 class MainWorker { | 166 class MainWorker { |
| 160 int id = 0; | 167 int id = 0; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 171 | 178 |
| 172 /** Holds isolate globals (statics and top-level properties). */ | 179 /** Holds isolate globals (statics and top-level properties). */ |
| 173 var isolateStatics; // native object containing all globals of an isolate. | 180 var isolateStatics; // native object containing all globals of an isolate. |
| 174 | 181 |
| 175 IsolateContext() { | 182 IsolateContext() { |
| 176 id = _globalState.nextIsolateId++; | 183 id = _globalState.nextIsolateId++; |
| 177 ports = {}; | 184 ports = {}; |
| 178 initGlobals(); | 185 initGlobals(); |
| 179 } | 186 } |
| 180 | 187 |
| 181 // TODO(sigmund): actually do the initialization too. | 188 // these are filled lazily the first time the isolate starts running. |
| 182 void initGlobals() native "this.isolateStatics = {};"; | 189 void initGlobals() native 'this.isolateStatics = {};'; |
| 183 | 190 |
| 184 /** | 191 /** |
| 185 * Run [code] in the context of the isolate represented by [this]. Note this | 192 * Run [code] in the context of the isolate represented by [this]. Note this |
| 186 * is marked as native because it is called from JavaScript (see $wrap_call in | 193 * is marked as native because it is called from JavaScript (see $wrap_call in |
| 187 * corejs.dart). | 194 * corejs.dart). |
| 188 */ | 195 */ |
| 189 void eval(Function code) native { | 196 void eval(Function code) native { |
| 190 var old = _globalState.currentIsolate; | 197 var old = _globalState.currentContext; |
| 191 _globalState.currentIsolate = this; | 198 _globalState.currentContext = this; |
| 199 this._setGlobals(); | |
| 192 var result = null; | 200 var result = null; |
| 193 try { | 201 try { |
| 194 result = code(); | 202 result = code(); |
| 195 } finally { | 203 } finally { |
| 196 _globalState.currentIsolate = old; | 204 _globalState.currentContext = old; |
| 205 old._setGlobals(); | |
| 197 } | 206 } |
| 198 return result; | 207 return result; |
| 199 } | 208 } |
| 200 | 209 |
| 210 void _setGlobals() native @'$globals = this.isolateStatics;'; | |
| 211 | |
| 201 /** Lookup a port registered for this isolate. */ | 212 /** Lookup a port registered for this isolate. */ |
| 202 ReceivePort lookup(int id) => ports[id]; | 213 ReceivePort lookup(int id) => ports[id]; |
| 203 | 214 |
| 204 /** Register a port on this isolate. */ | 215 /** Register a port on this isolate. */ |
| 205 void register(int portId, ReceivePort port) { | 216 void register(int portId, ReceivePort port) { |
| 206 if (ports.containsKey(portId)) { | 217 if (ports.containsKey(portId)) { |
| 207 throw new Exception("Registry: ports must be registered only once."); | 218 throw new Exception("Registry: ports must be registered only once."); |
| 208 } | 219 } |
| 209 ports[portId] = port; | 220 ports[portId] = port; |
| 210 _globalState.isolates[id] = this; // indicate this isolate is active | 221 _globalState.isolates[id] = this; // indicate this isolate is active |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 239 final event = dequeue(); | 250 final event = dequeue(); |
| 240 if (event == null) { | 251 if (event == null) { |
| 241 _globalState.closeWorker(); | 252 _globalState.closeWorker(); |
| 242 return false; | 253 return false; |
| 243 } | 254 } |
| 244 event.process(); | 255 event.process(); |
| 245 return true; | 256 return true; |
| 246 } | 257 } |
| 247 | 258 |
| 248 /** Function equivalent to [:window.setTimeout:] when available, or null. */ | 259 /** Function equivalent to [:window.setTimeout:] when available, or null. */ |
| 249 static Function _platformDefer() native """ | 260 static Function _wrapSetTimeout() native """ |
| 250 return typeof window != 'undefined' ? | 261 return typeof window != 'undefined' ? |
| 251 function(a, b) { window.setTimeout(a, b); } : undefined; | 262 function(a, b) { window.setTimeout(a, b); } : undefined; |
| 252 """; | 263 """; |
| 253 | 264 |
| 254 /** | 265 /** |
| 255 * Runs multiple iterations of the run-loop. If possible, each iteration is | 266 * Runs multiple iterations of the run-loop. If possible, each iteration is |
| 256 * run asynchronously. | 267 * run asynchronously. |
| 257 */ | 268 */ |
| 258 void _runHelper() { | 269 void _runHelper() { |
| 259 final setTimeout = _platformDefer(); | 270 final setTimeout = _wrapSetTimeout(); |
| 260 if (setTimeout != null) { | 271 if (setTimeout != null) { |
| 261 // Run each iteration from the browser's top event loop. | 272 // Run each iteration from the browser's top event loop. |
| 262 void next() { | 273 void next() { |
| 263 if (!runIteration()) return; | 274 if (!runIteration()) return; |
| 264 setTimeout(next, 0); | 275 setTimeout(next, 0); |
| 265 } | 276 } |
| 266 next(); | 277 next(); |
| 267 } else { | 278 } else { |
| 268 // Run synchronously until no more iterations are available. | 279 // Run synchronously until no more iterations are available. |
| 269 while (runIteration()) {} | 280 while (runIteration()) {} |
| 270 } | 281 } |
| 271 } | 282 } |
| 272 | 283 |
| 273 /** | 284 /** |
| 274 * Call [_runHelper] but ensure that worker exceptions are propragated. Note | 285 * Call [_runHelper] but ensure that worker exceptions are propragated. Note |
| 275 * this is marked as native because it is called from JavaScript (see | 286 * this is marked as native because it is called from JavaScript (see |
| 276 * $wrap_call in corejs.dart). | 287 * $wrap_call in corejs.dart). |
| 277 */ | 288 */ |
| 278 void run() native { | 289 void run() native { |
| 279 if (!_globalState.inWorker) { | 290 if (!_globalState.isWorker) { |
| 280 _runHelper(); | 291 _runHelper(); |
| 281 } else { | 292 } else { |
| 282 try { | 293 try { |
| 283 _runHelper(); | 294 _runHelper(); |
| 284 } catch(e) { | 295 } catch(e) { |
| 285 // TODO(floitsch): try to send stack-trace to the other side. | 296 // TODO(floitsch): try to send stack-trace to the other side. |
| 286 _globalState.mainWorker.postMessage(_serializeMessage( | 297 _globalState.mainWorker.postMessage(_serializeMessage( |
| 287 {'command': 'error', 'msg': "" + e })); | 298 {'command': 'error', 'msg': "" + e })); |
| 288 } | 299 } |
| 289 } | 300 } |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 356 | 367 |
| 357 factory ReceivePort.singleShot() { | 368 factory ReceivePort.singleShot() { |
| 358 return new ReceivePortSingleShotImpl(); | 369 return new ReceivePortSingleShotImpl(); |
| 359 } | 370 } |
| 360 } | 371 } |
| 361 | 372 |
| 362 /** Implementation of a multi-use [ReceivePort] on top of JavaScript. */ | 373 /** Implementation of a multi-use [ReceivePort] on top of JavaScript. */ |
| 363 class ReceivePortImpl implements ReceivePort { | 374 class ReceivePortImpl implements ReceivePort { |
| 364 ReceivePortImpl() | 375 ReceivePortImpl() |
| 365 : _id = _nextFreeId++ { | 376 : _id = _nextFreeId++ { |
| 366 _globalState.currentIsolate.register(_id, this); | 377 _globalState.currentContext.register(_id, this); |
| 367 } | 378 } |
| 368 | 379 |
| 369 void receive(void onMessage(var message, SendPort replyTo)) { | 380 void receive(void onMessage(var message, SendPort replyTo)) { |
| 370 _callback = onMessage; | 381 _callback = onMessage; |
| 371 } | 382 } |
| 372 | 383 |
| 373 void close() { | 384 void close() { |
| 374 _callback = null; | 385 _callback = null; |
| 375 _globalState.currentIsolate.unregister(_id); | 386 _globalState.currentContext.unregister(_id); |
| 376 } | 387 } |
| 377 | 388 |
| 378 /** | 389 /** |
| 379 * Returns a fresh [SendPort]. The implementation is not allowed to cache | 390 * Returns a fresh [SendPort]. The implementation is not allowed to cache |
| 380 * existing ports. | 391 * existing ports. |
| 381 */ | 392 */ |
| 382 SendPort toSendPort() { | 393 SendPort toSendPort() { |
| 383 return new SendPortImpl( | 394 return new SendPortImpl( |
| 384 _globalState.currentWorkerId, _globalState.currentIsolate.id, _id); | 395 _globalState.currentWorkerId, _globalState.currentContext.id, _id); |
| 385 } | 396 } |
| 386 | 397 |
| 387 int _id; | 398 int _id; |
| 388 Function _callback; | 399 Function _callback; |
| 389 | 400 |
| 390 static int _nextFreeId = 1; | 401 static int _nextFreeId = 1; |
| 391 } | 402 } |
| 392 | 403 |
| 393 /** Implementation of a single-shot [ReceivePort]. */ | 404 /** Implementation of a single-shot [ReceivePort]. */ |
| 394 class ReceivePortSingleShotImpl implements ReceivePort { | 405 class ReceivePortSingleShotImpl implements ReceivePort { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 430 _startWorker(isolate, port.toSendPort()); | 441 _startWorker(isolate, port.toSendPort()); |
| 431 } else { | 442 } else { |
| 432 _startNonWorker(isolate, port.toSendPort()); | 443 _startNonWorker(isolate, port.toSendPort()); |
| 433 } | 444 } |
| 434 | 445 |
| 435 return completer.future; | 446 return completer.future; |
| 436 } | 447 } |
| 437 | 448 |
| 438 static SendPort _startWorker(Isolate runnable, SendPort replyPort) { | 449 static SendPort _startWorker(Isolate runnable, SendPort replyPort) { |
| 439 var factoryName = _getJSConstructorName(runnable); | 450 var factoryName = _getJSConstructorName(runnable); |
| 440 if (_globalState.inWorker) { | 451 if (_globalState.isWorker) { |
| 441 _globalState.mainWorker.postMessage(_serializeMessage({ | 452 _globalState.mainWorker.postMessage(_serializeMessage({ |
| 442 'command': 'spawn-worker', | 453 'command': 'spawn-worker', |
| 443 'factoryName': factoryName, | 454 'factoryName': factoryName, |
| 444 'replyPort': replyPort})); | 455 'replyPort': replyPort})); |
| 445 } else { | 456 } else { |
| 446 _spawnWorker(factoryName, _serializeMessage(replyPort)); | 457 _spawnWorker(factoryName, _serializeMessage(replyPort)); |
| 447 } | 458 } |
| 448 } | 459 } |
| 449 | 460 |
| 450 | 461 |
| 451 /** | 462 /** |
| 452 * The src url for the script tag that loaded this code. Used to create | 463 * The src url for the script tag that loaded this code. Used to create |
| 453 * JavaScript workers. | 464 * JavaScript workers. |
| 454 */ | 465 */ |
| 455 static String get _thisScript() => | 466 static String get _thisScript() => |
| 456 _thisScriptCache != null ? _thisScriptCache : _computeThisScript(); | 467 _thisScriptCache != null ? _thisScriptCache : _computeThisScript(); |
| 457 | 468 |
| 458 static String _thisScriptCache; | 469 static String _thisScriptCache; |
| 459 | 470 |
| 460 // TODO(sigmund): fix - this code should be run synchronously when loading the | 471 // TODO(sigmund): fix - this code should be run synchronously when loading the |
| 461 // script. Running lazily on DOMContentLoaded will yield incorrect results. | 472 // script. Running lazily on DOMContentLoaded will yield incorrect results. |
| 462 static String _computeThisScript() native @""" | 473 static String _computeThisScript() native @""" |
| 463 if (!$globalState.supportsWorkers || $globalState.inWorker) return null; | 474 if (!$globalState.supportsWorkers || $globalState.isWorker) return null; |
| 464 | 475 |
| 465 // TODO(5334778): Find a cross-platform non-brittle way of getting the | 476 // TODO(5334778): Find a cross-platform non-brittle way of getting the |
| 466 // currently running script. | 477 // currently running script. |
| 467 var scripts = document.getElementsByTagName('script'); | 478 var scripts = document.getElementsByTagName('script'); |
| 468 // The scripts variable only contains the scripts that have already been | 479 // The scripts variable only contains the scripts that have already been |
| 469 // executed. The last one is the currently running script. | 480 // executed. The last one is the currently running script. |
| 470 var script = scripts[scripts.length - 1]; | 481 var script = scripts[scripts.length - 1]; |
| 471 var src = script.src; | 482 var src = script && script.src; |
|
Siggi Cherem (dart-lang)
2011/11/18 01:28:10
this was unrelated to this CL, but something that
| |
| 472 if (!src) { | 483 if (!src) { |
| 473 // TODO() | 484 // TODO() |
| 474 src = "FIXME:5407062" + "_" + Math.random().toString(); | 485 src = "FIXME:5407062" + "_" + Math.random().toString(); |
| 475 script.src = src; | 486 if (script) script.src = src; |
| 476 } | 487 } |
| 477 IsolateNatives._thisScriptCache = src; | 488 IsolateNatives._thisScriptCache = src; |
| 478 return src; | 489 return src; |
| 479 """; | 490 """; |
| 480 | 491 |
| 481 /** Starts a new worker with the given URL. */ | 492 /** Starts a new worker with the given URL. */ |
| 482 static void _newWorker(url) native "return new Worker(url)"; | 493 static void _newWorker(url) native "return new Worker(url)"; |
| 483 | 494 |
| 484 /** | 495 /** |
| 485 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor | 496 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 532 case 'close': | 543 case 'close': |
| 533 _log("Closing Worker"); | 544 _log("Closing Worker"); |
| 534 _globalState.workers.remove(sender.id); | 545 _globalState.workers.remove(sender.id); |
| 535 sender.terminate(); | 546 sender.terminate(); |
| 536 _globalState.topEventLoop.run(); | 547 _globalState.topEventLoop.run(); |
| 537 break; | 548 break; |
| 538 case 'log': | 549 case 'log': |
| 539 _log(msg['msg']); | 550 _log(msg['msg']); |
| 540 break; | 551 break; |
| 541 case 'print': | 552 case 'print': |
| 542 if (_globalState.inWorker) { | 553 if (_globalState.isWorker) { |
| 543 _globalState.mainWorker.postMessage( | 554 _globalState.mainWorker.postMessage( |
| 544 _serializeMessage({'command': 'print', 'msg': msg})); | 555 _serializeMessage({'command': 'print', 'msg': msg})); |
| 545 } else { | 556 } else { |
| 546 print(msg['msg']); | 557 print(msg['msg']); |
| 547 } | 558 } |
| 548 break; | 559 break; |
| 549 case 'error': | 560 case 'error': |
| 550 throw msg['msg']; | 561 throw msg['msg']; |
| 551 break; | 562 break; |
| 552 } | 563 } |
| 553 } | 564 } |
| 554 | 565 |
| 555 /** Log a message, forwarding to the main worker if appropriate. */ | 566 /** Log a message, forwarding to the main worker if appropriate. */ |
| 556 static _log(msg) { | 567 static _log(msg) { |
| 557 if (_globalState.inWorker) { | 568 if (_globalState.isWorker) { |
| 558 _globalState.mainWorker.postMessage( | 569 _globalState.mainWorker.postMessage( |
| 559 _serializeMessage({'command': 'log', 'msg': msg })); | 570 _serializeMessage({'command': 'log', 'msg': msg })); |
| 560 } else { | 571 } else { |
| 561 try { | 572 try { |
| 562 _consoleLog(msg); | 573 _consoleLog(msg); |
| 563 } catch(e, trace) { | 574 } catch(e, trace) { |
| 564 throw new Exception(trace); | 575 throw new Exception(trace); |
| 565 } | 576 } |
| 566 } | 577 } |
| 567 } | 578 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 601 // isolate. This way, we do not get cross-isolate references | 612 // isolate. This way, we do not get cross-isolate references |
| 602 // through the runnable. | 613 // through the runnable. |
| 603 final ctor = _getJSConstructor(runnable); | 614 final ctor = _getJSConstructor(runnable); |
| 604 _globalState.topEventLoop.enqueue(spawned, function() { | 615 _globalState.topEventLoop.enqueue(spawned, function() { |
| 605 _startIsolate(_allocate(ctor), replyTo); | 616 _startIsolate(_allocate(ctor), replyTo); |
| 606 }, 'nonworker start'); | 617 }, 'nonworker start'); |
| 607 } | 618 } |
| 608 | 619 |
| 609 /** Given a ready-to-start runnable, start running it. */ | 620 /** Given a ready-to-start runnable, start running it. */ |
| 610 static void _startIsolate(Isolate isolate, SendPort replyTo) { | 621 static void _startIsolate(Isolate isolate, SendPort replyTo) { |
| 622 _fillStatics(_globalState.currentContext); | |
| 611 ReceivePort port = new ReceivePort(); | 623 ReceivePort port = new ReceivePort(); |
| 612 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); | 624 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); |
| 613 isolate._run(port); | 625 isolate._run(port); |
| 614 } | 626 } |
| 615 | 627 |
| 616 static void _sendMessage(int workerId, int isolateId, int receivePortId, | 628 static void _sendMessage(int workerId, int isolateId, int receivePortId, |
| 617 message, replyTo) { | 629 message, replyTo) { |
| 618 // Both the message and the replyTo are already serialized. | 630 // Both the message and the replyTo are already serialized. |
| 619 if (workerId == _globalState.currentWorkerId) { | 631 if (workerId == _globalState.currentWorkerId) { |
| 620 var isolate = _globalState.isolates[isolateId]; | 632 var isolate = _globalState.isolates[isolateId]; |
| 621 if (isolate == null) return; // Isolate has been closed. | 633 if (isolate == null) return; // Isolate has been closed. |
| 622 var receivePort = isolate.lookup(receivePortId); | 634 var receivePort = isolate.lookup(receivePortId); |
| 623 if (receivePort == null) return; // ReceivePort has been closed. | 635 if (receivePort == null) return; // ReceivePort has been closed. |
| 624 _globalState.topEventLoop.enqueue(isolate, () { | 636 _globalState.topEventLoop.enqueue(isolate, () { |
| 625 if (receivePort._callback != null) { | 637 if (receivePort._callback != null) { |
| 626 receivePort._callback( | 638 receivePort._callback( |
| 627 _deserializeMessage(message), _deserializeMessage(replyTo)); | 639 _deserializeMessage(message), _deserializeMessage(replyTo)); |
| 628 } | 640 } |
| 629 }, 'receive ' + message); | 641 }, 'receive ' + message); |
| 630 } else { | 642 } else { |
| 631 var worker; | 643 var worker; |
| 632 // communication between workers go through the main worker | 644 // communication between workers go through the main worker |
| 633 if (_globalState.inWorker) { | 645 if (_globalState.isWorker) { |
| 634 worker = _globalState.mainWorker; | 646 worker = _globalState.mainWorker; |
| 635 } else { | 647 } else { |
| 636 // TODO(sigmund): make sure this works | 648 // TODO(sigmund): make sure this works |
| 637 worker = _globalState.workers[workerId]; | 649 worker = _globalState.workers[workerId]; |
| 638 } | 650 } |
| 639 worker.postMessage(_serializeMessage({ | 651 worker.postMessage(_serializeMessage({ |
| 640 'command': 'message', | 652 'command': 'message', |
| 641 'workerId': workerId, | 653 'workerId': workerId, |
| 642 'isolateId': isolateId, | 654 'isolateId': isolateId, |
| 643 'portId': receivePortId, | 655 'portId': receivePortId, |
| 644 'msg': message, | 656 'msg': message, |
| 645 'replyTo': replyTo })); | 657 'replyTo': replyTo })); |
| 646 } | 658 } |
| 647 } | 659 } |
| 648 } | 660 } |
| OLD | NEW |