Index: client/dart.js |
diff --git a/client/dart.js b/client/dart.js |
index 711aeee5702478258e964aad47a196e109154701..722cb4bdf16f4187b0fa0d59fddf99a25e25212c 100644 |
--- a/client/dart.js |
+++ b/client/dart.js |
@@ -46,31 +46,66 @@ function ReceivePortSync() { |
} |
(function() { |
- // Track proxied functions. |
- // TODO: Fix leaks, particularly in dart2js case. |
- var functionRefMap = {}; |
- |
- var nextFunctionRefId = 0; |
- |
- function functionRefDispatch(message) { |
- var id = message[0]; |
- var args = message[1]; |
- var f = functionRefMap[id]; |
- // TODO: Should we capture this automatically? |
- return f.apply(null, args); |
+ function RefTable(name) { |
+ // TODO(vsm): Fix leaks, particularly in dart2js case. |
+ this.name = name; |
+ this.map = {}; |
+ this.id = 0; |
+ this.initialized = false; |
+ } |
+ |
+ RefTable.prototype.nextId = function () { return this.id++; } |
+ |
+ RefTable.prototype.makeRef = function (obj) { |
+ this.initializeOnce(); |
+ // TODO(vsm): Cache refs for each obj. |
+ var ref = this.name + '-' + this.nextId(); |
+ this.map[ref] = obj; |
+ return ref; |
} |
- var functionRefPort = null; |
- |
- function makeFunctionRef(f) { |
- if (functionRefPort == null) { |
- var port = new ReceivePortSync(); |
- port.receive(functionRefDispatch); |
- functionRefPort = port.toSendPort(); |
+ RefTable.prototype.initializeOnce = function () { |
+ if (!this.initialized) { |
+ this.initialize(); |
} |
- var ref = 'func-ref-' + (nextFunctionRefId++); |
- functionRefMap[ref] = f; |
- return ref; |
+ this.initialized = true; |
+ } |
+ |
+ // Overridable initialization on first use hook. |
+ RefTable.prototype.initialize = function () {} |
+ |
+ RefTable.prototype.get = function (ref) { |
+ return this.map[ref]; |
+ } |
+ |
+ function FunctionRefTable() {} |
+ |
+ FunctionRefTable.prototype = new RefTable('func-ref'); |
+ |
+ FunctionRefTable.prototype.initialize = function () { |
+ var receivePort = new ReceivePortSync(); |
+ map = this.map; |
+ receivePort.receive(function (message) { |
+ var id = message[0]; |
+ var args = message[1]; |
+ var f = map[id]; |
+ // TODO(vsm): Should we capture this automatically? |
+ return f.apply(null, args); |
+ }); |
+ this.port = receivePort.toSendPort(); |
+ } |
+ |
+ var functionRefTable = new FunctionRefTable(); |
+ |
+ function JSRefTable() {} |
+ |
+ JSRefTable.prototype = new RefTable('js-ref'); |
+ |
+ var jsRefTable = new JSRefTable(); |
+ |
+ function DartProxy(id) { |
+ // TODO(vsm): Set isolate id. |
+ this.id = id; |
} |
function serialize(message) { |
@@ -107,8 +142,14 @@ function ReceivePortSync() { |
} else if (message instanceof DartSendPortSync) { |
return [ 'sendport', 'dart', message.isolateId, message.portId ]; |
} else if (message instanceof Function) { |
- return [ 'funcref', makeFunctionRef(message), |
- doSerialize(functionRefPort) ]; |
+ return [ 'funcref', functionRefTable.makeRef(message), |
+ doSerialize(functionRefTable.port) ]; |
+ } else if (message instanceof DartProxy) { |
+ return [ 'objref', 'dart', message.id ]; |
+ } else if (message.__proto__ != {}.__proto__) { |
+ // TODO(vsm): Is the above portable and what we want? |
+ // Proxy non-map Objects. |
+ return [ 'objref', 'nativejs', jsRefTable.makeRef(message) ]; |
} else { |
return checkedSerialization(message, function(id) { |
var keys = Object.getOwnPropertyNames(message); |
@@ -127,27 +168,28 @@ function ReceivePortSync() { |
return deserializeHelper(message); |
} |
- function deserializeHelper(x) { |
- if (x == null || |
- typeof(x) == 'string' || |
- typeof(x) == 'number' || |
- typeof(x) == 'boolean') { |
- return x; |
+ function deserializeHelper(message) { |
+ if (message == null || |
+ typeof(message) == 'string' || |
+ typeof(message) == 'number' || |
+ typeof(message) == 'boolean') { |
+ return message; |
} |
- switch (x[0]) { |
- case 'map': return deserializeMap(x); |
- case 'sendport': return deserializeSendPort(x); |
- case 'list': return deserializeList(x); |
- case 'funcref': return deserializeFunction(x); |
+ switch (message[0]) { |
+ case 'map': return deserializeMap(message); |
+ case 'sendport': return deserializeSendPort(message); |
+ case 'list': return deserializeList(message); |
+ case 'funcref': return deserializeFunction(message); |
+ case 'objref': return deserializeProxy(message); |
default: throw 'unimplemented'; |
} |
} |
- function deserializeMap(x) { |
+ function deserializeMap(message) { |
var result = { }; |
- var id = x[1]; |
- var keys = x[2]; |
- var values = x[3]; |
+ var id = message[1]; |
+ var keys = message[2]; |
+ var values = message[3]; |
for (var i = 0, length = keys.length; i < length; i++) { |
var key = deserializeHelper(keys[i]); |
var value = deserializeHelper(values[i]); |
@@ -156,23 +198,23 @@ function ReceivePortSync() { |
return result; |
} |
- function deserializeSendPort(x) { |
- var tag = x[1]; |
+ function deserializeSendPort(message) { |
+ var tag = message[1]; |
switch (tag) { |
case 'nativejs': |
- var id = x[2]; |
+ var id = message[2]; |
return new LocalSendPortSync(ReceivePortSync.map[id]); |
case 'dart': |
- var isolateId = x[2]; |
- var portId = x[3]; |
+ var isolateId = message[2]; |
+ var portId = message[3]; |
return new DartSendPortSync(isolateId, portId); |
default: |
throw 'Illegal SendPortSync type: $tag'; |
} |
} |
- function deserializeList(x) { |
- var values = x[2]; |
+ function deserializeList(message) { |
+ var values = message[2]; |
var length = values.length; |
var result = new Array(length); |
for (var i = 0; i < length; i++) { |
@@ -181,14 +223,26 @@ function ReceivePortSync() { |
return result; |
} |
- function deserializeFunction(x) { |
- var ref = x[1]; |
- var sendPort = deserializeSendPort(x[2]); |
+ function deserializeFunction(message) { |
+ var ref = message[1]; |
+ var sendPort = deserializeSendPort(message[2]); |
// Number of arguments is not used as of now |
// we cannot find it out for Dart function in pure Dart. |
return _makeFunctionFromRef(ref, sendPort); |
} |
+ function deserializeProxy(message) { |
+ var tag = message[1]; |
+ if (tag == 'nativejs') { |
+ var id = message[2]; |
+ return jsRefTable.map[id]; |
+ } else if (tag == 'dart') { |
+ var id = message[2]; |
+ return new DartProxy(id); |
+ } |
+ throw 'Illegal proxy object: ' + message; |
+ } |
+ |
window.registerPort = function(name, port) { |
var stringified = JSON.stringify(serialize(port)); |
window.localStorage['dart-port:' + name] = stringified; |
@@ -274,7 +328,7 @@ function ReceivePortSync() { |
} |
// Leaking implementation. |
- // TODO: provide proper, backend-specific implementation. |
+ // TODO(vsm): provide proper, backend-specific implementation. |
function _makeFunctionFromRef(ref, sendPort) { |
return function() { |
return sendPort.callSync([ref, Array.prototype.slice.call(arguments)]); |