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

Side by Side Diff: tool/input_sdk_patch/isolate_helper.dart

Issue 955513008: cleans up sdk patching so we no longer have unresolved names (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 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
« no previous file with comments | « tool/input_sdk_patch/interceptors.dart ('k') | tool/input_sdk_patch/isolate_serialization.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library _isolate_helper;
6
7 import 'dart:_js_embedded_names' show
8 CLASS_ID_EXTRACTOR,
9 CLASS_FIELDS_EXTRACTOR,
10 CURRENT_SCRIPT,
11 GLOBAL_FUNCTIONS,
12 INITIALIZE_EMPTY_INSTANCE,
13 INSTANCE_FROM_CLASS_ID;
14
15 import 'dart:async';
16 import 'dart:collection' show Queue, HashMap;
17 import 'dart:isolate';
18 import 'dart:_native_typed_data' show NativeByteBuffer, NativeTypedData;
19
20 import 'dart:_js_helper' show
21 Closure,
22 InternalMap,
23 Null,
24 Primitives,
25 convertDartClosureToJS,
26 random64,
27 requiresPreamble;
28
29 import 'dart:_foreign_helper' show DART_CLOSURE_TO_JS,
30 JS,
31 JS_CREATE_ISOLATE,
32 JS_CURRENT_ISOLATE_CONTEXT,
33 JS_CURRENT_ISOLATE,
34 JS_EMBEDDED_GLOBAL,
35 JS_SET_CURRENT_ISOLATE,
36 IsolateContext;
37
38 import 'dart:_interceptors' show Interceptor,
39 JSArray,
40 JSExtendableArray,
41 JSFixedArray,
42 JSIndexable,
43 JSMutableArray,
44 JSObject;
45
46
47 part 'isolate_serialization.dart';
48
49 /**
50 * Called by the compiler to support switching
51 * between isolates when we get a callback from the DOM.
52 */
53 _callInIsolate(_IsolateContext isolate, Function function) {
54 var result = isolate.eval(function);
55 _globalState.topEventLoop.run();
56 return result;
57 }
58
59 /// Marks entering a JavaScript async operation to keep the worker alive.
60 ///
61 /// To be called by library code before starting an async operation controlled
62 /// by the JavaScript event handler.
63 ///
64 /// Also call [leaveJsAsync] in all callback handlers marking the end of that
65 /// async operation (also error handlers) so the worker can be released.
66 ///
67 /// These functions only has to be called for code that can be run from a
68 /// worker-isolate (so not for general dom operations).
69 enterJsAsync() {
70 _globalState.topEventLoop._activeJsAsyncCount++;
71 }
72
73 /// Marks leaving a javascript async operation.
74 ///
75 /// See [enterJsAsync].
76 leaveJsAsync() {
77 _globalState.topEventLoop._activeJsAsyncCount--;
78 assert(_globalState.topEventLoop._activeJsAsyncCount >= 0);
79 }
80
81 /// Returns true if we are currently in a worker context.
82 bool isWorker() => _globalState.isWorker;
83
84 /**
85 * Called by the compiler to fetch the current isolate context.
86 */
87 _IsolateContext _currentIsolate() => _globalState.currentContext;
88
89 /**
90 * Wrapper that takes the dart entry point and runs it within an isolate. The
91 * dart2js compiler will inject a call of the form
92 * [: startRootIsolate(main); :] when it determines that this wrapping
93 * is needed. For single-isolate applications (e.g. hello world), this
94 * call is not emitted.
95 */
96 void startRootIsolate(entry, args) {
97 // The dartMainRunner can inject a new arguments array. We pass the arguments
98 // through a "JS", so that the type-inferrer loses track of it.
99 args = JS("", "#", args);
100 if (args == null) args = [];
101 if (args is! List) {
102 throw new ArgumentError("Arguments to main must be a List: $args");
103 }
104 _globalState = new _Manager(entry);
105
106 // Don't start the main loop again, if we are in a worker.
107 if (_globalState.isWorker) return;
108 final rootContext = new _IsolateContext();
109 _globalState.rootContext = rootContext;
110
111 // BUG(5151491): Setting currentContext should not be necessary, but
112 // because closures passed to the DOM as event handlers do not bind their
113 // isolate automatically we try to give them a reasonable context to live in
114 // by having a "default" isolate (the first one created).
115 _globalState.currentContext = rootContext;
116 if (entry is _MainFunctionArgs) {
117 rootContext.eval(() { entry(args); });
118 } else if (entry is _MainFunctionArgsMessage) {
119 rootContext.eval(() { entry(args, null); });
120 } else {
121 rootContext.eval(entry);
122 }
123 _globalState.topEventLoop.run();
124 }
125
126 /********************************************************
127 Inserted from lib/isolate/dart2js/isolateimpl.dart
128 ********************************************************/
129
130 /**
131 * Concepts used here:
132 *
133 * "manager" - A manager contains one or more isolates, schedules their
134 * execution, and performs other plumbing on their behalf. The isolate
135 * present at the creation of the manager is designated as its "root isolate".
136 * A manager may, for example, be implemented on a web Worker.
137 *
138 * [_Manager] - State present within a manager (exactly once, as a global).
139 *
140 * [_ManagerStub] - A handle held within one manager that allows interaction
141 * with another manager. A target manager may be addressed by zero or more
142 * [_ManagerStub]s.
143 * TODO(ahe): The _ManagerStub concept is broken. It was an attempt
144 * to create a common interface between the native Worker class and
145 * _MainManagerStub.
146 */
147
148 /**
149 * A native object that is shared across isolates. This object is visible to all
150 * isolates running under the same manager (either UI or background web worker).
151 *
152 * This is code that is intended to 'escape' the isolate boundaries in order to
153 * implement the semantics of isolates in JavaScript. Without this we would have
154 * been forced to implement more code (including the top-level event loop) in
155 * JavaScript itself.
156 */
157 // TODO(eub, sigmund): move the "manager" to be entirely in JS.
158 // Running any Dart code outside the context of an isolate gives it
159 // the chance to break the isolate abstraction.
160 _Manager get _globalState => JS("_Manager", "init.globalState");
161
162 set _globalState(_Manager val) {
163 JS("void", "init.globalState = #", val);
164 }
165
166 /** State associated with the current manager. See [globalState]. */
167 // TODO(sigmund): split in multiple classes: global, thread, main-worker states?
168 class _Manager {
169
170 /** Next available isolate id within this [_Manager]. */
171 int nextIsolateId = 0;
172
173 /** id assigned to this [_Manager]. */
174 int currentManagerId = 0;
175
176 /**
177 * Next available manager id. Only used by the main manager to assign a unique
178 * id to each manager created by it.
179 */
180 int nextManagerId = 1;
181
182 /** Context for the currently running [Isolate]. */
183 _IsolateContext currentContext = null;
184
185 /** Context for the root [Isolate] that first run in this [_Manager]. */
186 _IsolateContext rootContext = null;
187
188 /** The top-level event loop. */
189 _EventLoop topEventLoop;
190
191 /** Whether this program is running from the command line. */
192 bool fromCommandLine;
193
194 /** Whether this [_Manager] is running as a web worker. */
195 bool isWorker;
196
197 /** Whether we support spawning web workers. */
198 bool supportsWorkers;
199
200 /**
201 * Whether to use web workers when implementing isolates. Set to false for
202 * debugging/testing.
203 */
204 bool get useWorkers => supportsWorkers;
205
206 /**
207 * Registry of isolates. Isolates must be registered if, and only if, receive
208 * ports are alive. Normally no open receive-ports means that the isolate is
209 * dead, but DOM callbacks could resurrect it.
210 */
211 Map<int, _IsolateContext> isolates;
212
213 /** Reference to the main [_Manager]. Null in the main [_Manager] itself. */
214 _MainManagerStub mainManager;
215
216 /// Registry of active Web Workers. Only used in the main [_Manager].
217 Map<int, dynamic /* Worker */> managers;
218
219 /** The entry point given by [startRootIsolate]. */
220 final Function entry;
221
222 _Manager(this.entry) {
223 _nativeDetectEnvironment();
224 topEventLoop = new _EventLoop();
225 isolates = new Map<int, _IsolateContext>();
226 managers = new Map<int, dynamic>();
227 if (isWorker) { // "if we are not the main manager ourself" is the intent.
228 mainManager = new _MainManagerStub();
229 _nativeInitWorkerMessageHandler();
230 }
231 }
232
233 void _nativeDetectEnvironment() {
234 bool isWindowDefined = globalWindow != null;
235 bool isWorkerDefined = globalWorker != null;
236
237 isWorker = !isWindowDefined && globalPostMessageDefined;
238 supportsWorkers = isWorker
239 || (isWorkerDefined && IsolateNatives.thisScript != null);
240 fromCommandLine = !isWindowDefined && !isWorker;
241 }
242
243 void _nativeInitWorkerMessageHandler() {
244 var function = JS('',
245 "(function (f, a) { return function (e) { f(a, e); }})(#, #)",
246 DART_CLOSURE_TO_JS(IsolateNatives._processWorkerMessage),
247 mainManager);
248 JS("void", r"self.onmessage = #", function);
249 // We ensure dartPrint is defined so that the implementation of the Dart
250 // print method knows what to call.
251 JS('', '''self.dartPrint = self.dartPrint || (function(serialize) {
252 return function (object) {
253 if (self.console && self.console.log) {
254 self.console.log(object)
255 } else {
256 self.postMessage(serialize(object));
257 }
258 }
259 })(#)''', DART_CLOSURE_TO_JS(_serializePrintMessage));
260 }
261
262 static _serializePrintMessage(object) {
263 return _serializeMessage({"command": "print", "msg": object});
264 }
265
266 /**
267 * Close the worker running this code if all isolates are done and
268 * there are no active async JavaScript tasks still running.
269 */
270 void maybeCloseWorker() {
271 if (isWorker
272 && isolates.isEmpty
273 && topEventLoop._activeJsAsyncCount == 0) {
274 mainManager.postMessage(_serializeMessage({'command': 'close'}));
275 }
276 }
277 }
278
279 /** Context information tracked for each isolate. */
280 class _IsolateContext implements IsolateContext {
281 /** Current isolate id. */
282 final int id = _globalState.nextIsolateId++;
283
284 /** Registry of receive ports currently active on this isolate. */
285 final Map<int, RawReceivePortImpl> ports = new Map<int, RawReceivePortImpl>();
286
287 /** Registry of weak receive ports currently active on this isolate. */
288 final Set<int> weakPorts = new Set<int>();
289
290 /** Holds isolate globals (statics and top-level properties). */
291 // native object containing all globals of an isolate.
292 final isolateStatics = JS_CREATE_ISOLATE();
293
294 final RawReceivePortImpl controlPort = new RawReceivePortImpl._controlPort();
295
296 final Capability pauseCapability = new Capability();
297 final Capability terminateCapability = new Capability(); // License to kill.
298
299 /// Boolean flag set when the initial method of the isolate has been executed.
300 ///
301 /// Used to avoid considering the isolate dead when it has no open
302 /// receive ports and no scheduled timers, because it hasn't had time to
303 /// create them yet.
304 bool initialized = false;
305
306 // TODO(lrn): Store these in single "PauseState" object, so they don't take
307 // up as much room when not pausing.
308 bool isPaused = false;
309 List<_IsolateEvent> delayedEvents = [];
310 Set<Capability> pauseTokens = new Set();
311
312 // Container with the "on exit" handler send-ports.
313 var doneHandlers;
314
315 /**
316 * Queue of functions to call when the current event is complete.
317 *
318 * These events are not just put at the front of the event queue, because
319 * they represent control messages, and should be handled even if the
320 * event queue is paused.
321 */
322 var _scheduledControlEvents;
323 bool _isExecutingEvent = false;
324
325 /** Whether uncaught errors are considered fatal. */
326 bool errorsAreFatal = true;
327
328 // Set of ports that listen to uncaught errors.
329 Set<SendPort> errorPorts = new Set();
330
331 _IsolateContext() {
332 this.registerWeak(controlPort._id, controlPort);
333 }
334
335 void addPause(Capability authentification, Capability resume) {
336 if (pauseCapability != authentification) return;
337 if (pauseTokens.add(resume) && !isPaused) {
338 isPaused = true;
339 }
340 _updateGlobalState();
341 }
342
343 void removePause(Capability resume) {
344 if (!isPaused) return;
345 pauseTokens.remove(resume);
346 if (pauseTokens.isEmpty) {
347 while(delayedEvents.isNotEmpty) {
348 _IsolateEvent event = delayedEvents.removeLast();
349 _globalState.topEventLoop.prequeue(event);
350 }
351 isPaused = false;
352 }
353 _updateGlobalState();
354 }
355
356 void addDoneListener(SendPort responsePort) {
357 if (doneHandlers == null) {
358 doneHandlers = [];
359 }
360 // If necessary, we can switch doneHandlers to a Set if it gets larger.
361 // That is not expected to happen in practice.
362 if (doneHandlers.contains(responsePort)) return;
363 doneHandlers.add(responsePort);
364 }
365
366 void removeDoneListener(SendPort responsePort) {
367 if (doneHandlers == null) return;
368 doneHandlers.remove(responsePort);
369 }
370
371 void setErrorsFatal(Capability authentification, bool errorsAreFatal) {
372 if (terminateCapability != authentification) return;
373 this.errorsAreFatal = errorsAreFatal;
374 }
375
376 void handlePing(SendPort responsePort, int pingType) {
377 if (pingType == Isolate.IMMEDIATE ||
378 (pingType == Isolate.BEFORE_NEXT_EVENT &&
379 !_isExecutingEvent)) {
380 responsePort.send(null);
381 return;
382 }
383 void respond() { responsePort.send(null); }
384 if (pingType == Isolate.AS_EVENT) {
385 _globalState.topEventLoop.enqueue(this, respond, "ping");
386 return;
387 }
388 assert(pingType == Isolate.BEFORE_NEXT_EVENT);
389 if (_scheduledControlEvents == null) {
390 _scheduledControlEvents = new Queue();
391 }
392 _scheduledControlEvents.addLast(respond);
393 }
394
395 void handleKill(Capability authentification, int priority) {
396 if (this.terminateCapability != authentification) return;
397 if (priority == Isolate.IMMEDIATE ||
398 (priority == Isolate.BEFORE_NEXT_EVENT &&
399 !_isExecutingEvent)) {
400 kill();
401 return;
402 }
403 if (priority == Isolate.AS_EVENT) {
404 _globalState.topEventLoop.enqueue(this, kill, "kill");
405 return;
406 }
407 assert(priority == Isolate.BEFORE_NEXT_EVENT);
408 if (_scheduledControlEvents == null) {
409 _scheduledControlEvents = new Queue();
410 }
411 _scheduledControlEvents.addLast(kill);
412 }
413
414 void addErrorListener(SendPort port) {
415 errorPorts.add(port);
416 }
417
418 void removeErrorListener(SendPort port) {
419 errorPorts.remove(port);
420 }
421
422 /** Function called with an uncaught error. */
423 void handleUncaughtError(error, StackTrace stackTrace) {
424 // Just print the error if there is no error listener registered.
425 if (errorPorts.isEmpty) {
426 // An uncaught error in the root isolate will terminate the program?
427 if (errorsAreFatal && identical(this, _globalState.rootContext)) {
428 // The error will be rethrown to reach the global scope, so
429 // don't print it.
430 return;
431 }
432 if (JS('bool', 'self.console && self.console.error')) {
433 JS('void', 'self.console.error(#, #)', error, stackTrace);
434 } else {
435 print(error);
436 if (stackTrace != null) print(stackTrace);
437 }
438 return;
439 }
440 List message = new List(2)
441 ..[0] = error.toString()
442 ..[1] = (stackTrace == null) ? null : stackTrace.toString();
443 for (SendPort port in errorPorts) port.send(message);
444 }
445
446 /**
447 * Run [code] in the context of the isolate represented by [this].
448 */
449 dynamic eval(Function code) {
450 var old = _globalState.currentContext;
451 _globalState.currentContext = this;
452 this._setGlobals();
453 var result = null;
454 _isExecutingEvent = true;
455 try {
456 result = code();
457 } catch (e, s) {
458 handleUncaughtError(e, s);
459 if (errorsAreFatal) {
460 kill();
461 // An uncaught error in the root context terminates all isolates.
462 if (identical(this, _globalState.rootContext)) {
463 rethrow;
464 }
465 }
466 } finally {
467 _isExecutingEvent = false;
468 _globalState.currentContext = old;
469 if (old != null) old._setGlobals();
470 if (_scheduledControlEvents != null) {
471 while (_scheduledControlEvents.isNotEmpty) {
472 (_scheduledControlEvents.removeFirst())();
473 }
474 }
475 }
476 return result;
477 }
478
479 void _setGlobals() {
480 JS_SET_CURRENT_ISOLATE(isolateStatics);
481 }
482
483 /**
484 * Handle messages comming in on the control port.
485 *
486 * These events do not go through the event queue.
487 * The `_globalState.currentContext` context is not set to this context
488 * during the handling.
489 */
490 void handleControlMessage(message) {
491 switch (message[0]) {
492 case "pause":
493 addPause(message[1], message[2]);
494 break;
495 case "resume":
496 removePause(message[1]);
497 break;
498 case 'add-ondone':
499 addDoneListener(message[1]);
500 break;
501 case 'remove-ondone':
502 removeDoneListener(message[1]);
503 break;
504 case 'set-errors-fatal':
505 setErrorsFatal(message[1], message[2]);
506 break;
507 case "ping":
508 handlePing(message[1], message[2]);
509 break;
510 case "kill":
511 handleKill(message[1], message[2]);
512 break;
513 case "getErrors":
514 addErrorListener(message[1]);
515 break;
516 case "stopErrors":
517 removeErrorListener(message[1]);
518 break;
519 default:
520 }
521 }
522
523 /** Looks up a port registered for this isolate. */
524 RawReceivePortImpl lookup(int portId) => ports[portId];
525
526 void _addRegistration(int portId, RawReceivePortImpl port) {
527 if (ports.containsKey(portId)) {
528 throw new Exception("Registry: ports must be registered only once.");
529 }
530 ports[portId] = port;
531 }
532
533 /** Registers a port on this isolate. */
534 void register(int portId, RawReceivePortImpl port) {
535 _addRegistration(portId, port);
536 _updateGlobalState();
537 }
538
539 /**
540 * Registers a weak port on this isolate.
541 *
542 * The port does not keep the isolate active.
543 */
544 void registerWeak(int portId, RawReceivePortImpl port) {
545 weakPorts.add(portId);
546 _addRegistration(portId, port);
547 }
548
549 void _updateGlobalState() {
550 if (ports.length - weakPorts.length > 0 || isPaused || !initialized) {
551 _globalState.isolates[id] = this; // indicate this isolate is active
552 } else {
553 kill();
554 }
555 }
556
557 void kill() {
558 if (_scheduledControlEvents != null) {
559 // Kill all pending events.
560 _scheduledControlEvents.clear();
561 }
562 // Stop listening on all ports.
563 // This should happen before sending events to done handlers, in case
564 // we are listening on ourselves.
565 // Closes all ports, including control port.
566 for (var port in ports.values) {
567 port._close();
568 }
569 ports.clear();
570 weakPorts.clear();
571 _globalState.isolates.remove(id); // indicate this isolate is not active
572 errorPorts.clear();
573 if (doneHandlers != null) {
574 for (SendPort port in doneHandlers) {
575 port.send(null);
576 }
577 doneHandlers = null;
578 }
579 }
580
581 /** Unregister a port on this isolate. */
582 void unregister(int portId) {
583 ports.remove(portId);
584 weakPorts.remove(portId);
585 _updateGlobalState();
586 }
587 }
588
589 /** Represent the event loop on a javascript thread (DOM or worker). */
590 class _EventLoop {
591 final Queue<_IsolateEvent> events = new Queue<_IsolateEvent>();
592
593 /// The number of waiting callbacks not controlled by the dart event loop.
594 ///
595 /// This could be timers or http requests. The worker will only be killed if
596 /// this count reaches 0.
597 /// Access this by using [enterJsAsync] before starting a JavaScript async
598 /// operation and [leaveJsAsync] when the callback has fired.
599 int _activeJsAsyncCount = 0;
600
601 _EventLoop();
602
603 void enqueue(isolate, fn, msg) {
604 events.addLast(new _IsolateEvent(isolate, fn, msg));
605 }
606
607 void prequeue(_IsolateEvent event) {
608 events.addFirst(event);
609 }
610
611 _IsolateEvent dequeue() {
612 if (events.isEmpty) return null;
613 return events.removeFirst();
614 }
615
616 void checkOpenReceivePortsFromCommandLine() {
617 if (_globalState.rootContext != null
618 && _globalState.isolates.containsKey(_globalState.rootContext.id)
619 && _globalState.fromCommandLine
620 && _globalState.rootContext.ports.isEmpty) {
621 // We want to reach here only on the main [_Manager] and only
622 // on the command-line. In the browser the isolate might
623 // still be alive due to DOM callbacks, but the presumption is
624 // that on the command-line, no future events can be injected
625 // into the event queue once it's empty. Node has setTimeout
626 // so this presumption is incorrect there. We think(?) that
627 // in d8 this assumption is valid.
628 throw new Exception("Program exited with open ReceivePorts.");
629 }
630 }
631
632 /** Process a single event, if any. */
633 bool runIteration() {
634 final event = dequeue();
635 if (event == null) {
636 checkOpenReceivePortsFromCommandLine();
637 _globalState.maybeCloseWorker();
638 return false;
639 }
640 event.process();
641 return true;
642 }
643
644 /**
645 * Runs multiple iterations of the run-loop. If possible, each iteration is
646 * run asynchronously.
647 */
648 void _runHelper() {
649 if (globalWindow != null) {
650 // Run each iteration from the browser's top event loop.
651 void next() {
652 if (!runIteration()) return;
653 Timer.run(next);
654 }
655 next();
656 } else {
657 // Run synchronously until no more iterations are available.
658 while (runIteration()) {}
659 }
660 }
661
662 /**
663 * Call [_runHelper] but ensure that worker exceptions are propragated.
664 */
665 void run() {
666 if (!_globalState.isWorker) {
667 _runHelper();
668 } else {
669 try {
670 _runHelper();
671 } catch (e, trace) {
672 _globalState.mainManager.postMessage(_serializeMessage(
673 {'command': 'error', 'msg': '$e\n$trace' }));
674 }
675 }
676 }
677 }
678
679 /** An event in the top-level event queue. */
680 class _IsolateEvent {
681 _IsolateContext isolate;
682 Function fn;
683 String message;
684
685 _IsolateEvent(this.isolate, this.fn, this.message);
686
687 void process() {
688 if (isolate.isPaused) {
689 isolate.delayedEvents.add(this);
690 return;
691 }
692 isolate.eval(fn);
693 }
694 }
695
696 /** A stub for interacting with the main manager. */
697 class _MainManagerStub {
698 void postMessage(msg) {
699 // "self" is a way to refer to the global context object that
700 // works in HTML pages and in Web Workers. It does not work in d8
701 // and Firefox jsshell, because that would have been too easy.
702 //
703 // See: http://www.w3.org/TR/workers/#the-global-scope
704 // and: http://www.w3.org/TR/Window/#dfn-self-attribute
705 requiresPreamble();
706 JS("void", r"self.postMessage(#)", msg);
707 }
708 }
709
710 const String _SPAWNED_SIGNAL = "spawned";
711 const String _SPAWN_FAILED_SIGNAL = "spawn failed";
712
713 get globalWindow {
714 requiresPreamble();
715 return JS('', "self.window");
716 }
717
718 get globalWorker {
719 requiresPreamble();
720 return JS('', "self.Worker");
721 }
722 bool get globalPostMessageDefined {
723 requiresPreamble();
724 return JS('bool', "!!self.postMessage");
725 }
726
727 typedef _MainFunction();
728 typedef _MainFunctionArgs(args);
729 typedef _MainFunctionArgsMessage(args, message);
730
731 /// Note: IsolateNatives depends on _globalState which is only set up correctly
732 /// when 'dart:isolate' has been imported.
733 class IsolateNatives {
734
735 // We set [enableSpawnWorker] to true (not null) when calling isolate
736 // primitives that require support for spawning workers. The field starts out
737 // by being null, and dart2js' type inference will track if it can have a
738 // non-null value. So by testing if this value is not null, we generate code
739 // that dart2js knows is dead when worker support isn't needed.
740 // TODO(herhut): Initialize this to false when able to track compile-time
741 // constants.
742 static var enableSpawnWorker;
743
744 static String thisScript = computeThisScript();
745
746 /// Associates an ID with a native worker object.
747 static final Expando<int> workerIds = new Expando<int>();
748
749 /**
750 * The src url for the script tag that loaded this Used to create
751 * JavaScript workers.
752 */
753 static String computeThisScript() {
754 var currentScript = JS_EMBEDDED_GLOBAL('', CURRENT_SCRIPT);
755 if (currentScript != null) {
756 return JS('String', 'String(#.src)', currentScript);
757 }
758 if (Primitives.isD8) return computeThisScriptD8();
759 if (Primitives.isJsshell) return computeThisScriptJsshell();
760 // A worker has no script tag - so get an url from a stack-trace.
761 if (_globalState.isWorker) return computeThisScriptFromTrace();
762 return null;
763 }
764
765 static String computeThisScriptJsshell() {
766 return JS('String|Null', 'thisFilename()');
767 }
768
769 // TODO(ahe): The following is for supporting D8. We should move this code
770 // to a helper library that is only loaded when testing on D8.
771 static String computeThisScriptD8() => computeThisScriptFromTrace();
772
773 static String computeThisScriptFromTrace() {
774 var stack = JS('String|Null', 'new Error().stack');
775 if (stack == null) {
776 // According to Internet Explorer documentation, the stack
777 // property is not set until the exception is thrown. The stack
778 // property was not provided until IE10.
779 stack = JS('String|Null',
780 '(function() {'
781 'try { throw new Error() } catch(e) { return e.stack }'
782 '})()');
783 if (stack == null) throw new UnsupportedError('No stack trace');
784 }
785 var pattern, matches;
786
787 // This pattern matches V8, Chrome, and Internet Explorer stack
788 // traces that look like this:
789 // Error
790 // at methodName (URI:LINE:COLUMN)
791 pattern = JS('',
792 r'new RegExp("^ *at [^(]*\\((.*):[0-9]*:[0-9]*\\)$", "m")');
793
794
795 matches = JS('JSExtendableArray|Null', '#.match(#)', stack, pattern);
796 if (matches != null) return JS('String', '#[1]', matches);
797
798 // This pattern matches Firefox stack traces that look like this:
799 // methodName@URI:LINE
800 pattern = JS('', r'new RegExp("^[^@]*@(.*):[0-9]*$", "m")');
801
802 matches = JS('JSExtendableArray|Null', '#.match(#)', stack, pattern);
803 if (matches != null) return JS('String', '#[1]', matches);
804
805 throw new UnsupportedError('Cannot extract URI from "$stack"');
806 }
807
808 /**
809 * Assume that [e] is a browser message event and extract its message data.
810 * We don't import the dom explicitly so, when workers are disabled, this
811 * library can also run on top of nodejs.
812 */
813 static _getEventData(e) => JS("", "#.data", e);
814
815 /**
816 * Process messages on a worker, either to control the worker instance or to
817 * pass messages along to the isolate running in the worker.
818 */
819 static void _processWorkerMessage(/* Worker */ sender, e) {
820 var msg = _deserializeMessage(_getEventData(e));
821 switch (msg['command']) {
822 case 'start':
823 _globalState.currentManagerId = msg['id'];
824 String functionName = msg['functionName'];
825 Function entryPoint = (functionName == null)
826 ? _globalState.entry
827 : _getJSFunctionFromName(functionName);
828 var args = msg['args'];
829 var message = _deserializeMessage(msg['msg']);
830 var isSpawnUri = msg['isSpawnUri'];
831 var startPaused = msg['startPaused'];
832 var replyTo = _deserializeMessage(msg['replyTo']);
833 var context = new _IsolateContext();
834 _globalState.topEventLoop.enqueue(context, () {
835 _startIsolate(entryPoint, args, message,
836 isSpawnUri, startPaused, replyTo);
837 }, 'worker-start');
838 // Make sure we always have a current context in this worker.
839 // TODO(7907): This is currently needed because we're using
840 // Timers to implement Futures, and this isolate library
841 // implementation uses Futures. We should either stop using
842 // Futures in this library, or re-adapt if Futures get a
843 // different implementation.
844 _globalState.currentContext = context;
845 _globalState.topEventLoop.run();
846 break;
847 case 'spawn-worker':
848 if (enableSpawnWorker != null) handleSpawnWorkerRequest(msg);
849 break;
850 case 'message':
851 SendPort port = msg['port'];
852 // If the port has been closed, we ignore the message.
853 if (port != null) {
854 msg['port'].send(msg['msg']);
855 }
856 _globalState.topEventLoop.run();
857 break;
858 case 'close':
859 _globalState.managers.remove(workerIds[sender]);
860 JS('void', '#.terminate()', sender);
861 _globalState.topEventLoop.run();
862 break;
863 case 'log':
864 _log(msg['msg']);
865 break;
866 case 'print':
867 if (_globalState.isWorker) {
868 _globalState.mainManager.postMessage(
869 _serializeMessage({'command': 'print', 'msg': msg}));
870 } else {
871 print(msg['msg']);
872 }
873 break;
874 case 'error':
875 throw msg['msg'];
876 }
877 }
878
879 static handleSpawnWorkerRequest(msg) {
880 var replyPort = msg['replyPort'];
881 spawn(msg['functionName'], msg['uri'],
882 msg['args'], msg['msg'],
883 false, msg['isSpawnUri'], msg['startPaused']).then((msg) {
884 replyPort.send(msg);
885 }, onError: (String errorMessage) {
886 replyPort.send([_SPAWN_FAILED_SIGNAL, errorMessage]);
887 });
888 }
889
890 /** Log a message, forwarding to the main [_Manager] if appropriate. */
891 static _log(msg) {
892 if (_globalState.isWorker) {
893 _globalState.mainManager.postMessage(
894 _serializeMessage({'command': 'log', 'msg': msg }));
895 } else {
896 try {
897 _consoleLog(msg);
898 } catch (e, trace) {
899 throw new Exception(trace);
900 }
901 }
902 }
903
904 static void _consoleLog(msg) {
905 requiresPreamble();
906 JS("void", r"self.console.log(#)", msg);
907 }
908
909 static _getJSFunctionFromName(String functionName) {
910 var globalFunctionsContainer = JS_EMBEDDED_GLOBAL("", GLOBAL_FUNCTIONS);
911 return JS("", "#[#]()", globalFunctionsContainer, functionName);
912 }
913
914 /**
915 * Get a string name for the function, if possible. The result for
916 * anonymous functions is browser-dependent -- it may be "" or "anonymous"
917 * but you should probably not count on this.
918 */
919 static String _getJSFunctionName(Function f) {
920 return (f is Closure) ? JS("String|Null", r'#.$name', f) : null;
921 }
922
923 /** Create a new JavaScript object instance given its constructor. */
924 static dynamic _allocate(var ctor) {
925 return JS("", "new #()", ctor);
926 }
927
928 static Future<List> spawnFunction(void topLevelFunction(message),
929 var message,
930 bool startPaused) {
931 IsolateNatives.enableSpawnWorker = true;
932 final name = _getJSFunctionName(topLevelFunction);
933 if (name == null) {
934 throw new UnsupportedError(
935 "only top-level functions can be spawned.");
936 }
937 bool isLight = false;
938 bool isSpawnUri = false;
939 return spawn(name, null, null, message, isLight, isSpawnUri, startPaused);
940 }
941
942 static Future<List> spawnUri(Uri uri, List<String> args, var message,
943 bool startPaused) {
944 IsolateNatives.enableSpawnWorker = true;
945 bool isLight = false;
946 bool isSpawnUri = true;
947 return spawn(null, uri.toString(), args, message,
948 isLight, isSpawnUri, startPaused);
949 }
950
951 // TODO(sigmund): clean up above, after we make the new API the default:
952
953 /// If [uri] is `null` it is replaced with the current script.
954 static Future<List> spawn(String functionName, String uri,
955 List<String> args, message,
956 bool isLight, bool isSpawnUri, bool startPaused) {
957 // Assume that the compiled version of the Dart file lives just next to the
958 // dart file.
959 // TODO(floitsch): support precompiled version of dart2js output.
960 if (uri != null && uri.endsWith(".dart")) uri += ".js";
961
962 ReceivePort port = new ReceivePort();
963 Completer<List> completer = new Completer();
964 port.first.then((msg) {
965 if (msg[0] == _SPAWNED_SIGNAL) {
966 completer.complete(msg);
967 } else {
968 assert(msg[0] == _SPAWN_FAILED_SIGNAL);
969 completer.completeError(msg[1]);
970 }
971 });
972
973 SendPort signalReply = port.sendPort;
974
975 if (_globalState.useWorkers && !isLight) {
976 _startWorker(
977 functionName, uri, args, message, isSpawnUri, startPaused,
978 signalReply, (String message) => completer.completeError(message));
979 } else {
980 _startNonWorker(
981 functionName, uri, args, message, isSpawnUri, startPaused,
982 signalReply);
983 }
984 return completer.future;
985 }
986
987 static void _startWorker(
988 String functionName, String uri,
989 List<String> args, message,
990 bool isSpawnUri,
991 bool startPaused,
992 SendPort replyPort,
993 void onError(String message)) {
994 // Make sure that the args list is a fresh generic list. A newly spawned
995 // isolate should be able to assume that the arguments list is an
996 // extendable list.
997 if (args != null) args = new List<String>.from(args);
998 if (_globalState.isWorker) {
999 _globalState.mainManager.postMessage(_serializeMessage({
1000 'command': 'spawn-worker',
1001 'functionName': functionName,
1002 'args': args,
1003 'msg': message,
1004 'uri': uri,
1005 'isSpawnUri': isSpawnUri,
1006 'startPaused': startPaused,
1007 'replyPort': replyPort}));
1008 } else {
1009 _spawnWorker(functionName, uri, args, message,
1010 isSpawnUri, startPaused, replyPort, onError);
1011 }
1012 }
1013
1014 static void _startNonWorker(
1015 String functionName, String uri,
1016 List<String> args, var message,
1017 bool isSpawnUri,
1018 bool startPaused,
1019 SendPort replyPort) {
1020 // TODO(eub): support IE9 using an iframe -- Dart issue 1702.
1021 if (uri != null) {
1022 throw new UnsupportedError(
1023 "Currently spawnUri is not supported without web workers.");
1024 }
1025 // Clone the message to enforce the restrictions we have on isolate
1026 // messages.
1027 message = _clone(message);
1028 // Make sure that the args list is a fresh generic list. A newly spawned
1029 // isolate should be able to assume that the arguments list is an
1030 // extendable list.
1031 if (args != null) args = new List<String>.from(args);
1032 _globalState.topEventLoop.enqueue(new _IsolateContext(), () {
1033 final func = _getJSFunctionFromName(functionName);
1034 _startIsolate(func, args, message, isSpawnUri, startPaused, replyPort);
1035 }, 'nonworker start');
1036 }
1037
1038 static Isolate get currentIsolate {
1039 _IsolateContext context = JS_CURRENT_ISOLATE_CONTEXT();
1040 return new Isolate(context.controlPort.sendPort,
1041 pauseCapability: context.pauseCapability,
1042 terminateCapability: context.terminateCapability);
1043 }
1044
1045 static void _startIsolate(Function topLevel,
1046 List<String> args, message,
1047 bool isSpawnUri,
1048 bool startPaused,
1049 SendPort replyTo) {
1050 _IsolateContext context = JS_CURRENT_ISOLATE_CONTEXT();
1051 Primitives.initializeStatics(context.id);
1052 // The isolate's port does not keep the isolate open.
1053 replyTo.send([_SPAWNED_SIGNAL,
1054 context.controlPort.sendPort,
1055 context.pauseCapability,
1056 context.terminateCapability]);
1057
1058 void runStartFunction() {
1059 context.initialized = true;
1060 if (!isSpawnUri) {
1061 topLevel(message);
1062 } else if (topLevel is _MainFunctionArgsMessage) {
1063 topLevel(args, message);
1064 } else if (topLevel is _MainFunctionArgs) {
1065 topLevel(args);
1066 } else {
1067 topLevel();
1068 }
1069 }
1070
1071 if (startPaused) {
1072 context.addPause(context.pauseCapability, context.pauseCapability);
1073 _globalState.topEventLoop.enqueue(context, runStartFunction,
1074 'start isolate');
1075 } else {
1076 runStartFunction();
1077 }
1078 }
1079
1080 /**
1081 * Spawns an isolate in a worker. [factoryName] is the Javascript constructor
1082 * name for the isolate entry point class.
1083 */
1084 static void _spawnWorker(functionName, String uri,
1085 List<String> args, message,
1086 bool isSpawnUri,
1087 bool startPaused,
1088 SendPort replyPort,
1089 void onError(String message)) {
1090 if (uri == null) uri = thisScript;
1091 final worker = JS('var', 'new Worker(#)', uri);
1092 // Trampolines are used when wanting to call a Dart closure from
1093 // JavaScript. The helper function DART_CLOSURE_TO_JS only accepts
1094 // top-level or static methods, and the trampoline allows us to capture
1095 // arguments and values which can be passed to a static method.
1096 final onerrorTrampoline = JS(
1097 '',
1098 '''
1099 (function (f, u, c) {
1100 return function(e) {
1101 return f(e, u, c)
1102 }
1103 })(#, #, #)''',
1104 DART_CLOSURE_TO_JS(workerOnError), uri, onError);
1105 JS('void', '#.onerror = #', worker, onerrorTrampoline);
1106
1107 var processWorkerMessageTrampoline = JS(
1108 '',
1109 """
1110 (function (f, a) {
1111 return function (e) {
1112 // We can stop listening for errors when the first message is received as
1113 // we only listen for messages to determine if the uri was bad.
1114 e.onerror = null;
1115 return f(a, e);
1116 }
1117 })(#, #)""",
1118 DART_CLOSURE_TO_JS(_processWorkerMessage),
1119 worker);
1120 JS('void', '#.onmessage = #', worker, processWorkerMessageTrampoline);
1121 var workerId = _globalState.nextManagerId++;
1122 // We also store the id on the worker itself so that we can unregister it.
1123 workerIds[worker] = workerId;
1124 _globalState.managers[workerId] = worker;
1125 JS('void', '#.postMessage(#)', worker, _serializeMessage({
1126 'command': 'start',
1127 'id': workerId,
1128 // Note: we serialize replyPort twice because the child worker needs to
1129 // first deserialize the worker id, before it can correctly deserialize
1130 // the port (port deserialization is sensitive to what is the current
1131 // workerId).
1132 'replyTo': _serializeMessage(replyPort),
1133 'args': args,
1134 'msg': _serializeMessage(message),
1135 'isSpawnUri': isSpawnUri,
1136 'startPaused': startPaused,
1137 'functionName': functionName }));
1138 }
1139
1140 static bool workerOnError(
1141 /* Event */ event,
1142 String uri,
1143 void onError(String message)) {
1144 // Attempt to shut up the browser, as the error has been handled. Chrome
1145 // ignores this :-(
1146 JS('void', '#.preventDefault()', event);
1147 String message = JS('String|Null', '#.message', event);
1148 if (message == null) {
1149 // Some browsers, including Chrome, fail to provide a proper error
1150 // event.
1151 message = 'Error spawning worker for $uri';
1152 } else {
1153 message = 'Error spawning worker for $uri ($message)';
1154 }
1155 onError(message);
1156 return true;
1157 }
1158 }
1159
1160 /********************************************************
1161 Inserted from lib/isolate/dart2js/ports.dart
1162 ********************************************************/
1163
1164 /** Common functionality to all send ports. */
1165 abstract class _BaseSendPort implements SendPort {
1166 /** Id for the destination isolate. */
1167 final int _isolateId;
1168
1169 const _BaseSendPort(this._isolateId);
1170
1171 void _checkReplyTo(SendPort replyTo) {
1172 if (replyTo != null
1173 && replyTo is! _NativeJsSendPort
1174 && replyTo is! _WorkerSendPort) {
1175 throw new Exception("SendPort.send: Illegal replyTo port type");
1176 }
1177 }
1178
1179 void send(var message);
1180 bool operator ==(var other);
1181 int get hashCode;
1182 }
1183
1184 /** A send port that delivers messages in-memory via native JavaScript calls. */
1185 class _NativeJsSendPort extends _BaseSendPort implements SendPort {
1186 final RawReceivePortImpl _receivePort;
1187
1188 const _NativeJsSendPort(this._receivePort, int isolateId) : super(isolateId);
1189
1190 void send(var message) {
1191 // Check that the isolate still runs and the port is still open
1192 final isolate = _globalState.isolates[_isolateId];
1193 if (isolate == null) return;
1194 if (_receivePort._isClosed) return;
1195 // Clone the message to enforce the restrictions we have on isolate
1196 // messages.
1197 var msg = _clone(message);
1198 if (isolate.controlPort == _receivePort) {
1199 isolate.handleControlMessage(msg);
1200 return;
1201 }
1202 _globalState.topEventLoop.enqueue(isolate, () {
1203 if (!_receivePort._isClosed) {
1204 _receivePort._add(msg);
1205 }
1206 }, 'receive $message');
1207 }
1208
1209 bool operator ==(var other) => (other is _NativeJsSendPort) &&
1210 (_receivePort == other._receivePort);
1211
1212 int get hashCode => _receivePort._id;
1213 }
1214
1215 /** A send port that delivers messages via worker.postMessage. */
1216 // TODO(eub): abstract this for iframes.
1217 class _WorkerSendPort extends _BaseSendPort implements SendPort {
1218 final int _workerId;
1219 final int _receivePortId;
1220
1221 const _WorkerSendPort(this._workerId, int isolateId, this._receivePortId)
1222 : super(isolateId);
1223
1224 void send(var message) {
1225 final workerMessage = _serializeMessage({
1226 'command': 'message',
1227 'port': this,
1228 'msg': message});
1229
1230 if (_globalState.isWorker) {
1231 // Communication from one worker to another go through the
1232 // main worker.
1233 _globalState.mainManager.postMessage(workerMessage);
1234 } else {
1235 // Deliver the message only if the worker is still alive.
1236 /* Worker */ var manager = _globalState.managers[_workerId];
1237 if (manager != null) {
1238 JS('void', '#.postMessage(#)', manager, workerMessage);
1239 }
1240 }
1241 }
1242
1243 bool operator ==(var other) {
1244 return (other is _WorkerSendPort) &&
1245 (_workerId == other._workerId) &&
1246 (_isolateId == other._isolateId) &&
1247 (_receivePortId == other._receivePortId);
1248 }
1249
1250 int get hashCode {
1251 // TODO(sigmund): use a standard hash when we get one available in corelib.
1252 return (_workerId << 16) ^ (_isolateId << 8) ^ _receivePortId;
1253 }
1254 }
1255
1256 class RawReceivePortImpl implements RawReceivePort {
1257 static int _nextFreeId = 1;
1258
1259 final int _id;
1260 Function _handler;
1261 bool _isClosed = false;
1262
1263 RawReceivePortImpl(this._handler) : _id = _nextFreeId++ {
1264 _globalState.currentContext.register(_id, this);
1265 }
1266
1267 RawReceivePortImpl.weak(this._handler) : _id = _nextFreeId++ {
1268 _globalState.currentContext.registerWeak(_id, this);
1269 }
1270
1271 // Creates the control port of an isolate.
1272 // This is created before the isolate context object itself,
1273 // so it cannot access the static _nextFreeId field.
1274 RawReceivePortImpl._controlPort() : _handler = null, _id = 0;
1275
1276 void set handler(Function newHandler) {
1277 _handler = newHandler;
1278 }
1279
1280 // Close the port without unregistering it.
1281 // Used by an isolate context to close all ports when shutting down.
1282 void _close() {
1283 _isClosed = true;
1284 _handler = null;
1285 }
1286
1287 void close() {
1288 if (_isClosed) return;
1289 _isClosed = true;
1290 _handler = null;
1291 _globalState.currentContext.unregister(_id);
1292 }
1293
1294 void _add(dataEvent) {
1295 if (_isClosed) return;
1296 _handler(dataEvent);
1297 }
1298
1299 SendPort get sendPort {
1300 return new _NativeJsSendPort(this, _globalState.currentContext.id);
1301 }
1302 }
1303
1304 class ReceivePortImpl extends Stream implements ReceivePort {
1305 final RawReceivePort _rawPort;
1306 StreamController _controller;
1307
1308 ReceivePortImpl() : this.fromRawReceivePort(new RawReceivePortImpl(null));
1309
1310 ReceivePortImpl.weak()
1311 : this.fromRawReceivePort(new RawReceivePortImpl.weak(null));
1312
1313 ReceivePortImpl.fromRawReceivePort(this._rawPort) {
1314 _controller = new StreamController(onCancel: close, sync: true);
1315 _rawPort.handler = _controller.add;
1316 }
1317
1318 StreamSubscription listen(void onData(var event),
1319 {Function onError,
1320 void onDone(),
1321 bool cancelOnError}) {
1322 return _controller.stream.listen(onData, onError: onError, onDone: onDone,
1323 cancelOnError: cancelOnError);
1324 }
1325
1326 void close() {
1327 _rawPort.close();
1328 _controller.close();
1329 }
1330
1331 SendPort get sendPort => _rawPort.sendPort;
1332 }
1333
1334 class TimerImpl implements Timer {
1335 final bool _once;
1336 bool _inEventLoop = false;
1337 int _handle;
1338
1339 TimerImpl(int milliseconds, void callback())
1340 : _once = true {
1341 if (milliseconds == 0 && (!hasTimer() || _globalState.isWorker)) {
1342
1343 void internalCallback() {
1344 _handle = null;
1345 callback();
1346 }
1347
1348 // Setting _handle to something different from null indicates that the
1349 // callback has not been run. Hence, the choice of 1 is arbitrary.
1350 _handle = 1;
1351
1352 // This makes a dependency between the async library and the
1353 // event loop of the isolate library. The compiler makes sure
1354 // that the event loop is compiled if [Timer] is used.
1355 // TODO(7907): In case of web workers, we need to use the event
1356 // loop instead of setTimeout, to make sure the futures get executed in
1357 // order.
1358 _globalState.topEventLoop.enqueue(
1359 _globalState.currentContext, internalCallback, 'timer');
1360 _inEventLoop = true;
1361 } else if (hasTimer()) {
1362
1363 void internalCallback() {
1364 _handle = null;
1365 leaveJsAsync();
1366 callback();
1367 }
1368
1369 enterJsAsync();
1370
1371 _handle = JS('int', 'self.setTimeout(#, #)',
1372 convertDartClosureToJS(internalCallback, 0),
1373 milliseconds);
1374 } else {
1375 assert(milliseconds > 0);
1376 throw new UnsupportedError("Timer greater than 0.");
1377 }
1378 }
1379
1380 TimerImpl.periodic(int milliseconds, void callback(Timer timer))
1381 : _once = false {
1382 if (hasTimer()) {
1383 enterJsAsync();
1384 _handle = JS('int', 'self.setInterval(#, #)',
1385 convertDartClosureToJS(() { callback(this); }, 0),
1386 milliseconds);
1387 } else {
1388 throw new UnsupportedError("Periodic timer.");
1389 }
1390 }
1391
1392 void cancel() {
1393 if (hasTimer()) {
1394 if (_inEventLoop) {
1395 throw new UnsupportedError("Timer in event loop cannot be canceled.");
1396 }
1397 if (_handle == null) return;
1398 leaveJsAsync();
1399 if (_once) {
1400 JS('void', 'self.clearTimeout(#)', _handle);
1401 } else {
1402 JS('void', 'self.clearInterval(#)', _handle);
1403 }
1404 _handle = null;
1405 } else {
1406 throw new UnsupportedError("Canceling a timer.");
1407 }
1408 }
1409
1410 bool get isActive => _handle != null;
1411 }
1412
1413 bool hasTimer() {
1414 requiresPreamble();
1415 return JS('', 'self.setTimeout') != null;
1416 }
1417
1418
1419 /**
1420 * Implementation class for [Capability].
1421 *
1422 * It has the same name to make it harder for users to distinguish.
1423 */
1424 class CapabilityImpl implements Capability {
1425 /** Internal random secret identifying the capability. */
1426 final int _id;
1427
1428 CapabilityImpl() : this._internal(random64());
1429
1430 CapabilityImpl._internal(this._id);
1431
1432 int get hashCode {
1433 // Thomas Wang 32 bit Mix.
1434 // http://www.concentric.net/~Ttwang/tech/inthash.htm
1435 // (via https://gist.github.com/badboy/6267743)
1436 int hash = _id;
1437 hash = (hash >> 0) ^ (hash ~/ 0x100000000); // To 32 bit from ~64.
1438 hash = (~hash + (hash << 15)) & 0xFFFFFFFF;
1439 hash ^= hash >> 12;
1440 hash = (hash * 5) & 0xFFFFFFFF;
1441 hash ^= hash >> 4;
1442 hash = (hash * 2057) & 0xFFFFFFFF;
1443 hash ^= hash >> 16;
1444 return hash;
1445 }
1446
1447 bool operator==(Object other) {
1448 if (identical(other, this)) return true;
1449 if (other is CapabilityImpl) {
1450 return identical(_id, other._id);
1451 }
1452 return false;
1453 }
1454 }
OLDNEW
« no previous file with comments | « tool/input_sdk_patch/interceptors.dart ('k') | tool/input_sdk_patch/isolate_serialization.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698