Index: lib/dom/templates/html/frog/html_frog.darttemplate |
diff --git a/lib/dom/templates/html/frog/html_frog.darttemplate b/lib/dom/templates/html/frog/html_frog.darttemplate |
index ef0cd9497cf1746d8a1568f19c162d7448a3753e..ad5da264fc9a60e4997fe058effa9864e98099fe 100644 |
--- a/lib/dom/templates/html/frog/html_frog.darttemplate |
+++ b/lib/dom/templates/html/frog/html_frog.darttemplate |
@@ -19,6 +19,7 @@ $!GENERATED_DART_FILES |
#source('../../dom/src/_Collections.dart'); |
#source('../../dom/src/_XMLHttpRequestUtils.dart'); |
#source('../../html/src/IDBOpenDBRequest.dart'); |
+#source('../../html/src/Isolates.dart'); |
#source('../../html/src/Measurement.dart'); |
#source('../../html/src/shared_FactoryProviders.dart'); |
#source('../../html/src/frog_DOMImplementation.dart'); |
@@ -49,209 +50,15 @@ ElementList queryAll(String selector) => _document.queryAll(selector); |
class _HTMLElementImpl extends _ElementImpl native "*HTMLElement" { |
} |
-// TODO(vsm): Move this to a separate Isolates.dart file. |
-_serialize(var message) { |
- return new _JsSerializer().traverse(message); |
-} |
- |
-class _JsSerializer extends _Serializer { |
- |
- visitSendPortSync(SendPortSync x) { |
- if (x is _JsSendPortSync) return visitJsSendPortSync(x); |
- if (x is _LocalSendPortSync) return visitLocalSendPortSync(x); |
- if (x is _RemoteSendPortSync) return visitRemoteSendPortSync(x); |
- throw "Illegal underlying port $x"; |
- } |
- |
- visitJsSendPortSync(_JsSendPortSync x) { |
- return [ 'sendport', 'nativejs', x._id ]; |
- } |
- |
- visitLocalSendPortSync(_LocalSendPortSync x) { |
- return [ 'sendport', 'dart2js', |
- ReceivePortSync._isolateId, x._receivePort._portId ]; |
- } |
- |
- visitRemoteSendPortSync(_RemoteSendPortSync x) { |
- return [ 'sendport', 'dart2js', |
- x._receivePort._isolateId, x._receivePort._portId ]; |
- } |
-} |
- |
-_deserialize(var message) { |
- return new _JsDeserializer().deserialize(message); |
-} |
- |
-class _JsDeserializer extends _Deserializer { |
- |
- deserializeSendPort(List x) { |
- String tag = x[1]; |
- switch (tag) { |
- case 'nativejs': |
- num id = x[2]; |
- return new _JsSendPortSync(id); |
- case 'dart2js': |
- num isolateId = x[2]; |
- num portId = x[3]; |
- return ReceivePortSync._lookup(isolateId, portId); |
- default: |
- throw 'Illegal SendPortSync type: $tag'; |
- } |
- } |
- |
-} |
- |
-// The receiver is JS. |
-class _JsSendPortSync implements SendPortSync { |
- |
- num _id; |
- _JsSendPortSync(this._id); |
- |
- callSync(var message) { |
- var serialized = _serialize(message); |
- var result = |
- JS('var', @'ReceivePortSync.dispatchCall(#, #)', _id, serialized); |
- return _deserialize(result); |
- } |
- |
-} |
- |
-// TODO(vsm): Handle Dartium isolates. |
-// The receiver is a different Dart isolate, compiled to JS. |
-class _RemoteSendPortSync implements SendPortSync { |
- |
- int _isolateId; |
- int _portId; |
- _RemoteSendPortSync(this._isolateId, this._portId); |
- |
- callSync(var message) { |
- var serialized = _serialize(message); |
- var result = _call(_isolateId, _portId, serialized); |
- return _deserialize(result); |
- } |
- |
- static _call(int isolateId, int portId, var message) { |
- var target = 'dart-port-$isolateId-$portId'; |
- // TODO(vsm): Make this re-entrant. |
- // TODO(vsm): Set this up set once, on the first call. |
- var source = '$target-result'; |
- var result = null; |
- var listener = (TextEvent e) { |
- result = JSON.parse(e.data); |
- }; |
- window.on[source].add(listener); |
- _dispatchEvent(target, [source, message]); |
- window.on[source].remove(listener); |
- return result; |
+// Support for Send/ReceivePortSync. |
+int _getNewIsolateId() native @''' |
+ if (!window.$dart$isolate$counter) { |
+ window.$dart$isolate$counter = 1; |
} |
-} |
- |
-// The receiver is in the same Dart isolate, compiled to JS. |
-class _LocalSendPortSync implements SendPortSync { |
- |
- ReceivePortSync _receivePort; |
- |
- _LocalSendPortSync._internal(this._receivePort); |
- |
- callSync(var message) { |
- // TODO(vsm): Do a more efficient deep copy. |
- var copy = _deserialize(_serialize(message)); |
- var result = _receivePort._callback(copy); |
- return _deserialize(_serialize(result)); |
- } |
-} |
- |
-// TODO(vsm): Move this to dart:isolate. This will take some |
-// refactoring as there are dependences here on the DOM. Users |
-// interact with this class (or interface if we change it) directly - |
-// new ReceivePortSync. I think most of the DOM logic could be |
-// delayed until the corresponding SendPort is registered on the |
-// window. |
- |
-// A Dart2JS ReceivePortSync (tagged 'dart2js' when serialized) is |
-// identifiable / resolvable by the combination of its isolateid and |
-// portid. When a corresponding SendPort is used within the same |
-// isolate, the _portMap below can be used to obtain the |
-// ReceivePortSync directly. Across isolates (or from JS), an |
-// EventListener can be used to communicate with the port indirectly. |
-class ReceivePortSync { |
- |
- static Map<int, ReceivePortSync> _portMap; |
- static int _portIdCount; |
- static int _cachedIsolateId; |
- |
- num _portId; |
- Function _callback; |
- EventListener _listener; |
- |
- ReceivePortSync() { |
- if (_portIdCount == null) { |
- _portIdCount = 0; |
- _portMap = new Map<int, ReceivePortSync>(); |
- } |
- _portId = _portIdCount++; |
- _portMap[_portId] = this; |
- } |
- |
- static int get _isolateId() { |
- // TODO(vsm): Make this coherent with existing isolate code. |
- if (_cachedIsolateId == null) { |
- _cachedIsolateId = _getNewIsolateId(); |
- } |
- return _cachedIsolateId; |
- } |
- |
- static int _getNewIsolateId() native @''' |
- if (!window.$dart$isolate$counter) { |
- window.$dart$isolate$counter = 1; |
- } |
- return window.$dart$isolate$counter++; |
+ return window.$dart$isolate$counter++; |
'''; |
- static String _getListenerName(isolateId, portId) => |
- 'dart-port-$isolateId-$portId'; |
- String get _listenerName() => _getListenerName(_isolateId, _portId); |
- |
- void receive(callback(var message)) { |
- // Clear old listener. |
- if (_callback != null) { |
- window.on[_listenerName].remove(_listener); |
- } |
- |
- _callback = callback; |
- |
- // Install new listener. |
- var sendport = toSendPort(); |
- _listener = (TextEvent e) { |
- var data = JSON.parse(e.data); |
- var replyTo = data[0]; |
- var message = _deserialize(data[1]); |
- var result = sendport.callSync(message); |
- _dispatchEvent(replyTo, _serialize(result)); |
- }; |
- window.on[_listenerName].add(_listener); |
- } |
- |
- void close() { |
- _portMap.remove(_portId); |
- window.on[_listenerName].remove(_listener); |
- } |
- |
- SendPortSync toSendPort() { |
- return new _LocalSendPortSync._internal(this); |
- } |
- |
- static SendPortSync _lookup(int isolateId, int portId) { |
- if (isolateId == _isolateId) { |
- return _portMap[portId].toSendPort(); |
- } else { |
- return new _RemoteSendPortSync(isolateId, portId); |
- } |
- } |
-} |
- |
-void _dispatchEvent(String receiver, var message) { |
- var event = document.$dom_createEvent('TextEvent'); |
- event.initTextEvent(receiver, false, false, window, JSON.stringify(message)); |
- window.$dom_dispatchEvent(event); |
+// Fast path to invoke JS send port. |
+_callPortSync(int id, message) { |
+ return JS('var', @'ReceivePortSync.dispatchCall(#, #)', id, message); |
} |