Chromium Code Reviews| Index: sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart |
| =================================================================== |
| --- sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart (revision 16029) |
| +++ sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart (working copy) |
| @@ -5,8 +5,9 @@ |
| library _isolate_helper; |
| import 'dart:isolate'; |
| -import 'dart:uri'; |
|
ngeoffray
2012/12/12 15:37:21
For probably bootstrapping problems, having this i
|
| +ReceivePort lazyPort; |
| + |
| /** |
| * Called by the compiler to support switching |
| * between isolates when we get a callback from the DOM. |
| @@ -21,10 +22,6 @@ |
| */ |
| _IsolateContext _currentIsolate() => _globalState.currentContext; |
| -/******************************************************** |
| - Inserted from lib/isolate/dart2js/compiler_hooks.dart |
| - ********************************************************/ |
| - |
| /** |
| * Wrapper that takes the dart entry point and runs it within an isolate. The |
| * dart2js compiler will inject a call of the form |
| @@ -39,7 +36,6 @@ |
| if (_globalState.isWorker) return; |
| final rootContext = new _IsolateContext(); |
| _globalState.rootContext = rootContext; |
| - _fillStatics(rootContext); |
| // BUG(5151491): Setting currentContext should not be necessary, but |
| // because closures passed to the DOM as event handlers do not bind their |
| @@ -84,17 +80,11 @@ |
| // Running any Dart code outside the context of an isolate gives it |
| // the change to break the isolate abstraction. |
| _Manager get _globalState => JS("_Manager", r"$globalState"); |
| + |
| set _globalState(_Manager val) { |
| JS("void", r"$globalState = #", val); |
| } |
| -void _fillStatics(context) { |
| - JS("void", r"$globals = #.isolateStatics", context); |
| - JS("void", r"$static_init()"); |
| -} |
| - |
| -ReceivePort lazyPort; |
| - |
| /** State associated with the current manager. See [globalState]. */ |
| // TODO(sigmund): split in multiple classes: global, thread, main-worker states? |
| class _Manager { |
| @@ -167,22 +157,24 @@ |
| } |
| void _nativeDetectEnvironment() { |
| - isWorker = JS("bool", r"$isWorker"); |
| - supportsWorkers = JS("bool", r"$supportsWorkers"); |
| - fromCommandLine = JS("bool", r"typeof(window) == 'undefined'"); |
| + bool isWindowDefined = JS("String", r"typeof window") != 'undefined'; |
| + bool isPostMessageDefined = |
| + JS("String", r"typeof postMessage") != 'undefined'; |
| + bool isWorkerDefined = JS("String", r"typeof Worker") != 'undefined'; |
| + |
| + isWorker = !isWindowDefined && isPostMessageDefined; |
| + supportsWorkers = isWorker |
| + || (isWorkerDefined && IsolateNatives._thisScript != null); |
|
kasperl
2012/12/13 08:45:12
So this means that if you can't find the script yo
ngeoffray
2012/12/13 11:56:15
Yes :)
|
| + fromCommandLine = !isWindowDefined && !isWorker; |
| } |
| void _nativeInitWorkerMessageHandler() { |
| - JS("void", r""" |
| -$globalThis.onmessage = function (e) { |
| - IsolateNatives._processWorkerMessage(this.mainManager, e); |
| -}"""); |
| + var function = JS('', |
| + "function (e) { #(#, e); }", |
| + DART_CLOSURE_TO_JS(IsolateNatives._processWorkerMessage), |
| + mainManager); |
| + JS("void", r"#.onmessage = #", IsolateNatives.globalThis, function); |
| } |
| - /*: TODO: check that _processWorkerMessage is not discarded while treeshaking. |
| - """ { |
| - IsolateNatives._processWorkerMessage(null, null); |
| - } |
| - */ |
| /** Close the worker running this code if all isolates are done. */ |
| @@ -207,12 +199,9 @@ |
| _IsolateContext() { |
| id = _globalState.nextIsolateId++; |
| ports = new Map<int, ReceivePort>(); |
| - initGlobals(); |
| + isolateStatics = JS_CREATE_ISOLATE(); |
| } |
| - // these are filled lazily the first time the isolate starts running. |
| - void initGlobals() { JS("void", r'$initGlobals(#)', this); } |
| - |
| /** |
| * Run [code] in the context of the isolate represented by [this]. Note this |
| * is called from JavaScript (see $wrap_call in corejs.dart). |
| @@ -231,7 +220,9 @@ |
| return result; |
| } |
| - void _setGlobals() { JS("void", r'$setGlobals(#)', this); } |
| + void _setGlobals() { |
| + JS_SET_CURRENT_ISOLATE(isolateStatics); |
| + } |
| /** Lookup a port registered for this isolate. */ |
| ReceivePort lookup(int portId) => ports[portId]; |
| @@ -300,11 +291,11 @@ |
| * run asynchronously. |
| */ |
| void _runHelper() { |
| - if (hasWindow()) { |
| + if (JS('String', 'typeof window') != 'undefined') { |
|
kasperl
2012/12/13 08:45:12
It would be faster to do: JS('bool', 'typeof windo
ngeoffray
2012/12/13 11:56:15
Faster in which way? We generate the same code for
|
| // Run each iteration from the browser's top event loop. |
| void next() { |
| if (!runIteration()) return; |
| - _window.setTimeout(next, 0); |
| + JS('void', 'window.setTimeout(#, 0)', convertDartClosureToJS(next, 0)); |
| } |
| next(); |
| } else { |
| @@ -360,7 +351,9 @@ |
| void set onmessage(f) { |
| throw new Exception("onmessage should not be set on MainManagerStub"); |
| } |
| - void postMessage(msg) { JS("void", r"$globalThis.postMessage(#)", msg); } |
| + void postMessage(msg) { |
| + JS("void", r"#.postMessage(#)", IsolateNatives.globalThis, msg); |
| + } |
| void terminate() {} // Nothing useful to do here. |
| } |
| @@ -372,23 +365,39 @@ |
| */ |
| // @Native("*Worker"); |
| class _WorkerStub implements _ManagerStub { |
| - get id => JS("var", "#.id", this); |
| + get id => JS("", "#.id", this); |
| void set id(i) { JS("void", "#.id = #", this, i); } |
| void set onmessage(f) { JS("void", "#.onmessage = #", this, f); } |
| - void postMessage(msg) => JS("void", "#.postMessage(#)", this, msg); |
| - // terminate() is implemented by Worker. |
| - void terminate(); |
| + void postMessage(msg) { JS("void", "#.postMessage(#)", this, msg); } |
| + void terminate() { JS("void", "#.terminate()", this); } |
| } |
| const String _SPAWNED_SIGNAL = "spawned"; |
| class IsolateNatives { |
| + static var globalThis = JS('', 'function() { return this; }()'); |
|
kasperl
2012/12/13 08:45:12
How about using lazy initialized statics to cache
ngeoffray
2012/12/13 11:56:15
Done.
|
| + |
| /** |
| * The src url for the script tag that loaded this code. Used to create |
| * JavaScript workers. |
| */ |
| - static String get _thisScript => JS("String", r"$thisScriptUrl"); |
| + static String get _thisScript { |
| + // TODO(5334778): Find a cross-platform non-brittle way of getting the |
|
kasperl
2012/12/13 08:45:12
File a new bug on dartbug.com.
ngeoffray
2012/12/13 11:56:15
Done: http://code.google.com/p/dart/issues/detail?
|
| + // currently running script. |
| + var scripts = JS('=List', r"document.getElementsByTagName('script')"); |
| + // The scripts variable only contains the scripts that have already been |
| + // executed. The last one is the currently running script. |
| + for (var script in scripts) { |
| + var src = JS('String|Null', '# && #.src', script, script); |
| + if (src != null |
| + && !src.endsWith('test_controller.js') |
| + && !new RegExp('client.dart\.js').hasMatch(src)) { |
| + return src; |
| + } |
| + } |
| + return null; |
| + } |
| /** Starts a new worker with the given URL. */ |
| static _WorkerStub _newWorker(url) => JS("_WorkerStub", r"new Worker(#)", url); |
| @@ -398,7 +407,6 @@ |
| * We don't import the dom explicitly so, when workers are disabled, this |
| * library can also run on top of nodejs. |
| */ |
| - //static _getEventData(e) => JS("Object", "#.data", e); |
| static _getEventData(e) => JS("", "#.data", e); |
| /** |
| @@ -461,7 +469,7 @@ |
| } |
| static void _consoleLog(msg) { |
| - JS("void", r"$globalThis.console.log(#)", msg); |
| + JS("void", r"#.console.log(#)", globalThis, msg); |
| } |
| /** |
| @@ -469,7 +477,7 @@ |
| * isolate. |
| */ |
| static dynamic _getJSConstructor(Isolate runnable) { |
| - return JS("Object", "#.constructor", runnable); |
| + return JS("", "#.constructor", runnable); |
| } |
| /** Extract the constructor name of a runnable */ |
| @@ -477,16 +485,16 @@ |
| // TODO(floitsch): is this function still used? If yes, should we use |
| // Primitives.objectTypeName instead? |
| static dynamic _getJSConstructorName(Isolate runnable) { |
| - return JS("Object", "#.constructor.name", runnable); |
| + return JS("", "#.constructor.name", runnable); |
| } |
| /** Find a constructor given its name. */ |
| static dynamic _getJSConstructorFromName(String factoryName) { |
| - return JS("Object", r"$globalThis[#]", factoryName); |
| + return JS("", r"$[#]", factoryName); |
| } |
| static dynamic _getJSFunctionFromName(String functionName) { |
| - return JS("Object", r"$globalThis[#]", functionName); |
| + return JS("", r"$[#]", functionName); |
| } |
| /** |
| @@ -495,12 +503,12 @@ |
| * but you should probably not count on this. |
| */ |
| static String _getJSFunctionName(Function f) { |
| - return JS("Object", r"(#.$name || #)", f, null); |
| + return JS("String|Null", r"(#.$name || #)", f, null); |
| } |
| /** Create a new JavaScript object instance given its constructor. */ |
| static dynamic _allocate(var ctor) { |
| - return JS("Object", "new #()", ctor); |
| + return JS("", "new #()", ctor); |
| } |
| static SendPort spawnFunction(void topLevelFunction()) { |
| @@ -512,9 +520,18 @@ |
| return spawn(name, null, false); |
| } |
| + static SendPort spawnDomFunction(void topLevelFunction()) { |
| + final name = _getJSFunctionName(topLevelFunction); |
| + if (name == null) { |
| + throw new UnsupportedError( |
| + "only top-level functions can be spawned."); |
| + } |
| + return spawn(name, null, true); |
| + } |
| + |
| // TODO(sigmund): clean up above, after we make the new API the default: |
| - static SendPort spawn(String functionName, String uri, bool isLight) { |
| + static spawn(String functionName, String uri, bool isLight) { |
| Completer<SendPort> completer = new Completer<SendPort>(); |
| ReceivePort port = new ReceivePort(); |
| port.receive((msg, SendPort replyPort) { |
| @@ -559,10 +576,8 @@ |
| } |
| static void _startIsolate(Function topLevel, SendPort replyTo) { |
| - _fillStatics(_globalState.currentContext); |
| lazyPort = new ReceivePort(); |
| replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); |
| - |
| topLevel(); |
| } |
| @@ -573,14 +588,11 @@ |
| static void _spawnWorker(functionName, uri, replyPort) { |
| if (functionName == null) functionName = 'main'; |
| if (uri == null) uri = _thisScript; |
| - if (!(new Uri.fromString(uri).isAbsolute())) { |
| - // The constructor of dom workers requires an absolute URL. If we use a |
| - // relative path we will get a DOM exception. |
| - String prefix = _thisScript.substring(0, _thisScript.lastIndexOf('/')); |
| - uri = "$prefix/$uri"; |
| - } |
| final worker = _newWorker(uri); |
| - worker.onmessage = (e) { _processWorkerMessage(worker, e); }; |
| + worker.onmessage = JS('', |
| + 'function(e) { #(#, e); }', |
| + DART_CLOSURE_TO_JS(_processWorkerMessage), |
| + worker); |
| var workerId = _globalState.nextManagerId++; |
| // We also store the id on the worker itself so that we can unregister it. |
| worker.id = workerId; |
| @@ -1217,67 +1229,33 @@ |
| } |
| } |
| -/******************************************************** |
| - Inserted from lib/isolate/dart2js/timer_provider.dart |
| - ********************************************************/ |
| - |
| -// We don't want to import the DOM library just because of window.setTimeout, |
| -// so we reconstruct the Window class here. The only conflict that could happen |
| -// with the other DOMWindow class would be because of subclasses. |
| -// Currently, none of the two Dart classes have subclasses. |
| -typedef void _TimeoutHandler(); |
| - |
| -// @Native("*DOMWindow"); |
| -class _Window { |
| - int setTimeout(_TimeoutHandler handler, int timeout) { |
| - return JS('int', |
| - '#.setTimeout(#, #)', |
| - this, |
| - convertDartClosureToJS(handler, 0), |
| - timeout); |
| - } |
| - |
| - int setInterval(_TimeoutHandler handler, int timeout) { |
| - return JS('int', |
| - '#.setInterval(#, #)', |
| - this, |
| - convertDartClosureToJS(handler, 0), |
| - timeout); |
| - } |
| - |
| - void clearTimeout(int handle) { |
| - JS('void', '#.clearTimeout(#)', this, handle); |
| - } |
| - |
| - void clearInterval(int handle) { |
| - JS('void', '#.clearInterval(#)', this, handle); |
| - } |
| -} |
| - |
| -_Window get _window => |
| - JS('bool', 'typeof window != "undefined"') ? JS('_Window', 'window') : null; |
| - |
| -bool hasWindow() => _window != null; |
| - |
| class TimerImpl implements Timer { |
| final bool _once; |
| int _handle; |
| TimerImpl(int milliseconds, void callback(Timer timer)) |
| : _once = true { |
| - _handle = _window.setTimeout(() => callback(this), milliseconds); |
| + _handle = JS('int', '#.setTimeout(#, #)', |
| + IsolateNatives.globalThis, |
| + convertDartClosureToJS(() => callback(this), 0), |
| + milliseconds); |
| } |
| TimerImpl.repeating(int milliseconds, void callback(Timer timer)) |
| : _once = false { |
| - _handle = _window.setInterval(() => callback(this), milliseconds); |
| + _handle = JS('int', '#.setInterval(#, #)', |
| + IsolateNatives.globalThis, |
| + convertDartClosureToJS(() => callback(this), 0), |
| + milliseconds); |
| } |
| void cancel() { |
| if (_once) { |
| - _window.clearTimeout(_handle); |
| + JS('void', '#.clearTimeout(#)', IsolateNatives.globalThis, _handle); |
| } else { |
| - _window.clearInterval(_handle); |
| + JS('void', '#.clearInterval(#)', IsolateNatives.globalThis, _handle); |
| } |
| } |
| } |
| + |
| +bool hasTimer() => JS('', '#.setTimeout', IsolateNatives.globalThis) != null; |