| Index: pkg/browser/lib/interop.js
|
| diff --git a/pkg/browser/lib/interop.js b/pkg/browser/lib/interop.js
|
| index 8577e4f28b8c30aa67270ff78727da5789d0bea0..71af132522e77c5ef3f49b7b27e40535760acc3d 100644
|
| --- a/pkg/browser/lib/interop.js
|
| +++ b/pkg/browser/lib/interop.js
|
| @@ -14,7 +14,7 @@ function ReceivePortSync() {
|
| }
|
|
|
| // Type for remote proxies to Dart objects with dart2js.
|
| -function DartProxy(o) {
|
| +function DartObject(o) {
|
| this.o = o;
|
| }
|
|
|
| @@ -250,17 +250,40 @@ function DartProxy(o) {
|
| return Object.keys(this.map).length;
|
| }
|
|
|
| + var _dartRefPropertyName = "_$dart_ref";
|
| +
|
| + // attempts to add an unenumerable property to o. If that is not allowed
|
| + // it silently fails.
|
| + function _defineProperty(o, name, value) {
|
| + if (Object.isExtensible(o)) {
|
| + try {
|
| + Object.defineProperty(o, name, { 'value': value });
|
| + } catch (e) {
|
| + // object is native and lies about being extensible
|
| + // see https://bugzilla.mozilla.org/show_bug.cgi?id=775185
|
| + }
|
| + }
|
| + }
|
| +
|
| // Adds an object to the table and return an ID for serialization.
|
| - ProxiedObjectTable.prototype.add = function (obj) {
|
| - for (var ref in this.map) {
|
| - var o = this.map[ref];
|
| - if (o === obj) {
|
| - return ref;
|
| + ProxiedObjectTable.prototype.add = function (obj, id) {
|
| + if (id != null) {
|
| + this.map[id] = obj;
|
| + return id;
|
| + } else {
|
| + var ref = obj[_dartRefPropertyName];
|
| + if (ref == null) {
|
| + ref = this.name + '-' + this._nextId++;
|
| + this.map[ref] = obj;
|
| + _defineProperty(obj, _dartRefPropertyName, ref);
|
| }
|
| + return ref;
|
| }
|
| - var ref = this.name + '-' + this._nextId++;
|
| - this.map[ref] = obj;
|
| - return ref;
|
| + }
|
| +
|
| + // Gets the object or function corresponding to this ID.
|
| + ProxiedObjectTable.prototype.contains = function (id) {
|
| + return this.map.hasOwnProperty(id);
|
| }
|
|
|
| // Gets the object or function corresponding to this ID.
|
| @@ -328,7 +351,7 @@ function DartProxy(o) {
|
| proxiedObjectTable._initialize()
|
|
|
| // Type for remote proxies to Dart objects.
|
| - function DartProxy(id, sendPort) {
|
| + function DartObject(id, sendPort) {
|
| this.id = id;
|
| this.port = sendPort;
|
| }
|
| @@ -361,7 +384,7 @@ function DartProxy(o) {
|
| proxiedObjectTable.add(message),
|
| proxiedObjectTable.sendPort ];
|
| }
|
| - } else if (message instanceof DartProxy) {
|
| + } else if (message instanceof DartObject) {
|
| // Remote object proxy.
|
| return [ 'objref', message.id, message.port ];
|
| } else {
|
| @@ -402,6 +425,9 @@ function DartProxy(o) {
|
| return proxiedObjectTable.get(id);
|
| } else {
|
| // Remote function. Forward to its port.
|
| + if (proxiedObjectTable.contains(id)) {
|
| + return proxiedObjectTable.get(id);
|
| + }
|
| var f = function () {
|
| var args = Array.prototype.slice.apply(arguments);
|
| args.splice(0, 0, this);
|
| @@ -413,11 +439,12 @@ function DartProxy(o) {
|
| // Cache the remote id and port.
|
| f._dart_id = id;
|
| f._dart_port = port;
|
| + proxiedObjectTable.add(f, id);
|
| return f;
|
| }
|
| }
|
|
|
| - // Creates a DartProxy to forwards to the remote object.
|
| + // Creates a DartObject to forwards to the remote object.
|
| function deserializeObject(message) {
|
| var id = message[1];
|
| var port = message[2];
|
| @@ -427,7 +454,12 @@ function DartProxy(o) {
|
| return proxiedObjectTable.get(id);
|
| } else {
|
| // Remote object.
|
| - return new DartProxy(id, port);
|
| + if (proxiedObjectTable.contains(id)) {
|
| + return proxiedObjectTable.get(id);
|
| + }
|
| + proxy = new DartObject(id, port);
|
| + proxiedObjectTable.add(proxy, id);
|
| + return proxy;
|
| }
|
| }
|
|
|
| @@ -436,52 +468,16 @@ function DartProxy(o) {
|
| function construct(args) {
|
| args = args.map(deserialize);
|
| var constructor = args[0];
|
| - args = Array.prototype.slice.call(args, 1);
|
| -
|
| - // Until 10 args, the 'new' operator is used. With more arguments we use a
|
| - // generic way that may not work, particularly when the constructor does not
|
| - // have an "apply" method.
|
| - var ret = null;
|
| - if (args.length === 0) {
|
| - ret = new constructor();
|
| - } else if (args.length === 1) {
|
| - ret = new constructor(args[0]);
|
| - } else if (args.length === 2) {
|
| - ret = new constructor(args[0], args[1]);
|
| - } else if (args.length === 3) {
|
| - ret = new constructor(args[0], args[1], args[2]);
|
| - } else if (args.length === 4) {
|
| - ret = new constructor(args[0], args[1], args[2], args[3]);
|
| - } else if (args.length === 5) {
|
| - ret = new constructor(args[0], args[1], args[2], args[3], args[4]);
|
| - } else if (args.length === 6) {
|
| - ret = new constructor(args[0], args[1], args[2], args[3], args[4],
|
| - args[5]);
|
| - } else if (args.length === 7) {
|
| - ret = new constructor(args[0], args[1], args[2], args[3], args[4],
|
| - args[5], args[6]);
|
| - } else if (args.length === 8) {
|
| - ret = new constructor(args[0], args[1], args[2], args[3], args[4],
|
| - args[5], args[6], args[7]);
|
| - } else if (args.length === 9) {
|
| - ret = new constructor(args[0], args[1], args[2], args[3], args[4],
|
| - args[5], args[6], args[7], args[8]);
|
| - } else if (args.length === 10) {
|
| - ret = new constructor(args[0], args[1], args[2], args[3], args[4],
|
| - args[5], args[6], args[7], args[8], args[9]);
|
| - } else {
|
| - // Dummy Type with correct constructor.
|
| - var Type = function(){};
|
| - Type.prototype = constructor.prototype;
|
|
|
| - // Create a new instance
|
| - var instance = new Type();
|
| -
|
| - // Call the original constructor.
|
| - ret = constructor.apply(instance, args);
|
| - ret = Object(ret) === ret ? ret : instance;
|
| - }
|
| - return serialize(ret);
|
| + // The following code solves the problem of invoking a JavaScript
|
| + // constructor with an unknown number arguments.
|
| + // First bind the constructor to the argument list using bind.apply().
|
| + // The first argument to bind() is the binding of 'this', make it 'null'
|
| + // After that, use the JavaScript 'new' operator which overrides any binding
|
| + // of 'this' with the new instance.
|
| + args[0] = null;
|
| + var factoryFunction = constructor.bind.apply(constructor, args);
|
| + return serialize(new factoryFunction());
|
| }
|
|
|
| // Remote handler to return the top-level JavaScript context.
|
|
|