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

Side by Side Diff: compiler/lib/implementation/isolate.js

Issue 9702034: Removes dartc reliance on its own libraries, now can be targeted at any implementation's libraries (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: junit tests fixed 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
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 // TODO(sigmund): this file should be removed when the dart code generation
6 // backend is deleted.
7
8 var isolate$current = null;
9 var isolate$rootIsolate = null; // Will only be set in the main worker.
10 var isolate$inits = [];
11 var isolate$globalThis = this;
12
13 // These declarations are needed to avoid errors from the Closure Compiler
14 // optimizer. They are defined in client/dom/generated/dart_dom_wrapping.js.
15 var __dom_wrap;
16 var __dom_unwrap;
17
18 var isolate$inWorker =
19 (typeof isolate$globalThis['importScripts']) != "undefined";
20 var isolate$supportsWorkers =
21 isolate$inWorker || ((typeof isolate$globalThis['Worker']) != 'undefined');
22
23 var isolate$MAIN_WORKER_ID = 0;
24 // Non-main workers will update the id variable.
25 var isolate$thisWorkerId = isolate$MAIN_WORKER_ID;
26
27 // Whether to use web workers when implementing isolates.
28 var isolate$useWorkers = isolate$supportsWorkers;
29 // Uncomment this to not use web workers even if they're available.
30 // isolate$useWorkers = false;
31
32 // Whether to use the web-worker JSON-based message serialization protocol,
33 // even if not using web workers.
34 var isolate$useWorkerSerializationProtocol = false;
35 // Uncomment this to always use the web-worker JSON-based message
36 // serialization protocol, e.g. for testing purposes.
37 // isolate$useWorkerSerializationProtocol = true;
38
39
40 // ------- SendPort -------
41 function isolate$sendMessage(workerId, isolateId, receivePortId,
42 message, replyTo) {
43 // Both, the message and the replyTo are already serialized.
44 if (workerId == isolate$thisWorkerId) {
45 var isolate = isolate$isolateRegistry.get(isolateId);
46 if (!isolate) return; // Isolate has been closed.
47 var receivePort = isolate.getReceivePortForId(receivePortId);
48 if (!receivePort) return; // ReceivePort has been closed.
49 isolate$receiveMessage(receivePort, isolate, message, replyTo);
50 } else {
51 var worker;
52 if (isolate$inWorker) {
53 worker = isolate$mainWorker;
54 } else {
55 worker = isolate$workerRegistry.get(workerId);
56 }
57 worker.postMessage({ command: 'message',
58 workerId: workerId,
59 isolateId: isolateId,
60 portId: receivePortId,
61 msg: message,
62 replyTo: replyTo });
63 }
64 }
65
66 function isolate$receiveMessage(port, isolate,
67 serializedMessage, serializedReplyTo) {
68 isolate$IsolateEvent.enqueue(isolate, function() {
69 var message = isolate$deserializeMessage(serializedMessage);
70 var replyTo = isolate$deserializeMessage(serializedReplyTo);
71 native_ReceivePortImpl__invokeCallback(port, message, replyTo);
72 });
73 }
74
75 // ------- ReceivePort -------
76
77 function native_ReceivePortImpl__register(id) {
78 isolate$current.registerReceivePort(id, this);
79 }
80
81 function native_ReceivePortImpl__unregister(id) {
82 isolate$current.unregisterReceivePort(id);
83 }
84
85 function native_ReceivePortImpl__currentWorkerId() {
86 return isolate$thisWorkerId;
87 }
88
89 function native_ReceivePortImpl__currentIsolateId() {
90 return isolate$current.id;
91 }
92
93 // -------- Registry ---------
94 function isolate$Registry() {
95 this.map = {};
96 this.count = 0;
97 }
98
99 isolate$Registry.prototype.register = function(id, val) {
100 if (this.map[id]) {
101 throw Error("Registry: Elements must be registered only once.");
102 }
103 this.map[id] = val;
104 this.count++;
105 };
106
107 isolate$Registry.prototype.unregister = function(id) {
108 if (id in this.map) {
109 delete this.map[id];
110 this.count--;
111 }
112 };
113
114 isolate$Registry.prototype.get = function(id) {
115 return this.map[id];
116 };
117
118 isolate$Registry.prototype.contains = function(id) {
119 return this.map[id] !== void 0;
120 };
121
122 isolate$Registry.prototype.isEmpty = function() {
123 return this.count === 0;
124 };
125
126
127 // ------- Worker registry -------
128 // Only used in the main worker.
129 var isolate$workerRegistry = new isolate$Registry();
130
131 // ------- Isolate registry -------
132 // Isolates must be registered if, and only if, receive ports are alive.
133 // Normally no open receive-ports means that the isolate is dead, but
134 // DOM callbacks could resurrect it.
135 var isolate$isolateRegistry = new isolate$Registry();
136
137 // ------- Debugging log function -------
138 function isolate$log(msg) {
139 return;
140 if (isolate$inWorker) {
141 isolate$mainWorker.postMessage({ command: 'log', msg: msg });
142 } else {
143 try {
144 isolate$globalThis.console.log(msg);
145 } catch(e) {
146 throw String(e.stack);
147 }
148 }
149 }
150
151 function isolate$initializeWorker(workerId) {
152 isolate$thisWorkerId = workerId;
153 }
154
155 var isolate$workerPrint = false;
156 if (isolate$inWorker) {
157 isolate$workerPrint = function(msg){
158 isolate$mainWorker.postMessage({ command: 'print', msg: msg });
159 }
160 }
161
162 // ------- Message handler -------
163 function isolate$processWorkerMessage(sender, e) {
164 var msg = e.data;
165 switch (msg.command) {
166 case 'start':
167 isolate$log("starting worker: " + msg.id + " " + msg.factoryName);
168 isolate$initializeWorker(msg.id);
169 var runnerObject = (isolate$globalThis[msg.factoryName])();
170 var serializedReplyTo = msg.replyTo;
171 isolate$IsolateEvent.enqueue(new isolate$Isolate(), function() {
172 var replyTo = isolate$deserializeMessage(serializedReplyTo);
173 native__IsolateJsUtil__startIsolate(runnerObject, replyTo);
174 });
175 isolate$runEventLoop();
176 break;
177 case 'spawn-worker':
178 isolate$spawnWorker(msg.factoryName, msg.replyPort);
179 break;
180 case 'message':
181 isolate$sendMessage(msg.workerId, msg.isolateId, msg.portId,
182 msg.msg, msg.replyTo);
183 isolate$runEventLoop();
184 break;
185 case 'close':
186 isolate$log("Closing Worker");
187 isolate$workerRegistry.unregister(sender.id);
188 sender.terminate();
189 isolate$runEventLoop();
190 break;
191 case 'log':
192 isolate$log(msg.msg);
193 break;
194 case 'print':
195 native__IsolateJsUtil__print(msg.msg);
196 break;
197 case 'error':
198 throw msg.msg;
199 break;
200 }
201 }
202
203 if (isolate$supportsWorkers) {
204 isolate$globalThis.onmessage = function(e) {
205 isolate$processWorkerMessage(isolate$mainWorker, e);
206 };
207 }
208
209 // ------- Default Worker -------
210 function isolate$MainWorker() {
211 this.id = isolate$MAIN_WORKER_ID;
212 }
213
214 var isolate$mainWorker = new isolate$MainWorker();
215 isolate$mainWorker.postMessage = function(msg) {
216 isolate$globalThis.postMessage(msg);
217 };
218
219 var isolate$nextFreeIsolateId = 1;
220
221 // Native methods for isolate functionality.
222 /**
223 * @constructor
224 */
225 function isolate$Isolate() {
226 // The isolate ids is only unique within the current worker and frame.
227 this.id = isolate$nextFreeIsolateId++;
228 // When storing information on DOM nodes the isolate's id is not enough.
229 // We instead use a token with a hashcode. The token can be stored in the
230 // DOM node (since it is small and will not keep much data alive).
231 this.token = new Object();
232 this.token.hashCode = (Math.random() * 0xFFFFFFF) >>> 0;
233 this.receivePorts = new isolate$Registry();
234 this.run(function() {
235 // The Dart-to-JavaScript compiler builds a list of functions that
236 // need to run for each isolate to setup the state of static
237 // variables. Run through the list and execute each function.
238 for (var i = 0, len = isolate$inits.length; i < len; i++) {
239 isolate$inits[i]();
240 }
241 });
242 }
243
244 // It is allowed to stack 'run' calls. The stacked isolates can be different.
245 // That is Isolate1.run could call the DOM which then calls Isolate2.run.
246 isolate$Isolate.prototype.run = function(code) {
247 var old = isolate$current;
248 isolate$current = this;
249 var result = null;
250 try {
251 result = code();
252 } finally {
253 isolate$current = old;
254 }
255 return result;
256 };
257
258 isolate$Isolate.prototype.registerReceivePort = function(id, port) {
259 if (this.receivePorts.isEmpty()) {
260 isolate$isolateRegistry.register(this.id, this);
261 }
262 this.receivePorts.register(id, port);
263 };
264
265 isolate$Isolate.prototype.unregisterReceivePort = function(id) {
266 this.receivePorts.unregister(id);
267 if (this.receivePorts.isEmpty()) {
268 isolate$isolateRegistry.unregister(this.id);
269 }
270 };
271
272 isolate$Isolate.prototype.getReceivePortForId = function(id) {
273 return this.receivePorts.get(id);
274 };
275
276 var isolate$events = [];
277
278 /**
279 * @constructor
280 */
281 function isolate$IsolateEvent(isolate, fn) {
282 this.isolate = isolate;
283 this.fn = fn;
284 }
285
286 isolate$IsolateEvent.prototype.process = function() {
287 this.isolate.run(this.fn);
288 };
289
290 isolate$IsolateEvent.enqueue = function(isolate, fn) {
291 isolate$events.push(new isolate$IsolateEvent(isolate, fn));
292 };
293
294 isolate$IsolateEvent.dequeue = function() {
295 if (isolate$events.length == 0) return $Dart$Null;
296 var result = isolate$events[0];
297 isolate$events.splice(0, 1);
298 return result;
299 };
300
301 function native_IsolateNatives__spawn(runnable, light, replyPort) {
302 // TODO(floitsch): throw exception if runnable's class doesn't have a
303 // default constructor.
304 if (isolate$useWorkers && !light) {
305 isolate$startWorker(runnable, replyPort);
306 } else {
307 isolate$startNonWorker(runnable, replyPort);
308 }
309 }
310
311 function isolate$startNonWorker(runnable, replyTo) {
312 // Spawn a new isolate and create the receive port in it.
313 var spawned = new isolate$Isolate();
314
315 // Instead of just running the provided runnable, we create a
316 // new cloned instance of it with a fresh state in the spawned
317 // isolate. This way, we do not get cross-isolate references
318 // through the runnable.
319 var factory = runnable.getIsolateFactory();
320 isolate$IsolateEvent.enqueue(spawned, function() {
321 native__IsolateJsUtil__startIsolate(factory(), replyTo);
322 });
323 }
324
325 // This field is only used by the main worker.
326 var isolate$nextFreeWorkerId = isolate$thisWorkerId + 1;
327
328 var isolate$thisScript = function() {
329 if (!isolate$supportsWorkers || isolate$inWorker) return null;
330
331 // TODO(5334778): Find a cross-platform non-brittle way of getting the
332 // currently running script.
333 var scripts = document.getElementsByTagName('script');
334 // The scripts variable only contains the scripts that have already been
335 // executed. The last one is the currently running script.
336 var script = scripts[scripts.length - 1];
337 var src = script.src;
338 if (!src) {
339 // TODO()
340 src = "FIXME:5407062" + "_" + Math.random().toString();
341 script.src = src;
342 }
343 return src;
344 }();
345
346 function isolate$startWorker(runnable, replyPort) {
347 var factory = runnable.getIsolateFactory();
348 var factoryName = factory.name;
349 var serializedReplyPort = isolate$serializeMessage(replyPort);
350 if (isolate$inWorker) {
351 isolate$mainWorker.postMessage({ command: 'spawn-worker',
352 factoryName: factoryName,
353 replyPort: serializedReplyPort } );
354 } else {
355 isolate$spawnWorker(factoryName, serializedReplyPort);
356 }
357 }
358
359 function isolate$spawnWorker(factoryName, serializedReplyPort) {
360 var worker = new Worker(isolate$thisScript);
361 worker.onmessage = function(e) {
362 isolate$processWorkerMessage(worker, e);
363 };
364 var workerId = isolate$nextFreeWorkerId++;
365 // We also store the id on the worker itself so that we can unregister it.
366 worker.id = workerId;
367 isolate$workerRegistry.register(workerId, worker);
368 worker.postMessage({ command: 'start',
369 id: workerId,
370 replyTo: serializedReplyPort,
371 factoryName: factoryName });
372 }
373
374 function native_SendPortImpl__sendNow(message, replyTo) {
375 if (replyTo !== $Dart$Null && !(replyTo instanceof SendPortImpl$Dart)) {
376 throw "SendPort::send: Illegal replyTo type.";
377 }
378 message = isolate$serializeMessage(message);
379 replyTo = isolate$serializeMessage(replyTo);
380 var workerId = native_SendPortImpl__getWorkerId(this);
381 var isolateId = native_SendPortImpl__getIsolateId(this);
382 var receivePortId = native_SendPortImpl__getReceivePortId(this);
383 isolate$sendMessage(workerId, isolateId, receivePortId, message, replyTo);
384 }
385
386 function isolate$closeWorkerIfNecessary() {
387 if (!isolate$isolateRegistry.isEmpty()) return;
388 isolate$mainWorker.postMessage( { command: 'close' } );
389 }
390
391 function isolate$doOneEventLoopIteration() {
392 var CONTINUE_LOOP = true;
393 var STOP_LOOP = false;
394 var event = isolate$IsolateEvent.dequeue();
395 if (!event) {
396 if (isolate$inWorker) {
397 isolate$closeWorkerIfNecessary();
398 } else if (isolate$isolateRegistry.contains(isolate$rootIsolate.id) &&
399 isolate$workerRegistry.isEmpty() &&
400 !isolate$supportsWorkers && (typeof(window) == 'undefined')) {
401 // No events anymore, but the main-worker still has open receive-ports.
402 // This simulates the VM's behavior (which instead times out).
403 // We only trigger this message when we run on the console (where we
404 // don't have workers). We don't want this check to execute in the browser
405 // where the isolate might still be alive due to DOM callbacks.
406 throw Error("Program exited with open ReceivePorts.");
407 }
408 return STOP_LOOP;
409 } else {
410 event.process();
411 return CONTINUE_LOOP;
412 }
413 }
414
415 function isolate$doRunEventLoop() {
416 if (typeof window != 'undefined' && window.setTimeout) {
417 (function next() {
418 var continueLoop = isolate$doOneEventLoopIteration();
419 if (!continueLoop) return;
420 // TODO(kasperl): It might turn out to be too expensive to call
421 // setTimeout for every single event. This needs more investigation.
422 window.setTimeout(next, 0);
423 })();
424 } else {
425 while (true) {
426 var continueLoop = isolate$doOneEventLoopIteration();
427 if (!continueLoop) break;
428 }
429 }
430 }
431
432 function isolate$runEventLoop() {
433 if (!isolate$inWorker) {
434 isolate$doRunEventLoop();
435 } else {
436 try {
437 isolate$doRunEventLoop();
438 } catch(e) {
439 // TODO(floitsch): try to send stack-trace to the other side.
440 isolate$mainWorker.postMessage({ command: 'error', msg: "" + e });
441 }
442 }
443 }
444
445 function RunEntry(entry, args) {
446 // Don't start the main loop again, if we are in a worker.
447 if (isolate$inWorker) return;
448 var isolate = new isolate$Isolate();
449 isolate$rootIsolate = isolate;
450 isolate$IsolateEvent.enqueue(isolate, function() {
451 entry(args);
452 });
453 isolate$runEventLoop();
454
455 // BUG(5151491): This should not be necessary, but because closures
456 // passed to the DOM as event handlers do not bind their isolate
457 // automatically we try to give them a reasonable context to live in
458 // by having a "default" isolate (the first one created).
459 isolate$current = isolate;
460 }
461
462 // ------- Message Serializing and Deserializing -------
463
464 function native_MessageTraverser__clearAttachedInfo(o) {
465 o['__MessageTraverser__attached_info__'] = (void 0);
466 }
467
468 function native_MessageTraverser__setAttachedInfo(o, info) {
469 o['__MessageTraverser__attached_info__'] = info;
470 }
471
472 function native_MessageTraverser__getAttachedInfo(o) {
473 return o['__MessageTraverser__attached_info__'];
474 }
475
476 function native_Serializer__newJsArray(len) {
477 return new Array(len);
478 }
479
480 function native_Serializer__jsArrayIndexSet(jsArray, index, val) {
481 jsArray[index] = val;
482 }
483
484 function native_Serializer__dartListToJsArrayNoCopy(list) {
485 if (list instanceof Array) {
486 RTT.removeTypeInfo(list);
487 return list;
488 } else {
489 var len = native__ListJsUtil__listLength(list);
490 var array = new Array(len);
491 for (var i = 0; i < len; i++) {
492 array[i] = INDEX$operator(list, i);
493 }
494 return array;
495 }
496 }
497
498 function native_Deserializer__isJsArray(x) {
499 return x instanceof Array;
500 }
501
502 function native_Deserializer__jsArrayIndex(x, index) {
503 return x[index];
504 }
505
506 function native_Deserializer__jsArrayLength(x) {
507 return x.length;
508 }
509
510 function isolate$serializeMessage(message) {
511 if (isolate$useWorkers || isolate$useWorkerSerializationProtocol) {
512 return native__IsolateJsUtil__serializeObject(message);
513 } else {
514 return native__IsolateJsUtil__copyObject(message);
515 }
516 }
517
518 function isolate$deserializeMessage(message) {
519 if (isolate$useWorkers || isolate$useWorkerSerializationProtocol) {
520 return native__IsolateJsUtil__deserializeMessage(message);
521 } else {
522 // Nothing more to do.
523 return message;
524 }
525 }
OLDNEW
« no previous file with comments | « compiler/lib/implementation/date_implementation.js ('k') | compiler/lib/implementation/math_natives.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698