| Index: sdk/lib/js/dart2js/js_dart2js.dart
|
| diff --git a/sdk/lib/js/dart2js/js_dart2js.dart b/sdk/lib/js/dart2js/js_dart2js.dart
|
| index 8c5eb301d321be4a526095d489b0c01893c8fe71..417876e5738a9a246e767ab7454883f0b1c45ad9 100644
|
| --- a/sdk/lib/js/dart2js/js_dart2js.dart
|
| +++ b/sdk/lib/js/dart2js/js_dart2js.dart
|
| @@ -92,21 +92,30 @@ import 'dart:collection' show HashMap, ListMixin;
|
| import 'dart:indexed_db' show KeyRange;
|
| import 'dart:typed_data' show TypedData;
|
|
|
| -import 'dart:_foreign_helper' show JS, DART_CLOSURE_TO_JS;
|
| -import 'dart:_interceptors' show JavaScriptObject, UnknownJavaScriptObject;
|
| -import 'dart:_js_helper' show Primitives, convertDartClosureToJS,
|
| - getIsolateAffinityTag;
|
| +import 'dart:_foreign_helper' show JS, JS_CONST, DART_CLOSURE_TO_JS;
|
| +import 'dart:_interceptors'
|
| + show JavaScriptObject, UnknownJavaScriptObject, DART_CLOSURE_PROPERTY_NAME;
|
| +import 'dart:_js_helper'
|
| + show Primitives, convertDartClosureToJS, getIsolateAffinityTag;
|
| +
|
| +export 'dart:_interceptors' show JavaScriptObject;
|
|
|
| final JsObject context = _wrapToDart(JS('', 'self'));
|
|
|
| _convertDartFunction(Function f, {bool captureThis: false}) {
|
| - return JS('',
|
| - 'function(_call, f, captureThis) {'
|
| - 'return function() {'
|
| - 'return _call(f, captureThis, this, '
|
| - 'Array.prototype.slice.apply(arguments));'
|
| - '}'
|
| - '}(#, #, #)', DART_CLOSURE_TO_JS(_callDartFunction), f, captureThis);
|
| + return JS(
|
| + '',
|
| + '''
|
| + function(_call, f, captureThis) {
|
| + return function() {
|
| + return _call(f, captureThis, this,
|
| + Array.prototype.slice.apply(arguments));
|
| + }
|
| + }(#, #, #)
|
| + ''',
|
| + DART_CLOSURE_TO_JS(_callDartFunction),
|
| + f,
|
| + captureThis);
|
| }
|
|
|
| _callDartFunction(callback, bool captureThis, self, List arguments) {
|
| @@ -212,8 +221,7 @@ class JsObject {
|
| */
|
| factory JsObject.fromBrowserObject(object) {
|
| if (object is num || object is String || object is bool || object == null) {
|
| - throw new ArgumentError(
|
| - "object cannot be a num, string, bool, or null");
|
| + throw new ArgumentError("object cannot be a num, string, bool, or null");
|
| }
|
| return _wrapToDart(_convertToJS(object));
|
| }
|
| @@ -267,7 +275,7 @@ class JsObject {
|
| *
|
| * The type of [property] must be either [String] or [num].
|
| */
|
| - dynamic operator[](property) {
|
| + dynamic operator [](property) {
|
| if (property is! String && property is! num) {
|
| throw new ArgumentError("property is not a String or num");
|
| }
|
| @@ -280,7 +288,7 @@ class JsObject {
|
| *
|
| * The type of [property] must be either [String] or [num].
|
| */
|
| - operator[]=(property, value) {
|
| + operator []=(property, value) {
|
| if (property is! String && property is! num) {
|
| throw new ArgumentError("property is not a String or num");
|
| }
|
| @@ -289,8 +297,8 @@ class JsObject {
|
|
|
| int get hashCode => 0;
|
|
|
| - bool operator==(other) => other is JsObject &&
|
| - JS('bool', '# === #', _jsObject, other._jsObject);
|
| + bool operator ==(other) =>
|
| + other is JsObject && JS('bool', '# === #', _jsObject, other._jsObject);
|
|
|
| /**
|
| * Returns `true` if the JavaScript object contains the specified property
|
| @@ -332,7 +340,7 @@ class JsObject {
|
| String toString() {
|
| try {
|
| return JS('String', 'String(#)', _jsObject);
|
| - } catch(e) {
|
| + } catch (e) {
|
| return super.toString();
|
| }
|
| }
|
| @@ -347,7 +355,11 @@ class JsObject {
|
| if (method is! String && method is! num) {
|
| throw new ArgumentError("method is not a String or num");
|
| }
|
| - return _convertToDart(JS('', '#[#].apply(#, #)', _jsObject, method,
|
| + return _convertToDart(JS(
|
| + '',
|
| + '#[#].apply(#, #)',
|
| + _jsObject,
|
| + method,
|
| _jsObject,
|
| args == null ? null : new List.from(args.map(_convertToJS))));
|
| }
|
| @@ -357,7 +369,6 @@ class JsObject {
|
| * Proxies a JavaScript Function object.
|
| */
|
| class JsFunction extends JsObject {
|
| -
|
| /**
|
| * Returns a [JsFunction] that captures its 'this' binding and calls [f]
|
| * with the value of this passed as the first argument.
|
| @@ -373,17 +384,18 @@ class JsFunction extends JsObject {
|
| * Invokes the JavaScript function with arguments [args]. If [thisArg] is
|
| * supplied it is the value of `this` for the invocation.
|
| */
|
| - dynamic apply(List args, { thisArg }) =>
|
| - _convertToDart(JS('', '#.apply(#, #)', _jsObject,
|
| - _convertToJS(thisArg),
|
| - args == null ? null : new List.from(args.map(_convertToJS))));
|
| + dynamic apply(List args, {thisArg}) => _convertToDart(JS(
|
| + '',
|
| + '#.apply(#, #)',
|
| + _jsObject,
|
| + _convertToJS(thisArg),
|
| + args == null ? null : new List.from(args.map(_convertToJS))));
|
| }
|
|
|
| /**
|
| * A [List] that proxies a JavaScript array.
|
| */
|
| class JsArray<E> extends JsObject with ListMixin<E> {
|
| -
|
| /**
|
| * Creates a new JavaScript array.
|
| */
|
| @@ -449,8 +461,9 @@ class JsArray<E> extends JsObject with ListMixin<E> {
|
| throw new StateError('Bad JsArray length');
|
| }
|
|
|
| - set length(int length) { super['length'] = length; }
|
| -
|
| + void set length(int length) {
|
| + super['length'] = length;
|
| + }
|
|
|
| // Methods overriden for better performance
|
|
|
| @@ -503,12 +516,11 @@ class JsArray<E> extends JsObject with ListMixin<E> {
|
| // property added to a Dart object referencing its JS-side DartObject proxy
|
| final String _DART_OBJECT_PROPERTY_NAME =
|
| getIsolateAffinityTag(r'_$dart_dartObject');
|
| -final String _DART_CLOSURE_PROPERTY_NAME =
|
| - getIsolateAffinityTag(r'_$dart_dartClosure');
|
|
|
| // property added to a JS object referencing its Dart-side JsObject proxy
|
| const _JS_OBJECT_PROPERTY_NAME = r'_$dart_jsObject';
|
| const _JS_FUNCTION_PROPERTY_NAME = r'$dart_jsFunction';
|
| +const _JS_FUNCTION_PROPERTY_NAME_CAPTURE_THIS = r'_$dart_jsFunctionCaptureThis';
|
|
|
| bool _defineProperty(o, String name, value) {
|
| try {
|
| @@ -520,9 +532,9 @@ bool _defineProperty(o, String name, value) {
|
| return true;
|
| }
|
| } catch (e) {
|
| - // object is native and lies about being extensible
|
| - // see https://bugzilla.mozilla.org/show_bug.cgi?id=775185
|
| - // Or, isExtensible throws for this object.
|
| + // object is native and lies about being extensible
|
| + // see https://bugzilla.mozilla.org/show_bug.cgi?id=775185
|
| + // Or, isExtensible throws for this object.
|
| }
|
| return false;
|
| }
|
| @@ -555,8 +567,13 @@ dynamic _convertToJS(dynamic o) {
|
| if (o is JsObject) {
|
| return o._jsObject;
|
| }
|
| - if (o is Blob || o is Event || o is KeyRange || o is ImageData || o is Node ||
|
| - o is TypedData || o is Window) {
|
| + if (o is Blob ||
|
| + o is Event ||
|
| + o is KeyRange ||
|
| + o is ImageData ||
|
| + o is Node ||
|
| + o is TypedData ||
|
| + o is Window) {
|
| return o;
|
| }
|
| if (o is DateTime) {
|
| @@ -566,13 +583,13 @@ dynamic _convertToJS(dynamic o) {
|
| return _getJsProxy(o, _JS_FUNCTION_PROPERTY_NAME, (o) {
|
| var jsFunction = _convertDartFunction(o);
|
| // set a property on the JS closure referencing the Dart closure
|
| - _defineProperty(jsFunction, _DART_CLOSURE_PROPERTY_NAME, o);
|
| + _defineProperty(jsFunction, DART_CLOSURE_PROPERTY_NAME, o);
|
| return jsFunction;
|
| });
|
| }
|
| var ctor = _dartProxyCtor;
|
| - return _getJsProxy(o, _JS_OBJECT_PROPERTY_NAME,
|
| - (o) => JS('', 'new #(#)', ctor, o));
|
| + return _getJsProxy(
|
| + o, _JS_OBJECT_PROPERTY_NAME, (o) => JS('', 'new #(#)', ctor, o));
|
| }
|
|
|
| Object _getJsProxy(o, String propertyName, createProxy(o)) {
|
| @@ -592,9 +609,14 @@ Object _convertToDart(o) {
|
| JS('bool', 'typeof # == "number"', o) ||
|
| JS('bool', 'typeof # == "boolean"', o)) {
|
| return o;
|
| - } else if (_isLocalObject(o)
|
| - && (o is Blob || o is Event || o is KeyRange || o is ImageData
|
| - || o is Node || o is TypedData || o is Window)) {
|
| + } else if (_isLocalObject(o) &&
|
| + (o is Blob ||
|
| + o is Event ||
|
| + o is KeyRange ||
|
| + o is ImageData ||
|
| + o is Node ||
|
| + o is TypedData ||
|
| + o is Window)) {
|
| // long line: dart2js doesn't allow string concatenation in the JS() form
|
| return JS('Blob|Event|KeyRange|ImageData|Node|TypedData|Window', '#', o);
|
| } else if (JS('bool', '# instanceof Date', o)) {
|
| @@ -609,15 +631,15 @@ Object _convertToDart(o) {
|
|
|
| JsObject _wrapToDart(o) {
|
| if (JS('bool', 'typeof # == "function"', o)) {
|
| - return _getDartProxy(o, _DART_CLOSURE_PROPERTY_NAME,
|
| - (o) => new JsFunction._fromJs(o));
|
| + return _getDartProxy(
|
| + o, DART_CLOSURE_PROPERTY_NAME, (o) => new JsFunction._fromJs(o));
|
| }
|
| if (JS('bool', '# instanceof Array', o)) {
|
| - return _getDartProxy(o, _DART_OBJECT_PROPERTY_NAME,
|
| - (o) => new JsArray._fromJs(o));
|
| + return _getDartProxy(
|
| + o, _DART_OBJECT_PROPERTY_NAME, (o) => new JsArray._fromJs(o));
|
| }
|
| - return _getDartProxy(o, _DART_OBJECT_PROPERTY_NAME,
|
| - (o) => new JsObject._fromJs(o));
|
| + return _getDartProxy(
|
| + o, _DART_OBJECT_PROPERTY_NAME, (o) => new JsObject._fromJs(o));
|
| }
|
|
|
| Object _getDartProxy(o, String propertyName, createProxy(o)) {
|
| @@ -635,3 +657,72 @@ Object _getDartProxy(o, String propertyName, createProxy(o)) {
|
| }
|
| return dartProxy;
|
| }
|
| +
|
| +// ---------------------------------------------------------------------------
|
| +// Start of methods for new style Dart-JS interop.
|
| +
|
| +_convertDartFunctionFast(Function f) {
|
| + var existing = JS('', '#.#', f, _JS_FUNCTION_PROPERTY_NAME);
|
| + if (existing != null) return existing;
|
| + var ret = JS(
|
| + '',
|
| + '''
|
| + function(_call, f) {
|
| + return function() {
|
| + return _call(f, Array.prototype.slice.apply(arguments));
|
| + }
|
| + }(#, #)
|
| + ''',
|
| + DART_CLOSURE_TO_JS(_callDartFunctionFast),
|
| + f);
|
| + JS('', '#.# = #', ret, DART_CLOSURE_PROPERTY_NAME, f);
|
| + JS('', '#.# = #', f, _JS_FUNCTION_PROPERTY_NAME, ret);
|
| + return ret;
|
| +}
|
| +
|
| +_convertDartFunctionFastCaptureThis(Function f) {
|
| + var existing = JS('', '#.#', f, _JS_FUNCTION_PROPERTY_NAME_CAPTURE_THIS);
|
| + if (existing != null) return existing;
|
| + var ret = JS(
|
| + '',
|
| + '''
|
| + function(_call, f) {
|
| + return function() {
|
| + return _call(f, this,Array.prototype.slice.apply(arguments));
|
| + }
|
| + }(#, #)
|
| + ''',
|
| + DART_CLOSURE_TO_JS(_callDartFunctionFastCaptureThis),
|
| + f);
|
| + JS('', '#.# = #', ret, DART_CLOSURE_PROPERTY_NAME, f);
|
| + JS('', '#.# = #', f, _JS_FUNCTION_PROPERTY_NAME_CAPTURE_THIS, ret);
|
| + return ret;
|
| +}
|
| +
|
| +_callDartFunctionFast(callback, List arguments) {
|
| + return Function.apply(callback, arguments);
|
| +}
|
| +
|
| +_callDartFunctionFastCaptureThis(callback, self, List arguments) {
|
| + return _convertToJS(Function.apply(callback, [self]..addAll(arguments)));
|
| +}
|
| +
|
| +Function allowInterop(Function f) {
|
| + if (JS('bool', 'typeof(#) == "function"', f)) {
|
| + // Already supports interop, just use the existing function.
|
| + return f;
|
| + } else {
|
| + return _convertDartFunctionFast(f);
|
| + }
|
| +}
|
| +
|
| +Function allowInteropCaptureThis(Function f) {
|
| + if (JS('bool', 'typeof(#) == "function"', f)) {
|
| + // Behavior when the function is already a JS function is unspecified.
|
| + throw new ArgumentError(
|
| + "Function is already a JS function so cannot capture this.");
|
| + return f;
|
| + } else {
|
| + return _convertDartFunctionFastCaptureThis(f);
|
| + }
|
| +}
|
|
|