Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: pkg/browser/lib/interop.js

Issue 26270003: Cleanup JS() expressions. New Constructor for JsObject that preserves the correct prototype. Type c… (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | sdk/lib/js/dart2js/js_dart2js.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 // --------------------------------------------------------------------------- 5 // ---------------------------------------------------------------------------
6 // Support for JS interoperability 6 // Support for JS interoperability
7 // --------------------------------------------------------------------------- 7 // ---------------------------------------------------------------------------
8 function SendPortSync() { 8 function SendPortSync() {
9 } 9 }
10 10
11 function ReceivePortSync() { 11 function ReceivePortSync() {
12 this.id = ReceivePortSync.id++; 12 this.id = ReceivePortSync.id++;
13 ReceivePortSync.map[this.id] = this; 13 ReceivePortSync.map[this.id] = this;
14 } 14 }
15 15
16 // Type for remote proxies to Dart objects with dart2js. 16 // Type for remote proxies to Dart objects with dart2js.
17 function DartProxy(o) { 17 function DartObject(o) {
18 this.o = o; 18 this.o = o;
19 } 19 }
20 20
21 (function() { 21 (function() {
22 // Serialize the following types as follows: 22 // Serialize the following types as follows:
23 // - primitives / null: unchanged 23 // - primitives / null: unchanged
24 // - lists: [ 'list', internal id, list of recursively serialized elements ] 24 // - lists: [ 'list', internal id, list of recursively serialized elements ]
25 // - maps: [ 'map', internal id, map of keys and recursively serialized value s ] 25 // - maps: [ 'map', internal id, map of keys and recursively serialized value s ]
26 // - send ports: [ 'sendport', type, isolate id, port id ] 26 // - send ports: [ 'sendport', type, isolate id, port id ]
27 // 27 //
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 this.port = new ReceivePortSync(); 243 this.port = new ReceivePortSync();
244 this.sendPort = this.port.toSendPort(); 244 this.sendPort = this.port.toSendPort();
245 } 245 }
246 246
247 // Number of valid IDs. This is the number of objects (global and local) 247 // Number of valid IDs. This is the number of objects (global and local)
248 // kept alive by this table. 248 // kept alive by this table.
249 ProxiedObjectTable.prototype.count = function () { 249 ProxiedObjectTable.prototype.count = function () {
250 return Object.keys(this.map).length; 250 return Object.keys(this.map).length;
251 } 251 }
252 252
253 // Adds an object to the table and return an ID for serialization. 253 var _dartRefPropertyName = "_$dart_ref";
254 ProxiedObjectTable.prototype.add = function (obj) { 254
255 for (var ref in this.map) { 255 // attempts to add an unenumerable property to o. If that is not allowed
256 var o = this.map[ref]; 256 // it silently fails.
257 if (o === obj) { 257 function _defineProperty(o, name, value) {
258 return ref; 258 if (Object.isExtensible(o)) {
259 try {
260 Object.defineProperty(o, name, { 'value': value });
261 } catch (e) {
262 // object is native and lies about being extensible
263 // see https://bugzilla.mozilla.org/show_bug.cgi?id=775185
259 } 264 }
260 } 265 }
261 var ref = this.name + '-' + this._nextId++; 266 }
262 this.map[ref] = obj; 267
263 return ref; 268 // Adds an object to the table and return an ID for serialization.
269 ProxiedObjectTable.prototype.add = function (obj, id) {
270 if (id != null) {
271 this.map[id] = obj;
272 return id;
273 } else {
274 var ref = obj[_dartRefPropertyName];
275 if (ref == null) {
276 ref = this.name + '-' + this._nextId++;
277 this.map[ref] = obj;
278 _defineProperty(obj, _dartRefPropertyName, ref);
279 }
280 return ref;
281 }
264 } 282 }
265 283
266 // Gets the object or function corresponding to this ID. 284 // Gets the object or function corresponding to this ID.
285 ProxiedObjectTable.prototype.contains = function (id) {
286 return this.map.hasOwnProperty(id);
287 }
288
289 // Gets the object or function corresponding to this ID.
267 ProxiedObjectTable.prototype.get = function (id) { 290 ProxiedObjectTable.prototype.get = function (id) {
268 if (!this.map.hasOwnProperty(id)) { 291 if (!this.map.hasOwnProperty(id)) {
269 throw 'Proxy ' + id + ' has been invalidated.' 292 throw 'Proxy ' + id + ' has been invalidated.'
270 } 293 }
271 return this.map[id]; 294 return this.map[id];
272 } 295 }
273 296
274 ProxiedObjectTable.prototype._initialize = function () { 297 ProxiedObjectTable.prototype._initialize = function () {
275 // Configure this table's port to forward methods, getters, and setters 298 // Configure this table's port to forward methods, getters, and setters
276 // from the remote proxy to the local object. 299 // from the remote proxy to the local object.
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 return [ 'throws', e.toString() ]; 344 return [ 'throws', e.toString() ];
322 } 345 }
323 }); 346 });
324 } 347 }
325 348
326 // Singleton for local proxied objects. 349 // Singleton for local proxied objects.
327 var proxiedObjectTable = new ProxiedObjectTable(); 350 var proxiedObjectTable = new ProxiedObjectTable();
328 proxiedObjectTable._initialize() 351 proxiedObjectTable._initialize()
329 352
330 // Type for remote proxies to Dart objects. 353 // Type for remote proxies to Dart objects.
331 function DartProxy(id, sendPort) { 354 function DartObject(id, sendPort) {
332 this.id = id; 355 this.id = id;
333 this.port = sendPort; 356 this.port = sendPort;
334 } 357 }
335 358
336 // Serializes JS types to SendPortSync format: 359 // Serializes JS types to SendPortSync format:
337 // - primitives -> primitives 360 // - primitives -> primitives
338 // - sendport -> sendport 361 // - sendport -> sendport
339 // - Function -> [ 'funcref', function-id, sendport ] 362 // - Function -> [ 'funcref', function-id, sendport ]
340 // - Object -> [ 'objref', object-id, sendport ] 363 // - Object -> [ 'objref', object-id, sendport ]
341 function serialize(message) { 364 function serialize(message) {
(...skipping 12 matching lines...) Expand all
354 // Remote function proxy. 377 // Remote function proxy.
355 var remoteId = message._dart_id; 378 var remoteId = message._dart_id;
356 var remoteSendPort = message._dart_port; 379 var remoteSendPort = message._dart_port;
357 return [ 'funcref', remoteId, remoteSendPort ]; 380 return [ 'funcref', remoteId, remoteSendPort ];
358 } else { 381 } else {
359 // Local function proxy. 382 // Local function proxy.
360 return [ 'funcref', 383 return [ 'funcref',
361 proxiedObjectTable.add(message), 384 proxiedObjectTable.add(message),
362 proxiedObjectTable.sendPort ]; 385 proxiedObjectTable.sendPort ];
363 } 386 }
364 } else if (message instanceof DartProxy) { 387 } else if (message instanceof DartObject) {
365 // Remote object proxy. 388 // Remote object proxy.
366 return [ 'objref', message.id, message.port ]; 389 return [ 'objref', message.id, message.port ];
367 } else { 390 } else {
368 // Local object proxy. 391 // Local object proxy.
369 return [ 'objref', 392 return [ 'objref',
370 proxiedObjectTable.add(message), 393 proxiedObjectTable.add(message),
371 proxiedObjectTable.sendPort ]; 394 proxiedObjectTable.sendPort ];
372 } 395 }
373 } 396 }
374 397
(...skipping 20 matching lines...) Expand all
395 // Create a local function that forwards to the remote function. 418 // Create a local function that forwards to the remote function.
396 function deserializeFunction(message) { 419 function deserializeFunction(message) {
397 var id = message[1]; 420 var id = message[1];
398 var port = message[2]; 421 var port = message[2];
399 // TODO(vsm): Add a more robust check for a local SendPortSync. 422 // TODO(vsm): Add a more robust check for a local SendPortSync.
400 if ("receivePort" in port) { 423 if ("receivePort" in port) {
401 // Local function. 424 // Local function.
402 return proxiedObjectTable.get(id); 425 return proxiedObjectTable.get(id);
403 } else { 426 } else {
404 // Remote function. Forward to its port. 427 // Remote function. Forward to its port.
428 if (proxiedObjectTable.contains(id)) {
429 return proxiedObjectTable.get(id);
430 }
405 var f = function () { 431 var f = function () {
406 var args = Array.prototype.slice.apply(arguments); 432 var args = Array.prototype.slice.apply(arguments);
407 args.splice(0, 0, this); 433 args.splice(0, 0, this);
408 args = args.map(serialize); 434 args = args.map(serialize);
409 var result = port.callSync([id, '#call', args]); 435 var result = port.callSync([id, '#call', args]);
410 if (result[0] == 'throws') throw deserialize(result[1]); 436 if (result[0] == 'throws') throw deserialize(result[1]);
411 return deserialize(result[1]); 437 return deserialize(result[1]);
412 }; 438 };
413 // Cache the remote id and port. 439 // Cache the remote id and port.
414 f._dart_id = id; 440 f._dart_id = id;
415 f._dart_port = port; 441 f._dart_port = port;
442 proxiedObjectTable.add(f, id);
416 return f; 443 return f;
417 } 444 }
418 } 445 }
419 446
420 // Creates a DartProxy to forwards to the remote object. 447 // Creates a DartObject to forwards to the remote object.
421 function deserializeObject(message) { 448 function deserializeObject(message) {
422 var id = message[1]; 449 var id = message[1];
423 var port = message[2]; 450 var port = message[2];
424 // TODO(vsm): Add a more robust check for a local SendPortSync. 451 // TODO(vsm): Add a more robust check for a local SendPortSync.
425 if ("receivePort" in port) { 452 if ("receivePort" in port) {
426 // Local object. 453 // Local object.
427 return proxiedObjectTable.get(id); 454 return proxiedObjectTable.get(id);
428 } else { 455 } else {
429 // Remote object. 456 // Remote object.
430 return new DartProxy(id, port); 457 if (proxiedObjectTable.contains(id)) {
458 return proxiedObjectTable.get(id);
459 }
460 proxy = new DartObject(id, port);
461 proxiedObjectTable.add(proxy, id);
462 return proxy;
431 } 463 }
432 } 464 }
433 465
434 // Remote handler to construct a new JavaScript object given its 466 // Remote handler to construct a new JavaScript object given its
435 // serialized constructor and arguments. 467 // serialized constructor and arguments.
436 function construct(args) { 468 function construct(args) {
437 args = args.map(deserialize); 469 args = args.map(deserialize);
438 var constructor = args[0]; 470 var constructor = args[0];
439 args = Array.prototype.slice.call(args, 1);
440 471
441 // Until 10 args, the 'new' operator is used. With more arguments we use a 472 // The following code solves the problem of invoking a JavaScript
442 // generic way that may not work, particularly when the constructor does not 473 // constructor with an unknown number arguments.
443 // have an "apply" method. 474 // First bind the constructor to the argument list using bind.apply().
444 var ret = null; 475 // The first argument to bind() is the binding of 'this', make it 'null'
445 if (args.length === 0) { 476 // After that, use the JavaScript 'new' operator which overrides any binding
446 ret = new constructor(); 477 // of 'this' with the new instance.
447 } else if (args.length === 1) { 478 args[0] = null;
448 ret = new constructor(args[0]); 479 var factoryFunction = constructor.bind.apply(constructor, args);
449 } else if (args.length === 2) { 480 return serialize(new factoryFunction());
450 ret = new constructor(args[0], args[1]);
451 } else if (args.length === 3) {
452 ret = new constructor(args[0], args[1], args[2]);
453 } else if (args.length === 4) {
454 ret = new constructor(args[0], args[1], args[2], args[3]);
455 } else if (args.length === 5) {
456 ret = new constructor(args[0], args[1], args[2], args[3], args[4]);
457 } else if (args.length === 6) {
458 ret = new constructor(args[0], args[1], args[2], args[3], args[4],
459 args[5]);
460 } else if (args.length === 7) {
461 ret = new constructor(args[0], args[1], args[2], args[3], args[4],
462 args[5], args[6]);
463 } else if (args.length === 8) {
464 ret = new constructor(args[0], args[1], args[2], args[3], args[4],
465 args[5], args[6], args[7]);
466 } else if (args.length === 9) {
467 ret = new constructor(args[0], args[1], args[2], args[3], args[4],
468 args[5], args[6], args[7], args[8]);
469 } else if (args.length === 10) {
470 ret = new constructor(args[0], args[1], args[2], args[3], args[4],
471 args[5], args[6], args[7], args[8], args[9]);
472 } else {
473 // Dummy Type with correct constructor.
474 var Type = function(){};
475 Type.prototype = constructor.prototype;
476
477 // Create a new instance
478 var instance = new Type();
479
480 // Call the original constructor.
481 ret = constructor.apply(instance, args);
482 ret = Object(ret) === ret ? ret : instance;
483 }
484 return serialize(ret);
485 } 481 }
486 482
487 // Remote handler to return the top-level JavaScript context. 483 // Remote handler to return the top-level JavaScript context.
488 function context(data) { 484 function context(data) {
489 return serialize(globalContext); 485 return serialize(globalContext);
490 } 486 }
491 487
492 // Return true if a JavaScript proxy is instance of a given type (instanceof). 488 // Return true if a JavaScript proxy is instance of a given type (instanceof).
493 function proxyInstanceof(args) { 489 function proxyInstanceof(args) {
494 var obj = deserialize(args[0]); 490 var obj = deserialize(args[0]);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
532 port.receive(f); 528 port.receive(f);
533 window.registerPort(name, port.toSendPort()); 529 window.registerPort(name, port.toSendPort());
534 } 530 }
535 531
536 makeGlobalPort('dart-js-context', context); 532 makeGlobalPort('dart-js-context', context);
537 makeGlobalPort('dart-js-create', construct); 533 makeGlobalPort('dart-js-create', construct);
538 makeGlobalPort('dart-js-instanceof', proxyInstanceof); 534 makeGlobalPort('dart-js-instanceof', proxyInstanceof);
539 makeGlobalPort('dart-js-delete-property', proxyDeleteProperty); 535 makeGlobalPort('dart-js-delete-property', proxyDeleteProperty);
540 makeGlobalPort('dart-js-convert', proxyConvert); 536 makeGlobalPort('dart-js-convert', proxyConvert);
541 })(); 537 })();
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/js/dart2js/js_dart2js.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698