From 3800841285393df3245e203c942ec00a1871d6a8 Mon Sep 17 00:00:00 2001 From: "sigmund@google.com" Date: Fri, 2 Mar 2012 21:01:23 +0000 Subject: [PATCH] isolate in frog: hiding internal implementation classes, couple minor fixes. BUG= TEST= Review URL: https://chromiumcodereview.appspot.com//9562048 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@4900 260f80e4-7a28-3924-810f-c04153c831b5 --- lib/isolate/frog/compiler_hooks.dart | 14 +-- lib/isolate/frog/isolateimpl.dart | 131 +++++++++++++-------------- lib/isolate/frog/messages.dart | 10 +- lib/isolate/frog/ports.dart | 22 ++--- 4 files changed, 87 insertions(+), 90 deletions(-) diff --git a/lib/isolate/frog/compiler_hooks.dart b/lib/isolate/frog/compiler_hooks.dart index 31f4d80eb61..418f18925e2 100644 --- a/lib/isolate/frog/compiler_hooks.dart +++ b/lib/isolate/frog/compiler_hooks.dart @@ -12,20 +12,20 @@ * applications (e.g. hello world), this call is not emitted. */ void startRootIsolate(entry) { - globalState = new GlobalState(); + _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); + 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; + _globalState.currentContext = rootContext; rootContext.eval(entry); - globalState.topEventLoop.run(); + _globalState.topEventLoop.run(); } diff --git a/lib/isolate/frog/isolateimpl.dart b/lib/isolate/frog/isolateimpl.dart index 4fe0fd3e92b..2e096fc7776 100644 --- a/lib/isolate/frog/isolateimpl.dart +++ b/lib/isolate/frog/isolateimpl.dart @@ -11,17 +11,17 @@ * 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;"; -void fillStatics(context) native @""" +void _fillStatics(context) native @""" $globals = context.isolateStatics; $static_init(); """; /** Global state associated with the current worker. See [globalState]. */ // TODO(sigmund): split in multiple classes: global, thread, main-worker states? -class GlobalState { +class _GlobalState { /** Next available isolate id. */ int nextIsolateId = 0; @@ -36,13 +36,13 @@ class GlobalState { int nextWorkerId = 1; /** Context for the currently running [Isolate]. */ - IsolateContext currentContext = null; + _IsolateContext currentContext = null; /** Context for the root [Isolate] that first run in this worker. */ - IsolateContext rootContext = null; + _IsolateContext rootContext = null; /** The top-level event loop. */ - EventLoop topEventLoop; + _EventLoop topEventLoop; /** Whether this program is running in a background worker. */ bool isWorker; @@ -71,19 +71,19 @@ class GlobalState { * ports are alive. Normally no open receive-ports means that the isolate is * dead, but DOM callbacks could resurrect it. */ - Map isolates; + Map isolates; /** Reference to the main worker. */ - MainWorker mainWorker; + _MainWorker mainWorker; /** Registry of active workers. Only used in the main worker. */ Map workers; - GlobalState() { - topEventLoop = new EventLoop(); + _GlobalState() { + topEventLoop = new _EventLoop(); isolates = {}; workers = {}; - mainWorker = new MainWorker(); + mainWorker = new _MainWorker(); _nativeInit(); } @@ -92,10 +92,8 @@ class GlobalState { this.inWindow = typeof(window) !== 'undefined'; this.supportsWorkers = this.isWorker || ((typeof $globalThis['Worker']) != 'undefined'); - - // if workers are supported, treat this as a main worker: - if (this.supportsWorkers) { - $globalThis.onmessage = function(e) { + if (this.isWorker) { + $globalThis.onmessage = function (e) { _IsolateNatives._processWorkerMessage(this.mainWorker, e); }; } @@ -124,7 +122,7 @@ class GlobalState { } /** Context information tracked for each isolate. */ -class IsolateContext { +class _IsolateContext { /** Current isolate id. */ int id; @@ -134,8 +132,8 @@ class IsolateContext { /** Holds isolate globals (statics and top-level properties). */ var isolateStatics; // native object containing all globals of an isolate. - IsolateContext() { - id = globalState.nextIsolateId++; + _IsolateContext() { + id = _globalState.nextIsolateId++; ports = {}; initGlobals(); } @@ -148,14 +146,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; @@ -172,30 +170,30 @@ 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 events; +class _EventLoop { + Queue<_IsolateEvent> events; - EventLoop() : events = new Queue(); + _EventLoop() : events = new Queue<_IsolateEvent>(); void enqueue(isolate, fn, msg) { - events.addLast(new IsolateEvent(isolate, fn, msg)); + events.addLast(new _IsolateEvent(isolate, fn, msg)); } - IsolateEvent dequeue() { + _IsolateEvent dequeue() { if (events.isEmpty()) return null; return events.removeFirst(); } @@ -204,7 +202,7 @@ class EventLoop { bool runIteration() { final event = dequeue(); if (event == null) { - globalState.closeWorker(); + _globalState.closeWorker(); return false; } event.process(); @@ -241,13 +239,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' })); } } @@ -255,12 +253,12 @@ class EventLoop { } /** An event in the top-level event queue. */ -class IsolateEvent { - IsolateContext isolate; +class _IsolateEvent { + _IsolateContext isolate; Function fn; String message; - IsolateEvent(this.isolate, this.fn, this.message); + _IsolateEvent(this.isolate, this.fn, this.message); void process() { isolate.eval(fn); @@ -269,10 +267,9 @@ class IsolateEvent { /** Default worker. */ -class MainWorker { +class _MainWorker { int id = 0; - void postMessage(msg) native "return \$globalThis.postMessage(msg);"; - void set onmessage(f) native "\$globalThis.onmessage = f;"; + void postMessage(msg) native @"$globalThis.postMessage(msg);"; void terminate() {} } @@ -304,7 +301,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()); @@ -315,8 +312,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)})); @@ -368,10 +365,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, @@ -395,24 +392,24 @@ class _IsolateNatives { switch (msg['command']) { // TODO(sigmund): delete after we migrate to the new API 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 the new API case 'spawn-worker': @@ -423,20 +420,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']); @@ -449,8 +446,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 { @@ -522,21 +519,21 @@ class _IsolateNatives { /** Starts a non-worker isolate. */ static SendPort _startNonWorker(Isolate runnable, SendPort replyTo) { // Spawn a new isolate and create the receive port in it. - final spawned = new IsolateContext(); + final spawned = new _IsolateContext(); // Instead of just running the provided runnable, we create a // new cloned instance of it with a fresh state in the spawned // 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); @@ -554,19 +551,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); + _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, @@ -581,14 +578,14 @@ class _IsolateNatives { // TODO(eub): support IE9 using an iframe -- Dart issue 1702. if (uri != null) throw new UnsupportedOperationException( "Currently spawnUri 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); _port = new ReceivePort(); replyTo.send(_SPAWNED_SIGNAL, port.toSendPort()); topLevel(); @@ -609,10 +606,10 @@ class _IsolateNatives { } 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, diff --git a/lib/isolate/frog/messages.dart b/lib/isolate/frog/messages.dart index 9d0f12db4e3..e5d36b26b46 100644 --- a/lib/isolate/frog/messages.dart +++ b/lib/isolate/frog/messages.dart @@ -6,7 +6,7 @@ /** Serialize [message] (or simulate serialization). */ _serializeMessage(message) { - if (globalState.needSerialization) { + if (_globalState.needSerialization) { return new _Serializer().traverse(message); } else { return new _Copier().traverse(message); @@ -15,7 +15,7 @@ _serializeMessage(message) { /** Deserialize [message] (or simulate deserialization). */ _deserializeMessage(message) { - if (globalState.needSerialization) { + if (_globalState.needSerialization) { return new _Deserializer().deserialize(message); } else { // Nothing more to do. @@ -200,7 +200,7 @@ class _Serializer extends _MessageTraverser { } visitNativeJsSendPort(_NativeJsSendPort port) { - return ['sendport', globalState.currentWorkerId, + return ['sendport', _globalState.currentWorkerId, port._isolateId, port._receivePort._id]; } @@ -307,8 +307,8 @@ class _Deserializer { int receivePortId = x[3]; // If two isolates are in the same worker, we use NativeJsSendPorts to // deliver messages directly without using postMessage. - if (workerId == globalState.currentWorkerId) { - var isolate = globalState.isolates[isolateId]; + if (workerId == _globalState.currentWorkerId) { + var isolate = _globalState.isolates[isolateId]; if (isolate == null) return null; // Isolate has been closed. var receivePort = isolate.lookup(receivePortId); return new _NativeJsSendPort(receivePort, isolateId); diff --git a/lib/isolate/frog/ports.dart b/lib/isolate/frog/ports.dart index 5504b7470b7..21f58239180 100644 --- a/lib/isolate/frog/ports.dart +++ b/lib/isolate/frog/ports.dart @@ -54,7 +54,7 @@ class _NativeJsSendPort extends _BaseSendPort implements SendPort { _waitForPendingPorts([message, replyTo], () { checkReplyTo(replyTo); // Check that the isolate still runs and the port is still open - final isolate = globalState.isolates[_isolateId]; + final isolate = _globalState.isolates[_isolateId]; if (isolate == null) return; if (_receivePort._callback == null) return; @@ -64,16 +64,16 @@ class _NativeJsSendPort extends _BaseSendPort implements SendPort { // 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; + // 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, () { + _globalState.topEventLoop.enqueue(isolate, () { if (_receivePort._callback != null) { if (shouldSerialize) { msg = _deserializeMessage(msg); @@ -108,11 +108,11 @@ class _WorkerSendPort extends _BaseSendPort implements SendPort { 'msg': message, 'replyTo': replyTo}); - if (globalState.isWorker) { + if (_globalState.isWorker) { // communication from one worker to another go through the main worker: - globalState.mainWorker.postMessage(workerMessage); + _globalState.mainWorker.postMessage(workerMessage); } else { - globalState.workers[_workerId].postMessage(workerMessage); + _globalState.workers[_workerId].postMessage(workerMessage); } }); } @@ -200,7 +200,7 @@ class _ReceivePortImpl implements ReceivePort { _ReceivePortImpl() : _id = _nextFreeId++ { - globalState.currentContext.register(_id, this); + _globalState.currentContext.register(_id, this); } void receive(void onMessage(var message, SendPort replyTo)) { @@ -209,11 +209,11 @@ class _ReceivePortImpl implements ReceivePort { void close() { _callback = null; - globalState.currentContext.unregister(_id); + _globalState.currentContext.unregister(_id); } SendPort toSendPort() { - return new _NativeJsSendPort(this, globalState.currentContext.id); + return new _NativeJsSendPort(this, _globalState.currentContext.id); } }