| Index: pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
|
| diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
|
| index 6bacda511799a300a47608e489637d14340bafd7..835ead6f55a006461877ef6cb31680a4c128fc5c 100644
|
| --- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
|
| +++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
|
| @@ -36,38 +36,52 @@ class InvocationImpl extends Invocation {
|
| /// If the optional `f` argument is passed in, it will be used as the method.
|
| /// This supports cases like `super.foo` where we need to tear off the method
|
| /// from the superclass, not from the `obj` directly.
|
| -/// TODO(leafp): Consider caching the tearoff on the object?
|
| +// TODO(leafp): Consider caching the tearoff on the object?
|
| bind(obj, name, f) {
|
| - if (f == null) f = JS('', '#[#]', obj, name);
|
| -
|
| - // TODO(jmesserly): it would be nice to do this lazily, but JS interop seems
|
| - // to require us to be eager (the test below).
|
| - var sig = getMethodType(getType(obj), name);
|
| -
|
| - // JS interop case: do not bind this for compatibility with the dart2js
|
| - // implementation where we cannot bind this reliably here until we trust
|
| - // types more.
|
| - if (sig == null) return f;
|
| -
|
| - f = JS('', '#.bind(#)', f, obj);
|
| + // Handle Object members.
|
| + var method;
|
| + if (JS('bool', '# === "toString"', name)) {
|
| + method = _toString;
|
| + f = JS('', '() => #(#)', _toString, obj);
|
| + } else if (JS('bool', '# === "noSuchMethod"', name)) {
|
| + method = noSuchMethod;
|
| + f = JS('', '(i) => #(#, i)', noSuchMethod, obj);
|
| + } else {
|
| + // All other members
|
| + if (f == null) f = JS('', '#[#]', obj, name);
|
| + method = f;
|
| + f = JS('', '#.bind(#)', f, obj);
|
| + }
|
| + // TODO(jmesserly): should we canonicalize tearoffs so we don't need to
|
| + // define ==/hashCode? Then we'd only need the signature.
|
| + // Another idea here is to have a type that maps to Function.prototype,
|
| + // similar to all other JS types. That would give us a place to put function
|
| + // equality, hashCode, runtimeType, noSuchMethod, and toString, rather than
|
| + // it being a special case in every Object member helper.
|
| + JS(
|
| + '',
|
| + '#[dartx["=="]] = '
|
| + '(f) => { let eq = f[#]; return eq != null && eq(#, #); }',
|
| + f,
|
| + _tearoffEquals,
|
| + obj,
|
| + method);
|
| + JS('', '#[#] = (o, m) => o === # && m === #', f, _tearoffEquals, obj, method);
|
| JS(
|
| '',
|
| - r'''#[dartx["=="]] = function boundMethodEquals(other) {
|
| - return other[#] === this[#] && other[#] === this[#];
|
| - }''',
|
| + '#[#] = function() {'
|
| + 'let hash = (17 * 31 + #) & 0x1fffffff;'
|
| + 'return (hash * 31 + #) & 0x1fffffff; }',
|
| f,
|
| - _boundMethodTarget,
|
| - _boundMethodTarget,
|
| - _boundMethodName,
|
| - _boundMethodName);
|
| - JS('', '#[#] = #', f, _boundMethodTarget, obj);
|
| - JS('', '#[#] = #', f, _boundMethodName, name);
|
| - tag(f, sig);
|
| + _tearoffHashcode,
|
| + hashCode(obj),
|
| + hashCode(method));
|
| + tagLazy(f, JS('', '() => #', getMethodType(getType(obj), name)));
|
| return f;
|
| }
|
|
|
| -final _boundMethodTarget = JS('', 'Symbol("_boundMethodTarget")');
|
| -final _boundMethodName = JS('', 'Symbol("_boundMethodName")');
|
| +final _tearoffEquals = JS('', 'Symbol("_tearoffEquals")');
|
| +final _tearoffHashcode = JS('', 'Symbol("_tearoffHashcode")');
|
|
|
| /// Instantiate a generic method.
|
| ///
|
| @@ -91,7 +105,7 @@ dload(obj, field) {
|
| var type = getType(obj);
|
|
|
| if (hasField(type, f) || hasGetter(type, f)) return JS('', '#[#]', obj, f);
|
| - if (hasMethod(type, f)) return bind(obj, f, JS('', 'void 0'));
|
| + if (hasMethod(type, f)) return bind(obj, f, null);
|
|
|
| // Always allow for JS interop objects.
|
| if (isJsInterop(obj)) return JS('', '#[#]', obj, f);
|
| @@ -503,7 +517,7 @@ instanceOfOrNull(obj, type) => JS(
|
| })()''');
|
|
|
| @JSExportName('is')
|
| -instanceOf(obj, type) => JS(
|
| +bool instanceOf(obj, type) => JS(
|
| '',
|
| '''(() => {
|
| if ($obj == null) {
|
| @@ -892,7 +906,8 @@ hashCode(obj) {
|
| // From JSBool.hashCode, see comment there.
|
| return JS('', '# ? (2 * 3 * 23 * 3761) : (269 * 811)', obj);
|
| case "function":
|
| - // TODO(jmesserly): this doesn't work for method tear-offs.
|
| + var hashFn = JS('', '#[#]', obj, _tearoffHashcode);
|
| + if (hashFn != null) return JS('int', '#()', hashFn);
|
| return Primitives.objectHashCode(obj);
|
| }
|
|
|
| @@ -1010,3 +1025,10 @@ _canonicalMember(obj, name) {
|
| /// Libraries are not actually deferred in DDC, so this just returns a future
|
| /// that completes immediately.
|
| Future loadLibrary() => new Future.value();
|
| +
|
| +/// Defines lazy statics.
|
| +void defineLazy(to, from) {
|
| + for (var name in getOwnNamesAndSymbols(from)) {
|
| + defineLazyProperty(to, name, getOwnPropertyDescriptor(from, name));
|
| + }
|
| +}
|
|
|