Index: lib/isolate/frog/isolateimpl.dart |
diff --git a/frog/lib/isolate.dart b/lib/isolate/frog/isolateimpl.dart |
similarity index 59% |
rename from frog/lib/isolate.dart |
rename to lib/isolate/frog/isolateimpl.dart |
index 8b68c1338bfeaed3c511c6423015af2562920dd4..dab49cee8ba6309e2c4c324a1eeaf517319465b9 100644 |
--- a/frog/lib/isolate.dart |
+++ b/lib/isolate/frog/isolateimpl.dart |
@@ -2,49 +2,31 @@ |
// for details. All rights reserved. Use of this source code is governed by a |
// BSD-style license that can be found in the LICENSE file. |
+/** Implementation of [Isolate2]. */ |
+class _Isolate2Impl implements Isolate2 { |
+ SendPort sendPort; |
+ |
+ _Isolate2Impl(this.sendPort); |
+} |
+ |
/** |
* A native object that is shared across isolates. This object is visible to all |
* isolates running on the same worker (either UI or background web worker). |
* |
* This is code that is intended to 'escape' the isolate boundaries in order to |
- * implement the semantics of friendly isolates in JavaScript. Without this we |
- * would have been forced to implement more code (including the top-level event |
- * loop) in JavaScript itself. |
+ * implement the semantics of isolates in JavaScript. Without this we would have |
+ * been forced to implement more code (including the top-level event loop) in |
+ * JavaScript itself. |
*/ |
-GlobalState get _globalState() native "return \$globalState;"; |
-set _globalState(GlobalState val) native "\$globalState = val;"; |
+GlobalState get globalState() native "return \$globalState;"; |
+set globalState(GlobalState val) native "\$globalState = val;"; |
-/** |
- * Wrapper that takes the dart entry point and runs it within an isolate. The |
- * frog compiler will inject a call of the form [: startRootIsolate(main); :] |
- * when it determines that this wrapping is needed. For single-isolate |
- * applications (e.g. hello world), this call is not emitted. |
- */ |
-void startRootIsolate(entry) { |
- _globalState = new GlobalState(); |
- |
- // Don't start the main loop again, if we are in a worker. |
- 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 |
- // isolate automatically we try to give them a reasonable context to live in |
- // by having a "default" isolate (the first one created). |
- _globalState.currentContext = rootContext; |
- |
- rootContext.eval(entry); |
- _globalState.topEventLoop.run(); |
-} |
- |
-void _fillStatics(context) native @""" |
+void fillStatics(context) native @""" |
$globals = context.isolateStatics; |
$static_init(); |
"""; |
-/** Global state associated with the current worker. See [_globalState]. */ |
+/** Global state associated with the current worker. See [globalState]. */ |
// TODO(sigmund): split in multiple classes: global, thread, main-worker states? |
class GlobalState { |
@@ -102,7 +84,7 @@ class GlobalState { |
MainWorker mainWorker; |
/** Registry of active workers. Only used in the main worker. */ |
- Map<int, var> workers; |
+ Map<int, Dynamic> workers; |
GlobalState() { |
topEventLoop = new EventLoop(); |
@@ -121,12 +103,12 @@ class GlobalState { |
// if workers are supported, treat this as a main worker: |
if (this.supportsWorkers) { |
$globalThis.onmessage = function(e) { |
- IsolateNatives._processWorkerMessage(this.mainWorker, e); |
+ _IsolateNatives._processWorkerMessage(this.mainWorker, e); |
}; |
} |
""" { |
// Declare that the native code has a dependency on this fn. |
- IsolateNatives._processWorkerMessage(null, null); |
+ _IsolateNatives._processWorkerMessage(null, null); |
} |
/** |
@@ -148,51 +130,6 @@ class GlobalState { |
} |
} |
-_serializeMessage(message) { |
- if (_globalState.needSerialization) { |
- return new Serializer().traverse(message); |
- } else { |
- return new Copier().traverse(message); |
- } |
-} |
- |
-_deserializeMessage(message) { |
- if (_globalState.needSerialization) { |
- return new Deserializer().deserialize(message); |
- } else { |
- // Nothing more to do. |
- return message; |
- } |
-} |
- |
-/** Wait until all ports in a message are resolved. */ |
-_waitForPendingPorts(var message, void callback()) { |
- final finder = new PendingSendPortFinder(); |
- finder.traverse(message); |
- Futures.wait(finder.ports).then((_) => callback()); |
-} |
- |
-/** Default worker. */ |
-class MainWorker { |
- int id = 0; |
- void postMessage(msg) native "return \$globalThis.postMessage(msg);"; |
- void set onmessage(f) native "\$globalThis.onmessage = f;"; |
- void terminate() {} |
-} |
- |
-/** |
- * A web worker. This type is also defined in 'dart:dom', but we define it here |
- * to avoid introducing a dependency from corelib to dom. This definition uses a |
- * 'hidden' type (* prefix on the native name) to enforce that the type is |
- * defined dynamically only when web workers are actually available. |
- */ |
-class _Worker native "*Worker" { |
- get id() native "return this.id;"; |
- void set id(i) native "this.id = i;"; |
- void set onmessage(f) native "this.onmessage = f;"; |
- void postMessage(msg) native "return this.postMessage(msg);"; |
-} |
- |
/** Context information tracked for each isolate. */ |
class IsolateContext { |
/** Current isolate id. */ |
@@ -205,7 +142,7 @@ class IsolateContext { |
var isolateStatics; // native object containing all globals of an isolate. |
IsolateContext() { |
- id = _globalState.nextIsolateId++; |
+ id = globalState.nextIsolateId++; |
ports = {}; |
initGlobals(); |
} |
@@ -218,14 +155,14 @@ class IsolateContext { |
* is called from JavaScript (see $wrap_call in corejs.dart). |
*/ |
void eval(Function code) { |
- var old = _globalState.currentContext; |
- _globalState.currentContext = this; |
+ var old = globalState.currentContext; |
+ globalState.currentContext = this; |
this._setGlobals(); |
var result = null; |
try { |
result = code(); |
} finally { |
- _globalState.currentContext = old; |
+ globalState.currentContext = old; |
if (old != null) old._setGlobals(); |
} |
return result; |
@@ -242,18 +179,19 @@ class IsolateContext { |
throw new Exception("Registry: ports must be registered only once."); |
} |
ports[portId] = port; |
- _globalState.isolates[id] = this; // indicate this isolate is active |
+ globalState.isolates[id] = this; // indicate this isolate is active |
} |
/** Unregister a port on this isolate. */ |
void unregister(int portId) { |
ports.remove(portId); |
if (ports.isEmpty()) { |
- _globalState.isolates.remove(id); // indicate this isolate is not active |
+ globalState.isolates.remove(id); // indicate this isolate is not active |
} |
} |
} |
+ |
/** Represent the event loop on a javascript thread (DOM or worker). */ |
class EventLoop { |
Queue<IsolateEvent> events; |
@@ -273,7 +211,7 @@ class EventLoop { |
bool runIteration() { |
final event = dequeue(); |
if (event == null) { |
- _globalState.closeWorker(); |
+ globalState.closeWorker(); |
return false; |
} |
event.process(); |
@@ -310,13 +248,13 @@ class EventLoop { |
* this is called from JavaScript (see $wrap_call in corejs.dart). |
*/ |
void run() { |
- if (!_globalState.isWorker) { |
+ if (!globalState.isWorker) { |
_runHelper(); |
} else { |
try { |
_runHelper(); |
} catch(var e, var trace) { |
- _globalState.mainWorker.postMessage(_serializeMessage( |
+ globalState.mainWorker.postMessage(_serializeMessage( |
{'command': 'error', 'msg': '$e\n$trace' })); |
} |
} |
@@ -336,244 +274,31 @@ class IsolateEvent { |
} |
} |
-/** Common functionality to all send ports. */ |
-class BaseSendPort implements SendPort { |
- /** Id for the destination isolate. */ |
- final int _isolateId; |
- |
- BaseSendPort(this._isolateId); |
- |
- ReceivePortSingleShotImpl call(var message) { |
- final result = new ReceivePortSingleShotImpl(); |
- this.send(message, result.toSendPort()); |
- return result; |
- } |
- |
- static void checkReplyTo(SendPort replyTo) { |
- if (replyTo !== null |
- && replyTo is! NativeJsSendPort |
- && replyTo is! WorkerSendPort |
- && replyTo is! BufferingSendPort) { |
- throw new Exception("SendPort.send: Illegal replyTo port type"); |
- } |
- } |
- |
- // TODO(sigmund): replace the current SendPort.call with the following: |
- //Future call(var message) { |
- // final completer = new Completer(); |
- // final port = new ReceivePort.singleShot(); |
- // send(message, port.toSendPort()); |
- // port.receive((value, ignoreReplyTo) { |
- // if (value is Exception) { |
- // completer.completeException(value); |
- // } else { |
- // completer.complete(value); |
- // } |
- // }); |
- // return completer.future; |
- //} |
- |
- abstract void send(var message, [SendPort replyTo]); |
- abstract bool operator ==(var other); |
- abstract int hashCode(); |
-} |
- |
-/** A send port that delivers messages in-memory via native JavaScript calls. */ |
-class NativeJsSendPort extends BaseSendPort implements SendPort { |
- final ReceivePortImpl _receivePort; |
- |
- const NativeJsSendPort(this._receivePort, int isolateId) : super(isolateId); |
- |
- void send(var message, [SendPort replyTo = null]) { |
- _waitForPendingPorts([message, replyTo], () { |
- checkReplyTo(replyTo); |
- // Check that the isolate still runs and the port is still open |
- final isolate = _globalState.isolates[_isolateId]; |
- if (isolate == null) return; |
- if (_receivePort._callback == null) return; |
- |
- // We force serialization/deserialization as a simple way to ensure |
- // isolate communication restrictions are respected between isolates that |
- // live in the same worker. NativeJsSendPort delivers both messages from |
- // the same worker and messages from other workers. In particular, |
- // messages sent from a worker via a WorkerSendPort are received at |
- // [_processWorkerMessage] and forwarded to a native port. In such cases, |
- // here we'll see [_globalState.currentContext == null]. |
- final shouldSerialize = _globalState.currentContext != null |
- && _globalState.currentContext.id != _isolateId; |
- var msg = message; |
- var reply = replyTo; |
- if (shouldSerialize) { |
- msg = _serializeMessage(msg); |
- reply = _serializeMessage(reply); |
- } |
- _globalState.topEventLoop.enqueue(isolate, () { |
- if (_receivePort._callback != null) { |
- if (shouldSerialize) { |
- msg = _deserializeMessage(msg); |
- reply = _deserializeMessage(reply); |
- } |
- _receivePort._callback(msg, reply); |
- } |
- }, 'receive ' + message); |
- }); |
- } |
- |
- bool operator ==(var other) => (other is NativeJsSendPort) && |
- (_receivePort == other._receivePort); |
- |
- int hashCode() => _receivePort._id; |
-} |
- |
-/** A send port that delivers messages via worker.postMessage. */ |
-class WorkerSendPort extends BaseSendPort implements SendPort { |
- final int _workerId; |
- final int _receivePortId; |
- |
- const WorkerSendPort(this._workerId, int isolateId, this._receivePortId) |
- : super(isolateId); |
- |
- void send(var message, [SendPort replyTo = null]) { |
- _waitForPendingPorts([message, replyTo], () { |
- checkReplyTo(replyTo); |
- final workerMessage = _serializeMessage({ |
- 'command': 'message', |
- 'port': this, |
- 'msg': message, |
- 'replyTo': replyTo}); |
- |
- if (_globalState.isWorker) { |
- // communication from one worker to another go through the main worker: |
- _globalState.mainWorker.postMessage(workerMessage); |
- } else { |
- _globalState.workers[_workerId].postMessage(workerMessage); |
- } |
- }); |
- } |
- |
- bool operator ==(var other) { |
- return (other is WorkerSendPort) && |
- (_workerId == other._workerId) && |
- (_isolateId == other._isolateId) && |
- (_receivePortId == other._receivePortId); |
- } |
- |
- int hashCode() { |
- // TODO(sigmund): use a standard hash when we get one available in corelib. |
- return (_workerId << 16) ^ (_isolateId << 8) ^ _receivePortId; |
- } |
-} |
- |
-/** A port that buffers messages until an underlying port gets resolved. */ |
-class BufferingSendPort extends BaseSendPort implements SendPort { |
- /** Internal counter to assign unique ids to each port. */ |
- static int _idCount = 0; |
- |
- /** For implementing equals and hashcode. */ |
- final int _id; |
- |
- /** Underlying port, when resolved. */ |
- SendPort _port; |
- |
- /** |
- * Future of the underlying port, so that we can detect when this port can be |
- * sent on messages. |
- */ |
- Future<SendPort> _futurePort; |
- |
- /** Pending messages (and reply ports). */ |
- List pending; |
- |
- BufferingSendPort(isolateId, this._futurePort) |
- : super(isolateId), _id = _idCount, pending = [] { |
- _idCount++; |
- _futurePort.then((p) { |
- _port = p; |
- for (final item in pending) { |
- p.send(item['message'], item['replyTo']); |
- } |
- pending = null; |
- }); |
- } |
- |
- BufferingSendPort.fromPort(isolateId, this._port) |
- : super(isolateId), _id = _idCount { |
- _idCount++; |
- } |
- |
- void send(var message, [SendPort replyTo]) { |
- if (_port != null) { |
- _port.send(message, replyTo); |
- } else { |
- pending.add({'message': message, 'replyTo': replyTo}); |
- } |
- } |
- |
- bool operator ==(var other) => other is BufferingSendPort && _id == other._id; |
- int hashCode() => _id; |
-} |
- |
-/** Default factory for receive ports. */ |
-class ReceivePortFactory { |
- factory ReceivePort() { |
- return new ReceivePortImpl(); |
- } |
- |
- factory ReceivePort.singleShot() { |
- return new ReceivePortSingleShotImpl(); |
- } |
-} |
- |
-/** Implementation of a multi-use [ReceivePort] on top of JavaScript. */ |
-class ReceivePortImpl implements ReceivePort { |
- int _id; |
- Function _callback; |
- static int _nextFreeId = 1; |
- |
- ReceivePortImpl() |
- : _id = _nextFreeId++ { |
- _globalState.currentContext.register(_id, this); |
- } |
- |
- void receive(void onMessage(var message, SendPort replyTo)) { |
- _callback = onMessage; |
- } |
- |
- void close() { |
- _callback = null; |
- _globalState.currentContext.unregister(_id); |
- } |
- |
- SendPort toSendPort() { |
- return new NativeJsSendPort(this, _globalState.currentContext.id); |
- } |
+/** Default worker. */ |
+class MainWorker { |
+ int id = 0; |
+ void postMessage(msg) native "return \$globalThis.postMessage(msg);"; |
+ void set onmessage(f) native "\$globalThis.onmessage = f;"; |
+ void terminate() {} |
} |
-/** Implementation of a single-shot [ReceivePort]. */ |
-class ReceivePortSingleShotImpl implements ReceivePort { |
- |
- ReceivePortSingleShotImpl() : _port = new ReceivePortImpl() { } |
- |
- void receive(void callback(var message, SendPort replyTo)) { |
- _port.receive((var message, SendPort replyTo) { |
- _port.close(); |
- callback(message, replyTo); |
- }); |
- } |
- |
- void close() { |
- _port.close(); |
- } |
- |
- SendPort toSendPort() => _port.toSendPort(); |
- |
- final ReceivePortImpl _port; |
+/** |
+ * A web worker. This type is also defined in 'dart:dom', but we define it here |
+ * to avoid introducing a dependency from corelib to dom. This definition uses a |
+ * 'hidden' type (* prefix on the native name) to enforce that the type is |
+ * defined dynamically only when web workers are actually available. |
+ */ |
+class _Worker native "*Worker" { |
+ get id() native "return this.id;"; |
+ void set id(i) native "this.id = i;"; |
+ void set onmessage(f) native "this.onmessage = f;"; |
+ void postMessage(msg) native "return this.postMessage(msg);"; |
} |
final String _SPAWNED_SIGNAL = "spawned"; |
-class IsolateNatives { |
+class _IsolateNatives { |
/** JavaScript-specific implementation to spawn an isolate. */ |
static Future<SendPort> spawn(Isolate isolate, bool isLight) { |
@@ -586,7 +311,7 @@ class IsolateNatives { |
// TODO(floitsch): throw exception if isolate's class doesn't have a |
// default constructor. |
- if (_globalState.useWorkers && !isLight) { |
+ if (globalState.useWorkers && !isLight) { |
_startWorker(isolate, port.toSendPort()); |
} else { |
_startNonWorker(isolate, port.toSendPort()); |
@@ -597,8 +322,8 @@ class IsolateNatives { |
static SendPort _startWorker(Isolate runnable, SendPort replyPort) { |
var factoryName = _getJSConstructorName(runnable); |
- if (_globalState.isWorker) { |
- _globalState.mainWorker.postMessage(_serializeMessage({ |
+ if (globalState.isWorker) { |
+ globalState.mainWorker.postMessage(_serializeMessage({ |
'command': 'spawn-worker', |
'factoryName': factoryName, |
'replyPort': _serializeMessage(replyPort)})); |
@@ -633,7 +358,7 @@ class IsolateNatives { |
src = "FIXME:5407062" + "_" + Math.random().toString(); |
if (script) script.src = src; |
} |
- IsolateNatives._thisScriptCache = src; |
+ _IsolateNatives._thisScriptCache = src; |
return src; |
"""; |
@@ -647,10 +372,10 @@ class IsolateNatives { |
static void _spawnWorker(factoryName, serializedReplyPort) { |
final worker = _newWorker(_thisScript); |
worker.onmessage = (e) { _processWorkerMessage(worker, e); }; |
- var workerId = _globalState.nextWorkerId++; |
+ var workerId = globalState.nextWorkerId++; |
// We also store the id on the worker itself so that we can unregister it. |
worker.id = workerId; |
- _globalState.workers[workerId] = worker; |
+ globalState.workers[workerId] = worker; |
worker.postMessage(_serializeMessage({ |
'command': 'start', |
'id': workerId, |
@@ -674,24 +399,24 @@ class IsolateNatives { |
switch (msg['command']) { |
// TODO(sigmund): delete after we migrate to Isolate2 |
case 'start': |
- _globalState.currentWorkerId = msg['id']; |
+ globalState.currentWorkerId = msg['id']; |
var runnerObject = |
_allocate(_getJSConstructorFromName(msg['factoryName'])); |
var serializedReplyTo = msg['replyTo']; |
- _globalState.topEventLoop.enqueue(new IsolateContext(), function() { |
+ globalState.topEventLoop.enqueue(new IsolateContext(), function() { |
var replyTo = _deserializeMessage(serializedReplyTo); |
_startIsolate(runnerObject, replyTo); |
}, 'worker-start'); |
- _globalState.topEventLoop.run(); |
+ globalState.topEventLoop.run(); |
break; |
case 'start2': |
- _globalState.currentWorkerId = msg['id']; |
+ globalState.currentWorkerId = msg['id']; |
Function entryPoint = _getJSFunctionFromName(msg['functionName']); |
var replyTo = _deserializeMessage(msg['replyTo']); |
- _globalState.topEventLoop.enqueue(new IsolateContext(), function() { |
+ globalState.topEventLoop.enqueue(new IsolateContext(), function() { |
_startIsolate2(entryPoint, replyTo); |
}, 'worker-start'); |
- _globalState.topEventLoop.run(); |
+ globalState.topEventLoop.run(); |
break; |
// TODO(sigmund): delete after we migrate to Isolate2 |
case 'spawn-worker': |
@@ -702,20 +427,20 @@ class IsolateNatives { |
break; |
case 'message': |
msg['port'].send(msg['msg'], msg['replyTo']); |
- _globalState.topEventLoop.run(); |
+ globalState.topEventLoop.run(); |
break; |
case 'close': |
_log("Closing Worker"); |
- _globalState.workers.remove(sender.id); |
+ globalState.workers.remove(sender.id); |
sender.terminate(); |
- _globalState.topEventLoop.run(); |
+ globalState.topEventLoop.run(); |
break; |
case 'log': |
_log(msg['msg']); |
break; |
case 'print': |
- if (_globalState.isWorker) { |
- _globalState.mainWorker.postMessage( |
+ if (globalState.isWorker) { |
+ globalState.mainWorker.postMessage( |
_serializeMessage({'command': 'print', 'msg': msg})); |
} else { |
print(msg['msg']); |
@@ -728,8 +453,8 @@ class IsolateNatives { |
/** Log a message, forwarding to the main worker if appropriate. */ |
static _log(msg) { |
- if (_globalState.isWorker) { |
- _globalState.mainWorker.postMessage( |
+ if (globalState.isWorker) { |
+ globalState.mainWorker.postMessage( |
_serializeMessage({'command': 'log', 'msg': msg })); |
} else { |
try { |
@@ -781,14 +506,14 @@ class IsolateNatives { |
// isolate. This way, we do not get cross-isolate references |
// through the runnable. |
final ctor = _getJSConstructor(runnable); |
- _globalState.topEventLoop.enqueue(spawned, function() { |
+ globalState.topEventLoop.enqueue(spawned, function() { |
_startIsolate(_allocate(ctor), replyTo); |
}, 'nonworker start'); |
} |
/** Given a ready-to-start runnable, start running it. */ |
static void _startIsolate(Isolate isolate, SendPort replyTo) { |
- _fillStatics(_globalState.currentContext); |
+ fillStatics(globalState.currentContext); |
ReceivePort port = new ReceivePort(); |
replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); |
isolate._run(port); |
@@ -806,19 +531,19 @@ class IsolateNatives { |
SendPort signalReply = port.toSendPort(); |
- if (_globalState.useWorkers && !isLight) { |
+ if (globalState.useWorkers && !isLight) { |
_startWorker2(functionName, uri, signalReply); |
} else { |
_startNonWorker2(functionName, uri, signalReply); |
} |
- return new BufferingSendPort( |
- _globalState.currentContext.id, completer.future); |
+ return new _BufferingSendPort( |
+ globalState.currentContext.id, completer.future); |
} |
static SendPort _startWorker2( |
String functionName, String uri, SendPort replyPort) { |
- if (_globalState.isWorker) { |
- _globalState.mainWorker.postMessage(_serializeMessage({ |
+ if (globalState.isWorker) { |
+ globalState.mainWorker.postMessage(_serializeMessage({ |
'command': 'spawn-worker2', |
'functionName': functionName, |
'uri': uri, |
@@ -833,14 +558,14 @@ class IsolateNatives { |
// TODO(eub): support IE9 using an iframe -- Dart issue 1702. |
if (uri != null) throw new UnsupportedOperationException( |
"Currently Isolate2.fromUri is not supported without web workers."); |
- _globalState.topEventLoop.enqueue(new IsolateContext(), function() { |
+ globalState.topEventLoop.enqueue(new IsolateContext(), function() { |
final func = _getJSFunctionFromName(functionName); |
_startIsolate2(func, replyPort); |
}, 'nonworker start'); |
} |
static void _startIsolate2(Function topLevel, SendPort replyTo) { |
- _fillStatics(_globalState.currentContext); |
+ fillStatics(globalState.currentContext); |
final port = new ReceivePort(); |
replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); |
topLevel(port); |
@@ -856,10 +581,10 @@ class IsolateNatives { |
if (uri == null) uri = _thisScript; |
final worker = _newWorker(uri); |
worker.onmessage = (e) { _processWorkerMessage(worker, e); }; |
- var workerId = _globalState.nextWorkerId++; |
+ var workerId = globalState.nextWorkerId++; |
// We also store the id on the worker itself so that we can unregister it. |
worker.id = workerId; |
- _globalState.workers[workerId] = worker; |
+ globalState.workers[workerId] = worker; |
worker.postMessage(_serializeMessage({ |
'command': 'start2', |
'id': workerId, |
@@ -871,27 +596,3 @@ class IsolateNatives { |
'functionName': functionName })); |
} |
} |
- |
-class Isolate2Impl implements Isolate2 { |
- SendPort sendPort; |
- |
- Isolate2Impl(this.sendPort); |
- |
- void stop() {} |
-} |
- |
-class IsolateFactory implements Isolate2 { |
- |
- factory Isolate2.fromCode(Function topLevelFunction) { |
- final name = IsolateNatives._getJSFunctionName(topLevelFunction); |
- if (name == null) { |
- throw new UnsupportedOperationException( |
- "only top-level functions can be spawned."); |
- } |
- return new Isolate2Impl(IsolateNatives._spawn2(name, null, false)); |
- } |
- |
- factory Isolate2.fromUri(String uri) { |
- return new Isolate2Impl(IsolateNatives._spawn2(null, uri, false)); |
- } |
-} |