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

Side by Side Diff: lib/isolate/frog/isolateimpl.dart

Issue 9562048: isolate in frog: hiding internal implementation classes, couple minor fixes. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 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 | Annotate | Revision Log
« no previous file with comments | « lib/isolate/frog/compiler_hooks.dart ('k') | lib/isolate/frog/messages.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 /** 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 isolates in JavaScript. Without this we would have 10 * implement the semantics of isolates in JavaScript. Without this we would have
11 * been forced to implement more code (including the top-level event loop) in 11 * been forced to implement more code (including the top-level event loop) in
12 * JavaScript itself. 12 * 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 void fillStatics(context) native @""" 17 void _fillStatics(context) native @"""
18 $globals = context.isolateStatics; 18 $globals = context.isolateStatics;
19 $static_init(); 19 $static_init();
20 """; 20 """;
21 21
22 /** Global state associated with the current worker. See [globalState]. */ 22 /** Global state associated with the current worker. See [globalState]. */
23 // TODO(sigmund): split in multiple classes: global, thread, main-worker states? 23 // TODO(sigmund): split in multiple classes: global, thread, main-worker states?
24 class GlobalState { 24 class _GlobalState {
25 25
26 /** Next available isolate id. */ 26 /** Next available isolate id. */
27 int nextIsolateId = 0; 27 int nextIsolateId = 0;
28 28
29 /** Worker id associated with this worker. */ 29 /** Worker id associated with this worker. */
30 int currentWorkerId = 0; 30 int currentWorkerId = 0;
31 31
32 /** 32 /**
33 * Next available worker id. Only used by the main worker to assign a unique 33 * Next available worker id. Only used by the main worker to assign a unique
34 * id to each worker created by it. 34 * id to each worker created by it.
35 */ 35 */
36 int nextWorkerId = 1; 36 int nextWorkerId = 1;
37 37
38 /** Context for the currently running [Isolate]. */ 38 /** Context for the currently running [Isolate]. */
39 IsolateContext currentContext = null; 39 _IsolateContext currentContext = null;
40 40
41 /** Context for the root [Isolate] that first run in this worker. */ 41 /** Context for the root [Isolate] that first run in this worker. */
42 IsolateContext rootContext = null; 42 _IsolateContext rootContext = null;
43 43
44 /** The top-level event loop. */ 44 /** The top-level event loop. */
45 EventLoop topEventLoop; 45 _EventLoop topEventLoop;
46 46
47 /** Whether this program is running in a background worker. */ 47 /** Whether this program is running in a background worker. */
48 bool isWorker; 48 bool isWorker;
49 49
50 /** Whether this program is running in a UI worker. */ 50 /** Whether this program is running in a UI worker. */
51 bool inWindow; 51 bool inWindow;
52 52
53 /** Whether we support spawning workers. */ 53 /** Whether we support spawning workers. */
54 bool supportsWorkers; 54 bool supportsWorkers;
55 55
56 /** 56 /**
57 * Whether to use web workers when implementing isolates. Set to false for 57 * Whether to use web workers when implementing isolates. Set to false for
58 * debugging/testing. 58 * debugging/testing.
59 */ 59 */
60 bool get useWorkers() => supportsWorkers; 60 bool get useWorkers() => supportsWorkers;
61 61
62 /** 62 /**
63 * Whether to use the web-worker JSON-based message serialization protocol. By 63 * Whether to use the web-worker JSON-based message serialization protocol. By
64 * default this is only used with web workers. For debugging, you can force 64 * default this is only used with web workers. For debugging, you can force
65 * using this protocol by changing this field value to [true]. 65 * using this protocol by changing this field value to [true].
66 */ 66 */
67 bool get needSerialization() => useWorkers; 67 bool get needSerialization() => useWorkers;
68 68
69 /** 69 /**
70 * Registry of isolates. Isolates must be registered if, and only if, receive 70 * Registry of isolates. Isolates must be registered if, and only if, receive
71 * ports are alive. Normally no open receive-ports means that the isolate is 71 * ports are alive. Normally no open receive-ports means that the isolate is
72 * dead, but DOM callbacks could resurrect it. 72 * dead, but DOM callbacks could resurrect it.
73 */ 73 */
74 Map<int, IsolateContext> isolates; 74 Map<int, _IsolateContext> isolates;
75 75
76 /** Reference to the main worker. */ 76 /** Reference to the main worker. */
77 MainWorker mainWorker; 77 _MainWorker mainWorker;
78 78
79 /** Registry of active workers. Only used in the main worker. */ 79 /** Registry of active workers. Only used in the main worker. */
80 Map<int, Dynamic> workers; 80 Map<int, Dynamic> workers;
81 81
82 GlobalState() { 82 _GlobalState() {
83 topEventLoop = new EventLoop(); 83 topEventLoop = new _EventLoop();
84 isolates = {}; 84 isolates = {};
85 workers = {}; 85 workers = {};
86 mainWorker = new MainWorker(); 86 mainWorker = new _MainWorker();
87 _nativeInit(); 87 _nativeInit();
88 } 88 }
89 89
90 void _nativeInit() native @""" 90 void _nativeInit() native @"""
91 this.isWorker = typeof ($globalThis['importScripts']) != 'undefined'; 91 this.isWorker = typeof ($globalThis['importScripts']) != 'undefined';
92 this.inWindow = typeof(window) !== 'undefined'; 92 this.inWindow = typeof(window) !== 'undefined';
93 this.supportsWorkers = this.isWorker || 93 this.supportsWorkers = this.isWorker ||
94 ((typeof $globalThis['Worker']) != 'undefined'); 94 ((typeof $globalThis['Worker']) != 'undefined');
95 95 if (this.isWorker) {
96 // if workers are supported, treat this as a main worker: 96 $globalThis.onmessage = function (e) {
97 if (this.supportsWorkers) {
98 $globalThis.onmessage = function(e) {
99 _IsolateNatives._processWorkerMessage(this.mainWorker, e); 97 _IsolateNatives._processWorkerMessage(this.mainWorker, e);
100 }; 98 };
101 } 99 }
102 """ { 100 """ {
103 // Declare that the native code has a dependency on this fn. 101 // Declare that the native code has a dependency on this fn.
104 _IsolateNatives._processWorkerMessage(null, null); 102 _IsolateNatives._processWorkerMessage(null, null);
105 } 103 }
106 104
107 /** 105 /**
108 * Close the worker running this code, called when there is nothing else to 106 * Close the worker running this code, called when there is nothing else to
109 * run. 107 * run.
110 */ 108 */
111 void closeWorker() { 109 void closeWorker() {
112 if (isWorker) { 110 if (isWorker) {
113 if (!isolates.isEmpty()) return; 111 if (!isolates.isEmpty()) return;
114 mainWorker.postMessage( 112 mainWorker.postMessage(
115 _serializeMessage({'command': 'close'})); 113 _serializeMessage({'command': 'close'}));
116 } else if (isolates.containsKey(rootContext.id) && workers.isEmpty() && 114 } else if (isolates.containsKey(rootContext.id) && workers.isEmpty() &&
117 !supportsWorkers && !inWindow) { 115 !supportsWorkers && !inWindow) {
118 // This should only trigger when running on the command-line. 116 // This should only trigger when running on the command-line.
119 // We don't want this check to execute in the browser where the isolate 117 // We don't want this check to execute in the browser where the isolate
120 // might still be alive due to DOM callbacks. 118 // might still be alive due to DOM callbacks.
121 throw new Exception("Program exited with open ReceivePorts."); 119 throw new Exception("Program exited with open ReceivePorts.");
122 } 120 }
123 } 121 }
124 } 122 }
125 123
126 /** Context information tracked for each isolate. */ 124 /** Context information tracked for each isolate. */
127 class IsolateContext { 125 class _IsolateContext {
128 /** Current isolate id. */ 126 /** Current isolate id. */
129 int id; 127 int id;
130 128
131 /** Registry of receive ports currently active on this isolate. */ 129 /** Registry of receive ports currently active on this isolate. */
132 Map<int, ReceivePort> ports; 130 Map<int, ReceivePort> ports;
133 131
134 /** Holds isolate globals (statics and top-level properties). */ 132 /** Holds isolate globals (statics and top-level properties). */
135 var isolateStatics; // native object containing all globals of an isolate. 133 var isolateStatics; // native object containing all globals of an isolate.
136 134
137 IsolateContext() { 135 _IsolateContext() {
138 id = globalState.nextIsolateId++; 136 id = _globalState.nextIsolateId++;
139 ports = {}; 137 ports = {};
140 initGlobals(); 138 initGlobals();
141 } 139 }
142 140
143 // these are filled lazily the first time the isolate starts running. 141 // these are filled lazily the first time the isolate starts running.
144 void initGlobals() native 'this.isolateStatics = {};'; 142 void initGlobals() native 'this.isolateStatics = {};';
145 143
146 /** 144 /**
147 * Run [code] in the context of the isolate represented by [this]. Note this 145 * Run [code] in the context of the isolate represented by [this]. Note this
148 * is called from JavaScript (see $wrap_call in corejs.dart). 146 * is called from JavaScript (see $wrap_call in corejs.dart).
149 */ 147 */
150 void eval(Function code) { 148 void eval(Function code) {
151 var old = globalState.currentContext; 149 var old = _globalState.currentContext;
152 globalState.currentContext = this; 150 _globalState.currentContext = this;
153 this._setGlobals(); 151 this._setGlobals();
154 var result = null; 152 var result = null;
155 try { 153 try {
156 result = code(); 154 result = code();
157 } finally { 155 } finally {
158 globalState.currentContext = old; 156 _globalState.currentContext = old;
159 if (old != null) old._setGlobals(); 157 if (old != null) old._setGlobals();
160 } 158 }
161 return result; 159 return result;
162 } 160 }
163 161
164 void _setGlobals() native @'$globals = this.isolateStatics;'; 162 void _setGlobals() native @'$globals = this.isolateStatics;';
165 163
166 /** Lookup a port registered for this isolate. */ 164 /** Lookup a port registered for this isolate. */
167 ReceivePort lookup(int id) => ports[id]; 165 ReceivePort lookup(int id) => ports[id];
168 166
169 /** Register a port on this isolate. */ 167 /** Register a port on this isolate. */
170 void register(int portId, ReceivePort port) { 168 void register(int portId, ReceivePort port) {
171 if (ports.containsKey(portId)) { 169 if (ports.containsKey(portId)) {
172 throw new Exception("Registry: ports must be registered only once."); 170 throw new Exception("Registry: ports must be registered only once.");
173 } 171 }
174 ports[portId] = port; 172 ports[portId] = port;
175 globalState.isolates[id] = this; // indicate this isolate is active 173 _globalState.isolates[id] = this; // indicate this isolate is active
176 } 174 }
177 175
178 /** Unregister a port on this isolate. */ 176 /** Unregister a port on this isolate. */
179 void unregister(int portId) { 177 void unregister(int portId) {
180 ports.remove(portId); 178 ports.remove(portId);
181 if (ports.isEmpty()) { 179 if (ports.isEmpty()) {
182 globalState.isolates.remove(id); // indicate this isolate is not active 180 _globalState.isolates.remove(id); // indicate this isolate is not active
183 } 181 }
184 } 182 }
185 } 183 }
186 184
187 185
188 /** Represent the event loop on a javascript thread (DOM or worker). */ 186 /** Represent the event loop on a javascript thread (DOM or worker). */
189 class EventLoop { 187 class _EventLoop {
190 Queue<IsolateEvent> events; 188 Queue<_IsolateEvent> events;
191 189
192 EventLoop() : events = new Queue<IsolateEvent>(); 190 _EventLoop() : events = new Queue<_IsolateEvent>();
193 191
194 void enqueue(isolate, fn, msg) { 192 void enqueue(isolate, fn, msg) {
195 events.addLast(new IsolateEvent(isolate, fn, msg)); 193 events.addLast(new _IsolateEvent(isolate, fn, msg));
196 } 194 }
197 195
198 IsolateEvent dequeue() { 196 _IsolateEvent dequeue() {
199 if (events.isEmpty()) return null; 197 if (events.isEmpty()) return null;
200 return events.removeFirst(); 198 return events.removeFirst();
201 } 199 }
202 200
203 /** Process a single event, if any. */ 201 /** Process a single event, if any. */
204 bool runIteration() { 202 bool runIteration() {
205 final event = dequeue(); 203 final event = dequeue();
206 if (event == null) { 204 if (event == null) {
207 globalState.closeWorker(); 205 _globalState.closeWorker();
208 return false; 206 return false;
209 } 207 }
210 event.process(); 208 event.process();
211 return true; 209 return true;
212 } 210 }
213 211
214 /** Function equivalent to [:window.setTimeout:] when available, or null. */ 212 /** Function equivalent to [:window.setTimeout:] when available, or null. */
215 static Function _wrapSetTimeout() native """ 213 static Function _wrapSetTimeout() native """
216 return typeof window != 'undefined' ? 214 return typeof window != 'undefined' ?
217 function(a, b) { window.setTimeout(a, b); } : undefined; 215 function(a, b) { window.setTimeout(a, b); } : undefined;
(...skipping 16 matching lines...) Expand all
234 // Run synchronously until no more iterations are available. 232 // Run synchronously until no more iterations are available.
235 while (runIteration()) {} 233 while (runIteration()) {}
236 } 234 }
237 } 235 }
238 236
239 /** 237 /**
240 * Call [_runHelper] but ensure that worker exceptions are propragated. Note 238 * Call [_runHelper] but ensure that worker exceptions are propragated. Note
241 * this is called from JavaScript (see $wrap_call in corejs.dart). 239 * this is called from JavaScript (see $wrap_call in corejs.dart).
242 */ 240 */
243 void run() { 241 void run() {
244 if (!globalState.isWorker) { 242 if (!_globalState.isWorker) {
245 _runHelper(); 243 _runHelper();
246 } else { 244 } else {
247 try { 245 try {
248 _runHelper(); 246 _runHelper();
249 } catch(var e, var trace) { 247 } catch(var e, var trace) {
250 globalState.mainWorker.postMessage(_serializeMessage( 248 _globalState.mainWorker.postMessage(_serializeMessage(
251 {'command': 'error', 'msg': '$e\n$trace' })); 249 {'command': 'error', 'msg': '$e\n$trace' }));
252 } 250 }
253 } 251 }
254 } 252 }
255 } 253 }
256 254
257 /** An event in the top-level event queue. */ 255 /** An event in the top-level event queue. */
258 class IsolateEvent { 256 class _IsolateEvent {
259 IsolateContext isolate; 257 _IsolateContext isolate;
260 Function fn; 258 Function fn;
261 String message; 259 String message;
262 260
263 IsolateEvent(this.isolate, this.fn, this.message); 261 _IsolateEvent(this.isolate, this.fn, this.message);
264 262
265 void process() { 263 void process() {
266 isolate.eval(fn); 264 isolate.eval(fn);
267 } 265 }
268 } 266 }
269 267
270 268
271 /** Default worker. */ 269 /** Default worker. */
272 class MainWorker { 270 class _MainWorker {
273 int id = 0; 271 int id = 0;
274 void postMessage(msg) native "return \$globalThis.postMessage(msg);"; 272 void postMessage(msg) native @"$globalThis.postMessage(msg);";
275 void set onmessage(f) native "\$globalThis.onmessage = f;";
276 void terminate() {} 273 void terminate() {}
277 } 274 }
278 275
279 /** 276 /**
280 * A web worker. This type is also defined in 'dart:dom', but we define it here 277 * A web worker. This type is also defined in 'dart:dom', but we define it here
281 * to avoid introducing a dependency from corelib to dom. This definition uses a 278 * to avoid introducing a dependency from corelib to dom. This definition uses a
282 * 'hidden' type (* prefix on the native name) to enforce that the type is 279 * 'hidden' type (* prefix on the native name) to enforce that the type is
283 * defined dynamically only when web workers are actually available. 280 * defined dynamically only when web workers are actually available.
284 */ 281 */
285 class _Worker native "*Worker" { 282 class _Worker native "*Worker" {
(...skipping 11 matching lines...) Expand all
297 static Future<SendPort> spawn(Isolate isolate, bool isLight) { 294 static Future<SendPort> spawn(Isolate isolate, bool isLight) {
298 Completer<SendPort> completer = new Completer<SendPort>(); 295 Completer<SendPort> completer = new Completer<SendPort>();
299 ReceivePort port = new ReceivePort.singleShot(); 296 ReceivePort port = new ReceivePort.singleShot();
300 port.receive((msg, SendPort replyPort) { 297 port.receive((msg, SendPort replyPort) {
301 assert(msg == _SPAWNED_SIGNAL); 298 assert(msg == _SPAWNED_SIGNAL);
302 completer.complete(replyPort); 299 completer.complete(replyPort);
303 }); 300 });
304 301
305 // TODO(floitsch): throw exception if isolate's class doesn't have a 302 // TODO(floitsch): throw exception if isolate's class doesn't have a
306 // default constructor. 303 // default constructor.
307 if (globalState.useWorkers && !isLight) { 304 if (_globalState.useWorkers && !isLight) {
308 _startWorker(isolate, port.toSendPort()); 305 _startWorker(isolate, port.toSendPort());
309 } else { 306 } else {
310 _startNonWorker(isolate, port.toSendPort()); 307 _startNonWorker(isolate, port.toSendPort());
311 } 308 }
312 309
313 return completer.future; 310 return completer.future;
314 } 311 }
315 312
316 static SendPort _startWorker(Isolate runnable, SendPort replyPort) { 313 static SendPort _startWorker(Isolate runnable, SendPort replyPort) {
317 var factoryName = _getJSConstructorName(runnable); 314 var factoryName = _getJSConstructorName(runnable);
318 if (globalState.isWorker) { 315 if (_globalState.isWorker) {
319 globalState.mainWorker.postMessage(_serializeMessage({ 316 _globalState.mainWorker.postMessage(_serializeMessage({
320 'command': 'spawn-worker', 317 'command': 'spawn-worker',
321 'factoryName': factoryName, 318 'factoryName': factoryName,
322 'replyPort': _serializeMessage(replyPort)})); 319 'replyPort': _serializeMessage(replyPort)}));
323 } else { 320 } else {
324 _spawnWorker(factoryName, _serializeMessage(replyPort)); 321 _spawnWorker(factoryName, _serializeMessage(replyPort));
325 } 322 }
326 } 323 }
327 324
328 /** 325 /**
329 * The src url for the script tag that loaded this code. Used to create 326 * The src url for the script tag that loaded this code. Used to create
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 /** Starts a new worker with the given URL. */ 358 /** Starts a new worker with the given URL. */
362 static _Worker _newWorker(url) native "return new Worker(url);"; 359 static _Worker _newWorker(url) native "return new Worker(url);";
363 360
364 /** 361 /**
365 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor 362 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor
366 * name for the isolate entry point class. 363 * name for the isolate entry point class.
367 */ 364 */
368 static void _spawnWorker(factoryName, serializedReplyPort) { 365 static void _spawnWorker(factoryName, serializedReplyPort) {
369 final worker = _newWorker(_thisScript); 366 final worker = _newWorker(_thisScript);
370 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; 367 worker.onmessage = (e) { _processWorkerMessage(worker, e); };
371 var workerId = globalState.nextWorkerId++; 368 var workerId = _globalState.nextWorkerId++;
372 // We also store the id on the worker itself so that we can unregister it. 369 // We also store the id on the worker itself so that we can unregister it.
373 worker.id = workerId; 370 worker.id = workerId;
374 globalState.workers[workerId] = worker; 371 _globalState.workers[workerId] = worker;
375 worker.postMessage(_serializeMessage({ 372 worker.postMessage(_serializeMessage({
376 'command': 'start', 373 'command': 'start',
377 'id': workerId, 374 'id': workerId,
378 'replyTo': serializedReplyPort, 375 'replyTo': serializedReplyPort,
379 'factoryName': factoryName })); 376 'factoryName': factoryName }));
380 } 377 }
381 378
382 /** 379 /**
383 * Assume that [e] is a browser message event and extract its message data. 380 * Assume that [e] is a browser message event and extract its message data.
384 * We don't import the dom explicitly so, when workers are disabled, this 381 * We don't import the dom explicitly so, when workers are disabled, this
385 * library can also run on top of nodejs. 382 * library can also run on top of nodejs.
386 */ 383 */
387 static _getEventData(e) native "return e.data"; 384 static _getEventData(e) native "return e.data";
388 385
389 /** 386 /**
390 * Process messages on a worker, either to control the worker instance or to 387 * Process messages on a worker, either to control the worker instance or to
391 * pass messages along to the isolate running in the worker. 388 * pass messages along to the isolate running in the worker.
392 */ 389 */
393 static void _processWorkerMessage(sender, e) { 390 static void _processWorkerMessage(sender, e) {
394 var msg = _deserializeMessage(_getEventData(e)); 391 var msg = _deserializeMessage(_getEventData(e));
395 switch (msg['command']) { 392 switch (msg['command']) {
396 // TODO(sigmund): delete after we migrate to the new API 393 // TODO(sigmund): delete after we migrate to the new API
397 case 'start': 394 case 'start':
398 globalState.currentWorkerId = msg['id']; 395 _globalState.currentWorkerId = msg['id'];
399 var runnerObject = 396 var runnerObject =
400 _allocate(_getJSConstructorFromName(msg['factoryName'])); 397 _allocate(_getJSConstructorFromName(msg['factoryName']));
401 var serializedReplyTo = msg['replyTo']; 398 var serializedReplyTo = msg['replyTo'];
402 globalState.topEventLoop.enqueue(new IsolateContext(), function() { 399 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() {
403 var replyTo = _deserializeMessage(serializedReplyTo); 400 var replyTo = _deserializeMessage(serializedReplyTo);
404 _startIsolate(runnerObject, replyTo); 401 _startIsolate(runnerObject, replyTo);
405 }, 'worker-start'); 402 }, 'worker-start');
406 globalState.topEventLoop.run(); 403 _globalState.topEventLoop.run();
407 break; 404 break;
408 case 'start2': 405 case 'start2':
409 globalState.currentWorkerId = msg['id']; 406 _globalState.currentWorkerId = msg['id'];
410 Function entryPoint = _getJSFunctionFromName(msg['functionName']); 407 Function entryPoint = _getJSFunctionFromName(msg['functionName']);
411 var replyTo = _deserializeMessage(msg['replyTo']); 408 var replyTo = _deserializeMessage(msg['replyTo']);
412 globalState.topEventLoop.enqueue(new IsolateContext(), function() { 409 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() {
413 _startIsolate2(entryPoint, replyTo); 410 _startIsolate2(entryPoint, replyTo);
414 }, 'worker-start'); 411 }, 'worker-start');
415 globalState.topEventLoop.run(); 412 _globalState.topEventLoop.run();
416 break; 413 break;
417 // TODO(sigmund): delete after we migrate to the new API 414 // TODO(sigmund): delete after we migrate to the new API
418 case 'spawn-worker': 415 case 'spawn-worker':
419 _spawnWorker(msg['factoryName'], msg['replyPort']); 416 _spawnWorker(msg['factoryName'], msg['replyPort']);
420 break; 417 break;
421 case 'spawn-worker2': 418 case 'spawn-worker2':
422 _spawnWorker2(msg['functionName'], msg['uri'], msg['replyPort']); 419 _spawnWorker2(msg['functionName'], msg['uri'], msg['replyPort']);
423 break; 420 break;
424 case 'message': 421 case 'message':
425 msg['port'].send(msg['msg'], msg['replyTo']); 422 msg['port'].send(msg['msg'], msg['replyTo']);
426 globalState.topEventLoop.run(); 423 _globalState.topEventLoop.run();
427 break; 424 break;
428 case 'close': 425 case 'close':
429 _log("Closing Worker"); 426 _log("Closing Worker");
430 globalState.workers.remove(sender.id); 427 _globalState.workers.remove(sender.id);
431 sender.terminate(); 428 sender.terminate();
432 globalState.topEventLoop.run(); 429 _globalState.topEventLoop.run();
433 break; 430 break;
434 case 'log': 431 case 'log':
435 _log(msg['msg']); 432 _log(msg['msg']);
436 break; 433 break;
437 case 'print': 434 case 'print':
438 if (globalState.isWorker) { 435 if (_globalState.isWorker) {
439 globalState.mainWorker.postMessage( 436 _globalState.mainWorker.postMessage(
440 _serializeMessage({'command': 'print', 'msg': msg})); 437 _serializeMessage({'command': 'print', 'msg': msg}));
441 } else { 438 } else {
442 print(msg['msg']); 439 print(msg['msg']);
443 } 440 }
444 break; 441 break;
445 case 'error': 442 case 'error':
446 throw msg['msg']; 443 throw msg['msg'];
447 } 444 }
448 } 445 }
449 446
450 /** Log a message, forwarding to the main worker if appropriate. */ 447 /** Log a message, forwarding to the main worker if appropriate. */
451 static _log(msg) { 448 static _log(msg) {
452 if (globalState.isWorker) { 449 if (_globalState.isWorker) {
453 globalState.mainWorker.postMessage( 450 _globalState.mainWorker.postMessage(
454 _serializeMessage({'command': 'log', 'msg': msg })); 451 _serializeMessage({'command': 'log', 'msg': msg }));
455 } else { 452 } else {
456 try { 453 try {
457 _consoleLog(msg); 454 _consoleLog(msg);
458 } catch(e, trace) { 455 } catch(e, trace) {
459 throw new Exception(trace); 456 throw new Exception(trace);
460 } 457 }
461 } 458 }
462 } 459 }
463 460
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
515 return f.name || null; 512 return f.name || null;
516 } 513 }
517 """; 514 """;
518 515
519 /** Create a new JavaScript object instance given its constructor. */ 516 /** Create a new JavaScript object instance given its constructor. */
520 static var _allocate(var ctor) native "return new ctor();"; 517 static var _allocate(var ctor) native "return new ctor();";
521 518
522 /** Starts a non-worker isolate. */ 519 /** Starts a non-worker isolate. */
523 static SendPort _startNonWorker(Isolate runnable, SendPort replyTo) { 520 static SendPort _startNonWorker(Isolate runnable, SendPort replyTo) {
524 // Spawn a new isolate and create the receive port in it. 521 // Spawn a new isolate and create the receive port in it.
525 final spawned = new IsolateContext(); 522 final spawned = new _IsolateContext();
526 523
527 // Instead of just running the provided runnable, we create a 524 // Instead of just running the provided runnable, we create a
528 // new cloned instance of it with a fresh state in the spawned 525 // new cloned instance of it with a fresh state in the spawned
529 // isolate. This way, we do not get cross-isolate references 526 // isolate. This way, we do not get cross-isolate references
530 // through the runnable. 527 // through the runnable.
531 final ctor = _getJSConstructor(runnable); 528 final ctor = _getJSConstructor(runnable);
532 globalState.topEventLoop.enqueue(spawned, function() { 529 _globalState.topEventLoop.enqueue(spawned, function() {
533 _startIsolate(_allocate(ctor), replyTo); 530 _startIsolate(_allocate(ctor), replyTo);
534 }, 'nonworker start'); 531 }, 'nonworker start');
535 } 532 }
536 533
537 /** Given a ready-to-start runnable, start running it. */ 534 /** Given a ready-to-start runnable, start running it. */
538 static void _startIsolate(Isolate isolate, SendPort replyTo) { 535 static void _startIsolate(Isolate isolate, SendPort replyTo) {
539 fillStatics(globalState.currentContext); 536 _fillStatics(_globalState.currentContext);
540 ReceivePort port = new ReceivePort(); 537 ReceivePort port = new ReceivePort();
541 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); 538 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort());
542 isolate._run(port); 539 isolate._run(port);
543 } 540 }
544 541
545 // TODO(sigmund): clean up above, after we make the new API the default: 542 // TODO(sigmund): clean up above, after we make the new API the default:
546 543
547 static _spawn2(String functionName, String uri, bool isLight) { 544 static _spawn2(String functionName, String uri, bool isLight) {
548 Completer<SendPort> completer = new Completer<SendPort>(); 545 Completer<SendPort> completer = new Completer<SendPort>();
549 ReceivePort port = new ReceivePort.singleShot(); 546 ReceivePort port = new ReceivePort.singleShot();
550 port.receive((msg, SendPort replyPort) { 547 port.receive((msg, SendPort replyPort) {
551 assert(msg == _SPAWNED_SIGNAL); 548 assert(msg == _SPAWNED_SIGNAL);
552 completer.complete(replyPort); 549 completer.complete(replyPort);
553 }); 550 });
554 551
555 SendPort signalReply = port.toSendPort(); 552 SendPort signalReply = port.toSendPort();
556 553
557 if (globalState.useWorkers && !isLight) { 554 if (_globalState.useWorkers && !isLight) {
558 _startWorker2(functionName, uri, signalReply); 555 _startWorker2(functionName, uri, signalReply);
559 } else { 556 } else {
560 _startNonWorker2(functionName, uri, signalReply); 557 _startNonWorker2(functionName, uri, signalReply);
561 } 558 }
562 return new _BufferingSendPort( 559 return new _BufferingSendPort(
563 globalState.currentContext.id, completer.future); 560 _globalState.currentContext.id, completer.future);
564 } 561 }
565 562
566 static SendPort _startWorker2( 563 static SendPort _startWorker2(
567 String functionName, String uri, SendPort replyPort) { 564 String functionName, String uri, SendPort replyPort) {
568 if (globalState.isWorker) { 565 if (_globalState.isWorker) {
569 globalState.mainWorker.postMessage(_serializeMessage({ 566 _globalState.mainWorker.postMessage(_serializeMessage({
570 'command': 'spawn-worker2', 567 'command': 'spawn-worker2',
571 'functionName': functionName, 568 'functionName': functionName,
572 'uri': uri, 569 'uri': uri,
573 'replyPort': replyPort})); 570 'replyPort': replyPort}));
574 } else { 571 } else {
575 _spawnWorker2(functionName, uri, replyPort); 572 _spawnWorker2(functionName, uri, replyPort);
576 } 573 }
577 } 574 }
578 575
579 static SendPort _startNonWorker2( 576 static SendPort _startNonWorker2(
580 String functionName, String uri, SendPort replyPort) { 577 String functionName, String uri, SendPort replyPort) {
581 // TODO(eub): support IE9 using an iframe -- Dart issue 1702. 578 // TODO(eub): support IE9 using an iframe -- Dart issue 1702.
582 if (uri != null) throw new UnsupportedOperationException( 579 if (uri != null) throw new UnsupportedOperationException(
583 "Currently spawnUri is not supported without web workers."); 580 "Currently spawnUri is not supported without web workers.");
584 globalState.topEventLoop.enqueue(new IsolateContext(), function() { 581 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() {
585 final func = _getJSFunctionFromName(functionName); 582 final func = _getJSFunctionFromName(functionName);
586 _startIsolate2(func, replyPort); 583 _startIsolate2(func, replyPort);
587 }, 'nonworker start'); 584 }, 'nonworker start');
588 } 585 }
589 586
590 static void _startIsolate2(Function topLevel, SendPort replyTo) { 587 static void _startIsolate2(Function topLevel, SendPort replyTo) {
591 fillStatics(globalState.currentContext); 588 _fillStatics(_globalState.currentContext);
592 _port = new ReceivePort(); 589 _port = new ReceivePort();
593 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); 590 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort());
594 topLevel(); 591 topLevel();
595 } 592 }
596 593
597 /** 594 /**
598 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor 595 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor
599 * name for the isolate entry point class. 596 * name for the isolate entry point class.
600 */ 597 */
601 static void _spawnWorker2(functionName, uri, replyPort) { 598 static void _spawnWorker2(functionName, uri, replyPort) {
602 if (functionName == null) functionName = 'main'; 599 if (functionName == null) functionName = 'main';
603 if (uri == null) uri = _thisScript; 600 if (uri == null) uri = _thisScript;
604 if (!(new Uri.fromString(uri).isAbsolute())) { 601 if (!(new Uri.fromString(uri).isAbsolute())) {
605 // The constructor of dom workers requires an absolute URL. If we use a 602 // The constructor of dom workers requires an absolute URL. If we use a
606 // relative path we will get a DOM exception. 603 // relative path we will get a DOM exception.
607 String prefix = _thisScript.substring(0, _thisScript.lastIndexOf('/')); 604 String prefix = _thisScript.substring(0, _thisScript.lastIndexOf('/'));
608 uri = "$prefix/$uri"; 605 uri = "$prefix/$uri";
609 } 606 }
610 final worker = _newWorker(uri); 607 final worker = _newWorker(uri);
611 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; 608 worker.onmessage = (e) { _processWorkerMessage(worker, e); };
612 var workerId = globalState.nextWorkerId++; 609 var workerId = _globalState.nextWorkerId++;
613 // We also store the id on the worker itself so that we can unregister it. 610 // We also store the id on the worker itself so that we can unregister it.
614 worker.id = workerId; 611 worker.id = workerId;
615 globalState.workers[workerId] = worker; 612 _globalState.workers[workerId] = worker;
616 worker.postMessage(_serializeMessage({ 613 worker.postMessage(_serializeMessage({
617 'command': 'start2', 614 'command': 'start2',
618 'id': workerId, 615 'id': workerId,
619 // Note: we serialize replyPort twice because the child worker needs to 616 // Note: we serialize replyPort twice because the child worker needs to
620 // first deserialize the worker id, before it can correctly deserialize 617 // first deserialize the worker id, before it can correctly deserialize
621 // the port (port deserialization is sensitive to what is the current 618 // the port (port deserialization is sensitive to what is the current
622 // workerId). 619 // workerId).
623 'replyTo': _serializeMessage(replyPort), 620 'replyTo': _serializeMessage(replyPort),
624 'functionName': functionName })); 621 'functionName': functionName }));
625 } 622 }
626 } 623 }
OLDNEW
« no previous file with comments | « lib/isolate/frog/compiler_hooks.dart ('k') | lib/isolate/frog/messages.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698