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

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) {
Siggi Cherem (dart-lang) 2012/03/02 01:58:30 both the comment and the condition were wrong. Thi
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 if (_globalState.isWorker) {
eub 2012/03/02 19:48:27 This was already true at the time we entered this
Siggi Cherem (dart-lang) 2012/03/02 21:00:39 totally redundant, good catch. Thanks!
251 {'command': 'error', 'msg': '$e\n$trace' })); 249 _globalState.mainWorker.postMessage(_serializeMessage(
250 {'command': 'error', 'msg': '$e\n$trace' }));
251 } else {
252 throw e;
253 }
252 } 254 }
253 } 255 }
254 } 256 }
255 } 257 }
256 258
257 /** An event in the top-level event queue. */ 259 /** An event in the top-level event queue. */
258 class IsolateEvent { 260 class _IsolateEvent {
259 IsolateContext isolate; 261 _IsolateContext isolate;
260 Function fn; 262 Function fn;
261 String message; 263 String message;
262 264
263 IsolateEvent(this.isolate, this.fn, this.message); 265 _IsolateEvent(this.isolate, this.fn, this.message);
264 266
265 void process() { 267 void process() {
266 isolate.eval(fn); 268 isolate.eval(fn);
267 } 269 }
268 } 270 }
269 271
270 272
271 /** Default worker. */ 273 /** Default worker. */
272 class MainWorker { 274 class _MainWorker {
273 int id = 0; 275 int id = 0;
274 void postMessage(msg) native "return \$globalThis.postMessage(msg);"; 276 void postMessage(msg) native @"$globalThis.postMessage(msg);";
275 void set onmessage(f) native "\$globalThis.onmessage = f;";
276 void terminate() {} 277 void terminate() {}
277 } 278 }
278 279
279 /** 280 /**
280 * A web worker. This type is also defined in 'dart:dom', but we define it here 281 * 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 282 * 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 283 * 'hidden' type (* prefix on the native name) to enforce that the type is
283 * defined dynamically only when web workers are actually available. 284 * defined dynamically only when web workers are actually available.
284 */ 285 */
285 class _Worker native "*Worker" { 286 class _Worker native "*Worker" {
(...skipping 11 matching lines...) Expand all
297 static Future<SendPort> spawn(Isolate isolate, bool isLight) { 298 static Future<SendPort> spawn(Isolate isolate, bool isLight) {
298 Completer<SendPort> completer = new Completer<SendPort>(); 299 Completer<SendPort> completer = new Completer<SendPort>();
299 ReceivePort port = new ReceivePort.singleShot(); 300 ReceivePort port = new ReceivePort.singleShot();
300 port.receive((msg, SendPort replyPort) { 301 port.receive((msg, SendPort replyPort) {
301 assert(msg == _SPAWNED_SIGNAL); 302 assert(msg == _SPAWNED_SIGNAL);
302 completer.complete(replyPort); 303 completer.complete(replyPort);
303 }); 304 });
304 305
305 // TODO(floitsch): throw exception if isolate's class doesn't have a 306 // TODO(floitsch): throw exception if isolate's class doesn't have a
306 // default constructor. 307 // default constructor.
307 if (globalState.useWorkers && !isLight) { 308 if (_globalState.useWorkers && !isLight) {
308 _startWorker(isolate, port.toSendPort()); 309 _startWorker(isolate, port.toSendPort());
309 } else { 310 } else {
310 _startNonWorker(isolate, port.toSendPort()); 311 _startNonWorker(isolate, port.toSendPort());
311 } 312 }
312 313
313 return completer.future; 314 return completer.future;
314 } 315 }
315 316
316 static SendPort _startWorker(Isolate runnable, SendPort replyPort) { 317 static SendPort _startWorker(Isolate runnable, SendPort replyPort) {
317 var factoryName = _getJSConstructorName(runnable); 318 var factoryName = _getJSConstructorName(runnable);
318 if (globalState.isWorker) { 319 if (_globalState.isWorker) {
319 globalState.mainWorker.postMessage(_serializeMessage({ 320 _globalState.mainWorker.postMessage(_serializeMessage({
320 'command': 'spawn-worker', 321 'command': 'spawn-worker',
321 'factoryName': factoryName, 322 'factoryName': factoryName,
322 'replyPort': _serializeMessage(replyPort)})); 323 'replyPort': _serializeMessage(replyPort)}));
323 } else { 324 } else {
324 _spawnWorker(factoryName, _serializeMessage(replyPort)); 325 _spawnWorker(factoryName, _serializeMessage(replyPort));
325 } 326 }
326 } 327 }
327 328
328 /** 329 /**
329 * The src url for the script tag that loaded this code. Used to create 330 * 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. */ 362 /** Starts a new worker with the given URL. */
362 static _Worker _newWorker(url) native "return new Worker(url);"; 363 static _Worker _newWorker(url) native "return new Worker(url);";
363 364
364 /** 365 /**
365 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor 366 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor
366 * name for the isolate entry point class. 367 * name for the isolate entry point class.
367 */ 368 */
368 static void _spawnWorker(factoryName, serializedReplyPort) { 369 static void _spawnWorker(factoryName, serializedReplyPort) {
369 final worker = _newWorker(_thisScript); 370 final worker = _newWorker(_thisScript);
370 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; 371 worker.onmessage = (e) { _processWorkerMessage(worker, e); };
371 var workerId = globalState.nextWorkerId++; 372 var workerId = _globalState.nextWorkerId++;
372 // We also store the id on the worker itself so that we can unregister it. 373 // We also store the id on the worker itself so that we can unregister it.
373 worker.id = workerId; 374 worker.id = workerId;
374 globalState.workers[workerId] = worker; 375 _globalState.workers[workerId] = worker;
375 worker.postMessage(_serializeMessage({ 376 worker.postMessage(_serializeMessage({
376 'command': 'start', 377 'command': 'start',
377 'id': workerId, 378 'id': workerId,
378 'replyTo': serializedReplyPort, 379 'replyTo': serializedReplyPort,
379 'factoryName': factoryName })); 380 'factoryName': factoryName }));
380 } 381 }
381 382
382 /** 383 /**
383 * Assume that [e] is a browser message event and extract its message data. 384 * 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 385 * We don't import the dom explicitly so, when workers are disabled, this
385 * library can also run on top of nodejs. 386 * library can also run on top of nodejs.
386 */ 387 */
387 static _getEventData(e) native "return e.data"; 388 static _getEventData(e) native "return e.data";
388 389
389 /** 390 /**
390 * Process messages on a worker, either to control the worker instance or to 391 * Process messages on a worker, either to control the worker instance or to
391 * pass messages along to the isolate running in the worker. 392 * pass messages along to the isolate running in the worker.
392 */ 393 */
393 static void _processWorkerMessage(sender, e) { 394 static void _processWorkerMessage(sender, e) {
394 var msg = _deserializeMessage(_getEventData(e)); 395 var msg = _deserializeMessage(_getEventData(e));
395 switch (msg['command']) { 396 switch (msg['command']) {
396 // TODO(sigmund): delete after we migrate to the new API 397 // TODO(sigmund): delete after we migrate to the new API
397 case 'start': 398 case 'start':
398 globalState.currentWorkerId = msg['id']; 399 _globalState.currentWorkerId = msg['id'];
399 var runnerObject = 400 var runnerObject =
400 _allocate(_getJSConstructorFromName(msg['factoryName'])); 401 _allocate(_getJSConstructorFromName(msg['factoryName']));
401 var serializedReplyTo = msg['replyTo']; 402 var serializedReplyTo = msg['replyTo'];
402 globalState.topEventLoop.enqueue(new IsolateContext(), function() { 403 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() {
403 var replyTo = _deserializeMessage(serializedReplyTo); 404 var replyTo = _deserializeMessage(serializedReplyTo);
404 _startIsolate(runnerObject, replyTo); 405 _startIsolate(runnerObject, replyTo);
405 }, 'worker-start'); 406 }, 'worker-start');
406 globalState.topEventLoop.run(); 407 _globalState.topEventLoop.run();
407 break; 408 break;
408 case 'start2': 409 case 'start2':
409 globalState.currentWorkerId = msg['id']; 410 _globalState.currentWorkerId = msg['id'];
410 Function entryPoint = _getJSFunctionFromName(msg['functionName']); 411 Function entryPoint = _getJSFunctionFromName(msg['functionName']);
411 var replyTo = _deserializeMessage(msg['replyTo']); 412 var replyTo = _deserializeMessage(msg['replyTo']);
412 globalState.topEventLoop.enqueue(new IsolateContext(), function() { 413 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() {
413 _startIsolate2(entryPoint, replyTo); 414 _startIsolate2(entryPoint, replyTo);
414 }, 'worker-start'); 415 }, 'worker-start');
415 globalState.topEventLoop.run(); 416 _globalState.topEventLoop.run();
416 break; 417 break;
417 // TODO(sigmund): delete after we migrate to the new API 418 // TODO(sigmund): delete after we migrate to the new API
418 case 'spawn-worker': 419 case 'spawn-worker':
419 _spawnWorker(msg['factoryName'], msg['replyPort']); 420 _spawnWorker(msg['factoryName'], msg['replyPort']);
420 break; 421 break;
421 case 'spawn-worker2': 422 case 'spawn-worker2':
422 _spawnWorker2(msg['functionName'], msg['uri'], msg['replyPort']); 423 _spawnWorker2(msg['functionName'], msg['uri'], msg['replyPort']);
423 break; 424 break;
424 case 'message': 425 case 'message':
425 msg['port'].send(msg['msg'], msg['replyTo']); 426 msg['port'].send(msg['msg'], msg['replyTo']);
426 globalState.topEventLoop.run(); 427 _globalState.topEventLoop.run();
427 break; 428 break;
428 case 'close': 429 case 'close':
429 _log("Closing Worker"); 430 _log("Closing Worker");
430 globalState.workers.remove(sender.id); 431 _globalState.workers.remove(sender.id);
431 sender.terminate(); 432 sender.terminate();
432 globalState.topEventLoop.run(); 433 _globalState.topEventLoop.run();
433 break; 434 break;
434 case 'log': 435 case 'log':
435 _log(msg['msg']); 436 _log(msg['msg']);
436 break; 437 break;
437 case 'print': 438 case 'print':
438 if (globalState.isWorker) { 439 if (_globalState.isWorker) {
439 globalState.mainWorker.postMessage( 440 _globalState.mainWorker.postMessage(
440 _serializeMessage({'command': 'print', 'msg': msg})); 441 _serializeMessage({'command': 'print', 'msg': msg}));
441 } else { 442 } else {
442 print(msg['msg']); 443 print(msg['msg']);
443 } 444 }
444 break; 445 break;
445 case 'error': 446 case 'error':
446 throw msg['msg']; 447 throw msg['msg'];
447 } 448 }
448 } 449 }
449 450
450 /** Log a message, forwarding to the main worker if appropriate. */ 451 /** Log a message, forwarding to the main worker if appropriate. */
451 static _log(msg) { 452 static _log(msg) {
452 if (globalState.isWorker) { 453 if (_globalState.isWorker) {
453 globalState.mainWorker.postMessage( 454 _globalState.mainWorker.postMessage(
454 _serializeMessage({'command': 'log', 'msg': msg })); 455 _serializeMessage({'command': 'log', 'msg': msg }));
455 } else { 456 } else {
456 try { 457 try {
457 _consoleLog(msg); 458 _consoleLog(msg);
458 } catch(e, trace) { 459 } catch(e, trace) {
459 throw new Exception(trace); 460 throw new Exception(trace);
460 } 461 }
461 } 462 }
462 } 463 }
463 464
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
515 return f.name || null; 516 return f.name || null;
516 } 517 }
517 """; 518 """;
518 519
519 /** Create a new JavaScript object instance given its constructor. */ 520 /** Create a new JavaScript object instance given its constructor. */
520 static var _allocate(var ctor) native "return new ctor();"; 521 static var _allocate(var ctor) native "return new ctor();";
521 522
522 /** Starts a non-worker isolate. */ 523 /** Starts a non-worker isolate. */
523 static SendPort _startNonWorker(Isolate runnable, SendPort replyTo) { 524 static SendPort _startNonWorker(Isolate runnable, SendPort replyTo) {
524 // Spawn a new isolate and create the receive port in it. 525 // Spawn a new isolate and create the receive port in it.
525 final spawned = new IsolateContext(); 526 final spawned = new _IsolateContext();
526 527
527 // Instead of just running the provided runnable, we create a 528 // Instead of just running the provided runnable, we create a
528 // new cloned instance of it with a fresh state in the spawned 529 // new cloned instance of it with a fresh state in the spawned
529 // isolate. This way, we do not get cross-isolate references 530 // isolate. This way, we do not get cross-isolate references
530 // through the runnable. 531 // through the runnable.
531 final ctor = _getJSConstructor(runnable); 532 final ctor = _getJSConstructor(runnable);
532 globalState.topEventLoop.enqueue(spawned, function() { 533 _globalState.topEventLoop.enqueue(spawned, function() {
533 _startIsolate(_allocate(ctor), replyTo); 534 _startIsolate(_allocate(ctor), replyTo);
534 }, 'nonworker start'); 535 }, 'nonworker start');
535 } 536 }
536 537
537 /** Given a ready-to-start runnable, start running it. */ 538 /** Given a ready-to-start runnable, start running it. */
538 static void _startIsolate(Isolate isolate, SendPort replyTo) { 539 static void _startIsolate(Isolate isolate, SendPort replyTo) {
539 fillStatics(globalState.currentContext); 540 _fillStatics(_globalState.currentContext);
540 ReceivePort port = new ReceivePort(); 541 ReceivePort port = new ReceivePort();
541 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); 542 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort());
542 isolate._run(port); 543 isolate._run(port);
543 } 544 }
544 545
545 // TODO(sigmund): clean up above, after we make the new API the default: 546 // TODO(sigmund): clean up above, after we make the new API the default:
546 547
547 static _spawn2(String functionName, String uri, bool isLight) { 548 static _spawn2(String functionName, String uri, bool isLight) {
548 Completer<SendPort> completer = new Completer<SendPort>(); 549 Completer<SendPort> completer = new Completer<SendPort>();
549 ReceivePort port = new ReceivePort.singleShot(); 550 ReceivePort port = new ReceivePort.singleShot();
550 port.receive((msg, SendPort replyPort) { 551 port.receive((msg, SendPort replyPort) {
551 assert(msg == _SPAWNED_SIGNAL); 552 assert(msg == _SPAWNED_SIGNAL);
552 completer.complete(replyPort); 553 completer.complete(replyPort);
553 }); 554 });
554 555
555 SendPort signalReply = port.toSendPort(); 556 SendPort signalReply = port.toSendPort();
556 557
557 if (globalState.useWorkers && !isLight) { 558 if (_globalState.useWorkers && !isLight) {
558 _startWorker2(functionName, uri, signalReply); 559 _startWorker2(functionName, uri, signalReply);
559 } else { 560 } else {
560 _startNonWorker2(functionName, uri, signalReply); 561 _startNonWorker2(functionName, uri, signalReply);
561 } 562 }
562 return new _BufferingSendPort( 563 return new _BufferingSendPort(
563 globalState.currentContext.id, completer.future); 564 _globalState.currentContext.id, completer.future);
564 } 565 }
565 566
566 static SendPort _startWorker2( 567 static SendPort _startWorker2(
567 String functionName, String uri, SendPort replyPort) { 568 String functionName, String uri, SendPort replyPort) {
568 if (globalState.isWorker) { 569 if (_globalState.isWorker) {
569 globalState.mainWorker.postMessage(_serializeMessage({ 570 _globalState.mainWorker.postMessage(_serializeMessage({
570 'command': 'spawn-worker2', 571 'command': 'spawn-worker2',
571 'functionName': functionName, 572 'functionName': functionName,
572 'uri': uri, 573 'uri': uri,
573 'replyPort': replyPort})); 574 'replyPort': replyPort}));
574 } else { 575 } else {
575 _spawnWorker2(functionName, uri, replyPort); 576 _spawnWorker2(functionName, uri, replyPort);
576 } 577 }
577 } 578 }
578 579
579 static SendPort _startNonWorker2( 580 static SendPort _startNonWorker2(
580 String functionName, String uri, SendPort replyPort) { 581 String functionName, String uri, SendPort replyPort) {
581 // TODO(eub): support IE9 using an iframe -- Dart issue 1702. 582 // TODO(eub): support IE9 using an iframe -- Dart issue 1702.
582 if (uri != null) throw new UnsupportedOperationException( 583 if (uri != null) throw new UnsupportedOperationException(
583 "Currently spawnUri is not supported without web workers."); 584 "Currently spawnUri is not supported without web workers.");
584 globalState.topEventLoop.enqueue(new IsolateContext(), function() { 585 _globalState.topEventLoop.enqueue(new _IsolateContext(), function() {
585 final func = _getJSFunctionFromName(functionName); 586 final func = _getJSFunctionFromName(functionName);
586 _startIsolate2(func, replyPort); 587 _startIsolate2(func, replyPort);
587 }, 'nonworker start'); 588 }, 'nonworker start');
588 } 589 }
589 590
590 static void _startIsolate2(Function topLevel, SendPort replyTo) { 591 static void _startIsolate2(Function topLevel, SendPort replyTo) {
591 fillStatics(globalState.currentContext); 592 _fillStatics(_globalState.currentContext);
592 _port = new ReceivePort(); 593 _port = new ReceivePort();
593 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); 594 replyTo.send(_SPAWNED_SIGNAL, port.toSendPort());
594 topLevel(); 595 topLevel();
595 } 596 }
596 597
597 /** 598 /**
598 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor 599 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor
599 * name for the isolate entry point class. 600 * name for the isolate entry point class.
600 */ 601 */
601 static void _spawnWorker2(functionName, uri, replyPort) { 602 static void _spawnWorker2(functionName, uri, replyPort) {
602 if (functionName == null) functionName = 'main'; 603 if (functionName == null) functionName = 'main';
603 if (uri == null) uri = _thisScript; 604 if (uri == null) uri = _thisScript;
604 if (!(new Uri.fromString(uri).isAbsolute())) { 605 if (!(new Uri.fromString(uri).isAbsolute())) {
605 // The constructor of dom workers requires an absolute URL. If we use a 606 // The constructor of dom workers requires an absolute URL. If we use a
606 // relative path we will get a DOM exception. 607 // relative path we will get a DOM exception.
607 String prefix = _thisScript.substring(0, _thisScript.lastIndexOf('/')); 608 String prefix = _thisScript.substring(0, _thisScript.lastIndexOf('/'));
608 uri = "$prefix/$uri"; 609 uri = "$prefix/$uri";
609 } 610 }
610 final worker = _newWorker(uri); 611 final worker = _newWorker(uri);
611 worker.onmessage = (e) { _processWorkerMessage(worker, e); }; 612 worker.onmessage = (e) { _processWorkerMessage(worker, e); };
612 var workerId = globalState.nextWorkerId++; 613 var workerId = _globalState.nextWorkerId++;
613 // We also store the id on the worker itself so that we can unregister it. 614 // We also store the id on the worker itself so that we can unregister it.
614 worker.id = workerId; 615 worker.id = workerId;
615 globalState.workers[workerId] = worker; 616 _globalState.workers[workerId] = worker;
616 worker.postMessage(_serializeMessage({ 617 worker.postMessage(_serializeMessage({
617 'command': 'start2', 618 'command': 'start2',
618 'id': workerId, 619 'id': workerId,
619 // Note: we serialize replyPort twice because the child worker needs to 620 // Note: we serialize replyPort twice because the child worker needs to
620 // first deserialize the worker id, before it can correctly deserialize 621 // first deserialize the worker id, before it can correctly deserialize
621 // the port (port deserialization is sensitive to what is the current 622 // the port (port deserialization is sensitive to what is the current
622 // workerId). 623 // workerId).
623 'replyTo': _serializeMessage(replyPort), 624 'replyTo': _serializeMessage(replyPort),
624 'functionName': functionName })); 625 'functionName': functionName }));
625 } 626 }
626 } 627 }
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