mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 02:37:53 +00:00
Added Dartium support for JS to Dart PortSync calls
I addressed your test comments from the last cl - sorry for missing the last time. Review URL: https://chromiumcodereview.appspot.com//10702110 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@9431 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
6b9e8a0ea1
commit
9c4f5eda7f
|
@ -55,8 +55,8 @@ function ReceivePortSync() {
|
|||
return message;
|
||||
} else if (message instanceof LocalSendPortSync) {
|
||||
return [ 'sendport', 'nativejs', message.receivePort.id ];
|
||||
} else if (message instanceof Dart2JsSendPortSync) {
|
||||
return [ 'sendport', 'dart2js', message.receivePort.isolateId,
|
||||
} else if (message instanceof DartSendPortSync) {
|
||||
return [ 'sendport', 'dart', message.receivePort.isolateId,
|
||||
message.receivePort.portId ];
|
||||
} else {
|
||||
var id = 0;
|
||||
|
@ -106,10 +106,10 @@ function ReceivePortSync() {
|
|||
case 'nativejs':
|
||||
var id = x[2];
|
||||
return new LocalSendPortSync(id);
|
||||
case 'dart2js':
|
||||
case 'dart':
|
||||
var isolateId = x[2];
|
||||
var portId = x[3];
|
||||
return new Dart2JsSendPortSync(isolateId, portId);
|
||||
return new DartSendPortSync(isolateId, portId);
|
||||
default:
|
||||
throw 'Illegal SendPortSync type: $tag';
|
||||
}
|
||||
|
@ -169,21 +169,21 @@ function ReceivePortSync() {
|
|||
return this.receivePort.callback(message);
|
||||
}
|
||||
|
||||
function Dart2JsSendPortSync(isolateId, portId) {
|
||||
function DartSendPortSync(isolateId, portId) {
|
||||
this.isolateId = isolateId;
|
||||
this.portId = portId;
|
||||
}
|
||||
|
||||
Dart2JsSendPortSync.prototype = new SendPortSync();
|
||||
DartSendPortSync.prototype = new SendPortSync();
|
||||
|
||||
function dispatchEvent(receiver, message) {
|
||||
var string = JSON.stringify(message);
|
||||
var event = document.createEvent('TextEvent');
|
||||
event.initTextEvent(receiver, false, false, window, string);
|
||||
window.dispatchEvent(event);
|
||||
window.dispatchEvent(event);
|
||||
}
|
||||
|
||||
Dart2JsSendPortSync.prototype.callSync = function(message) {
|
||||
DartSendPortSync.prototype.callSync = function(message) {
|
||||
var serialized = serialize(message);
|
||||
var target = 'dart-port-' + this.isolateId + '-' + this.portId;
|
||||
// TODO(vsm): Make this re-entrant.
|
||||
|
|
|
@ -22,6 +22,7 @@ $!GENERATED_DART_FILES
|
|||
#source('$AUXILIARY_DIR/../../html/src/shared_FactoryProviders.dart');
|
||||
#source('$AUXILIARY_DIR/../../html/src/dartium_FactoryProviders.dart');
|
||||
#source('$AUXILIARY_DIR/../../html/src/IDBOpenDBRequest.dart');
|
||||
#source('$AUXILIARY_DIR/../../html/src/Isolates.dart');
|
||||
#source('$AUXILIARY_DIR/../../html/src/Measurement.dart');
|
||||
#source('$AUXILIARY_DIR/../../html/src/Device.dart');
|
||||
#source('$AUXILIARY_DIR/../../html/src/_Testing.dart');
|
||||
|
@ -65,54 +66,27 @@ class _Null {
|
|||
|
||||
final _null = const _Null();
|
||||
|
||||
// TODO(vsm): Move this to a separate Isolates.dart file.
|
||||
_serialize(var message) {
|
||||
// TODO(kasperl): Specialize the serializer.
|
||||
return new _Serializer().traverse(message);
|
||||
int _getNewIsolateId() {
|
||||
// TODO(vsm): We need a Dartium native for this.
|
||||
return 1;
|
||||
}
|
||||
|
||||
_deserialize(var message) {
|
||||
return new _JsDeserializer().deserialize(message);
|
||||
}
|
||||
bool _callPortInitialized = false;
|
||||
var _callPortLastResult = null;
|
||||
|
||||
class _JsDeserializer extends _Deserializer {
|
||||
|
||||
deserializeSendPort(List x) {
|
||||
num id = x[1];
|
||||
return new _JsSendPortSync(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class _JsSendPortSync implements SendPortSync {
|
||||
|
||||
static bool initialized = false;
|
||||
static var lastResult = null;
|
||||
|
||||
num _id;
|
||||
_JsSendPortSync(this._id) {
|
||||
if (initialized) return;
|
||||
_callPortSync(num id, var message) {
|
||||
if (!_callPortInitialized) {
|
||||
window.on['js-result'].add((event) {
|
||||
lastResult = JSON.parse(event.data);
|
||||
_callPortLastResult = JSON.parse(event.data);
|
||||
}, false);
|
||||
initialized = true;
|
||||
_callPortInitialized = true;
|
||||
}
|
||||
|
||||
callSync(var message) {
|
||||
var serialized = _serialize(message);
|
||||
var result = _callUsingEvent(_id, serialized);
|
||||
return _deserialize(result);
|
||||
}
|
||||
|
||||
static _callUsingEvent(num id, var message) {
|
||||
var data = JSON.stringify({ 'id': id, 'message': message });
|
||||
var event = document.$dom_createEvent('TextEvent');
|
||||
event.initTextEvent('js-sync-message', false, false, window, data);
|
||||
assert(lastResult == null);
|
||||
window.$dom_dispatchEvent(event);
|
||||
var result = lastResult;
|
||||
lastResult = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
var data = JSON.stringify({ 'id': id, 'message': message });
|
||||
var event = document.$dom_createEvent('TextEvent');
|
||||
event.initTextEvent('js-sync-message', false, false, window, data);
|
||||
assert(_callPortLastResult == null);
|
||||
window.$dom_dispatchEvent(event);
|
||||
var result = _callPortLastResult;
|
||||
_callPortLastResult = null;
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -15,11 +15,16 @@ class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
|
|||
|
||||
IDBFactory get indexedDB() => webkitIndexedDB;
|
||||
|
||||
// TODO(kasperl): Document this.
|
||||
// TODO(kasperl): Document these.
|
||||
lookupPort(String name) {
|
||||
var port = JSON.parse(localStorage['dart-port:$name']);
|
||||
return _deserialize(port);
|
||||
}
|
||||
|
||||
registerPort(String name, var port) {
|
||||
var serialized = _serialize(port);
|
||||
localStorage['dart-port:$name'] = JSON.stringify(serialized);
|
||||
}
|
||||
|
||||
$!MEMBERS
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
// Support for Send/ReceivePortSync.
|
||||
int _getNewIsolateId() native @'''
|
||||
if (!window.$dart$isolate$counter) {
|
||||
window.$dart$isolate$counter = 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
|
|
@ -49,56 +49,29 @@ class _Null {
|
|||
|
||||
final _null = const _Null();
|
||||
|
||||
// TODO(vsm): Move this to a separate Isolates.dart file.
|
||||
_serialize(var message) {
|
||||
// TODO(kasperl): Specialize the serializer.
|
||||
return new _Serializer().traverse(message);
|
||||
int _getNewIsolateId() {
|
||||
// TODO(vsm): We need a Dartium native for this.
|
||||
return 1;
|
||||
}
|
||||
|
||||
_deserialize(var message) {
|
||||
return new _JsDeserializer().deserialize(message);
|
||||
}
|
||||
bool _callPortInitialized = false;
|
||||
var _callPortLastResult = null;
|
||||
|
||||
class _JsDeserializer extends _Deserializer {
|
||||
|
||||
deserializeSendPort(List x) {
|
||||
num id = x[1];
|
||||
return new _JsSendPortSync(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class _JsSendPortSync implements SendPortSync {
|
||||
|
||||
static bool initialized = false;
|
||||
static var lastResult = null;
|
||||
|
||||
num _id;
|
||||
_JsSendPortSync(this._id) {
|
||||
if (initialized) return;
|
||||
_callPortSync(num id, var message) {
|
||||
if (!_callPortInitialized) {
|
||||
window.on['js-result'].add((event) {
|
||||
lastResult = JSON.parse(event.data);
|
||||
_callPortLastResult = JSON.parse(event.data);
|
||||
}, false);
|
||||
initialized = true;
|
||||
_callPortInitialized = true;
|
||||
}
|
||||
|
||||
callSync(var message) {
|
||||
var serialized = _serialize(message);
|
||||
var result = _callUsingEvent(_id, serialized);
|
||||
return _deserialize(result);
|
||||
}
|
||||
|
||||
static _callUsingEvent(num id, var message) {
|
||||
var data = JSON.stringify({ 'id': id, 'message': message });
|
||||
var event = document.$dom_createEvent('TextEvent');
|
||||
event.initTextEvent('js-sync-message', false, false, window, data);
|
||||
assert(lastResult == null);
|
||||
window.$dom_dispatchEvent(event);
|
||||
var result = lastResult;
|
||||
lastResult = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
var data = JSON.stringify({ 'id': id, 'message': message });
|
||||
var event = document.$dom_createEvent('TextEvent');
|
||||
event.initTextEvent('js-sync-message', false, false, window, data);
|
||||
assert(_callPortLastResult == null);
|
||||
window.$dom_dispatchEvent(event);
|
||||
var result = _callPortLastResult;
|
||||
_callPortLastResult = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
class _AbstractWorkerEventsImpl extends _EventsImpl implements AbstractWorkerEvents {
|
||||
|
@ -5205,12 +5178,17 @@ class _DOMWindowImpl extends _EventTargetImpl implements Window {
|
|||
|
||||
IDBFactory get indexedDB() => webkitIndexedDB;
|
||||
|
||||
// TODO(kasperl): Document this.
|
||||
// TODO(kasperl): Document these.
|
||||
lookupPort(String name) {
|
||||
var port = JSON.parse(localStorage['dart-port:$name']);
|
||||
return _deserialize(port);
|
||||
}
|
||||
|
||||
registerPort(String name, var port) {
|
||||
var serialized = _serialize(port);
|
||||
localStorage['dart-port:$name'] = JSON.stringify(serialized);
|
||||
}
|
||||
|
||||
|
||||
_WindowEventsImpl get on() =>
|
||||
new _WindowEventsImpl(this);
|
||||
|
@ -40825,6 +40803,207 @@ interface IDBOpenDBRequestEvents extends IDBRequestEvents {
|
|||
// 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.
|
||||
|
||||
_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', 'dart',
|
||||
ReceivePortSync._isolateId, x._receivePort._portId ];
|
||||
}
|
||||
|
||||
visitRemoteSendPortSync(_RemoteSendPortSync x) {
|
||||
return [ 'sendport', 'dart',
|
||||
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 'dart':
|
||||
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 = _callPortSync(_id, serialized);
|
||||
return _deserialize(result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO(vsm): Differentiate between Dart2Js and 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 Dart ReceivePortSync (tagged 'dart' 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 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);
|
||||
}
|
||||
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
||||
// 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.
|
||||
|
||||
typedef Object ComputeValue();
|
||||
|
||||
class _MeasurementRequest<T> {
|
||||
|
|
|
@ -30,211 +30,17 @@ 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";
|
||||
// Support for Send/ReceivePortSync.
|
||||
int _getNewIsolateId() native @'''
|
||||
if (!window.$dart$isolate$counter) {
|
||||
window.$dart$isolate$counter = 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
class _AbstractWorkerImpl extends _EventTargetImpl implements AbstractWorker native "*AbstractWorker" {
|
||||
|
@ -36895,6 +36701,207 @@ interface IDBOpenDBRequestEvents extends IDBRequestEvents {
|
|||
// 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.
|
||||
|
||||
_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', 'dart',
|
||||
ReceivePortSync._isolateId, x._receivePort._portId ];
|
||||
}
|
||||
|
||||
visitRemoteSendPortSync(_RemoteSendPortSync x) {
|
||||
return [ 'sendport', 'dart',
|
||||
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 'dart':
|
||||
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 = _callPortSync(_id, serialized);
|
||||
return _deserialize(result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO(vsm): Differentiate between Dart2Js and 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 Dart ReceivePortSync (tagged 'dart' 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 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);
|
||||
}
|
||||
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
||||
// 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.
|
||||
|
||||
typedef Object ComputeValue();
|
||||
|
||||
class _MeasurementRequest<T> {
|
||||
|
|
201
lib/html/src/Isolates.dart
Normal file
201
lib/html/src/Isolates.dart
Normal file
|
@ -0,0 +1,201 @@
|
|||
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
||||
// 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.
|
||||
|
||||
_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', 'dart',
|
||||
ReceivePortSync._isolateId, x._receivePort._portId ];
|
||||
}
|
||||
|
||||
visitRemoteSendPortSync(_RemoteSendPortSync x) {
|
||||
return [ 'sendport', 'dart',
|
||||
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 'dart':
|
||||
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 = _callPortSync(_id, serialized);
|
||||
return _deserialize(result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO(vsm): Differentiate between Dart2Js and 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 Dart ReceivePortSync (tagged 'dart' 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 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);
|
||||
}
|
|
@ -11,9 +11,7 @@ measurement_test: Pass, Fail # Issue 1940
|
|||
[ $compiler == none && ($runtime == drt || $runtime == dartium) ]
|
||||
request_animation_frame_test: Skip # drt hangs; requestAnimationFrame not implemented
|
||||
blob_constructor_test: Fail # custom Blob constructor not implemented.
|
||||
js_interop_2_test: Fail # Fix Dartium sendport (de)serialization
|
||||
js_interop_3_test: Fail # Implement ReceivePortSync in Dartium
|
||||
js_interop_4_test: Fail # Implement ReceivePortSync in Dartium
|
||||
js_interop_4_test: Fail # Dart-to-Dart sync calls not implemented.
|
||||
|
||||
[ $compiler == none && ($runtime == drt || $runtime == dartium) && $mode == debug ]
|
||||
native_gc_test: Skip # Issue 2538. Too slow in debug.
|
||||
|
|
|
@ -27,8 +27,6 @@ main() {
|
|||
useHtmlConfiguration();
|
||||
|
||||
test('js-to-dart', () {
|
||||
var done = expectAsync0(() {});
|
||||
|
||||
var fun1 = (message) {
|
||||
Expect.equals('Hello', message['a']);
|
||||
Expect.equals('World', message['b']);
|
||||
|
@ -41,10 +39,10 @@ main() {
|
|||
port1.receive(fun1);
|
||||
window.registerPort('fun1', port1.toSendPort());
|
||||
|
||||
// TODO(vsm): Investigate why this needs to be called asynchronously.
|
||||
var done = expectAsync0(() {});
|
||||
var fun2 = (message) {
|
||||
Expect.equals(42, message);
|
||||
|
||||
// TODO(vsm): Investigate why this needs to be called asynchronously.
|
||||
window.setTimeout(done, 0);
|
||||
};
|
||||
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
#import('dart:html');
|
||||
#import('dart:isolate');
|
||||
|
||||
const testData = const [1, '2', 'true'];
|
||||
final testData = const [1, '2', 'true'];
|
||||
|
||||
// TODO(vsm): Convert all DOM isolate tests to the new syntax.
|
||||
class TestIsolate extends Isolate {
|
||||
TestIsolate() : super();
|
||||
|
||||
|
@ -28,9 +29,9 @@ main() {
|
|||
// Test that our interop scheme also works from Dart to Dart.
|
||||
test('dart-to-dart-same-isolate', () {
|
||||
var fun = expectAsync1((message) {
|
||||
Expect.listEquals(testData, message);
|
||||
return message.length;
|
||||
});
|
||||
Expect.listEquals(testData, message);
|
||||
return message.length;
|
||||
});
|
||||
|
||||
var port1 = new ReceivePortSync();
|
||||
port1.receive(fun);
|
||||
|
@ -43,8 +44,6 @@ main() {
|
|||
|
||||
// Test across isolate boundary.
|
||||
test('dart-to-dart-cross-isolate', () {
|
||||
var done = expectAsync0(() {});
|
||||
|
||||
var fun1 = (message) {
|
||||
Expect.listEquals(testData, message);
|
||||
return message.length;
|
||||
|
@ -54,10 +53,10 @@ main() {
|
|||
port1.receive(fun1);
|
||||
window.registerPort('fun1', port1.toSendPort());
|
||||
|
||||
// TODO(vsm): Investigate why this needs to be called asynchronously.
|
||||
var done = expectAsync0(() {});
|
||||
var fun2 = (message) {
|
||||
Expect.equals(3, message);
|
||||
|
||||
// TODO(vsm): Investigate why this needs to be called asynchronously.
|
||||
window.setTimeout(done, 0);
|
||||
};
|
||||
|
||||
|
@ -65,6 +64,6 @@ main() {
|
|||
port2.receive(fun2);
|
||||
window.registerPort('fun2', port2.toSendPort());
|
||||
|
||||
new TestIsolate().spawn().then((p) {});
|
||||
new TestIsolate().spawn();
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue