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:
vsm@google.com 2012-07-06 09:33:34 +00:00
parent 6b9e8a0ea1
commit 9c4f5eda7f
10 changed files with 686 additions and 518 deletions

View file

@ -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.

View file

@ -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;
}

View file

@ -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
}

View file

@ -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);
}

View file

@ -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> {

View file

@ -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
View 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);
}

View file

@ -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.

View file

@ -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);
};

View file

@ -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();
});
}