Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 /// This library defines runtime operations on objects used by the code | 5 /// This library defines runtime operations on objects used by the code |
| 6 /// generator. | 6 /// generator. |
| 7 part of dart._runtime; | 7 part of dart._runtime; |
| 8 | 8 |
| 9 class InvocationImpl extends Invocation { | 9 class InvocationImpl extends Invocation { |
| 10 final Symbol memberName; | 10 final Symbol memberName; |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 29 } | 29 } |
| 30 } | 30 } |
| 31 | 31 |
| 32 /// Given an object and a method name, tear off the method. | 32 /// Given an object and a method name, tear off the method. |
| 33 /// Sets the runtime type of the torn off method appropriately, | 33 /// Sets the runtime type of the torn off method appropriately, |
| 34 /// and also binds the object. | 34 /// and also binds the object. |
| 35 /// | 35 /// |
| 36 /// If the optional `f` argument is passed in, it will be used as the method. | 36 /// If the optional `f` argument is passed in, it will be used as the method. |
| 37 /// This supports cases like `super.foo` where we need to tear off the method | 37 /// This supports cases like `super.foo` where we need to tear off the method |
| 38 /// from the superclass, not from the `obj` directly. | 38 /// from the superclass, not from the `obj` directly. |
| 39 /// TODO(leafp): Consider caching the tearoff on the object? | 39 // TODO(leafp): Consider caching the tearoff on the object? |
| 40 bind(obj, name, f) { | 40 bind(obj, name, f) { |
| 41 if (f == null) f = JS('', '#[#]', obj, name); | 41 // Handle Object members. |
| 42 | 42 var method; |
| 43 // TODO(jmesserly): it would be nice to do this lazily, but JS interop seems | 43 if (JS('bool', '# === "toString"', name)) { |
| 44 // to require us to be eager (the test below). | 44 method = _toString; |
| 45 var sig = getMethodType(getType(obj), name); | 45 f = JS('', '() => #(#)', _toString, obj); |
| 46 | 46 } else if (JS('bool', '# === "noSuchMethod"', name)) { |
| 47 // JS interop case: do not bind this for compatibility with the dart2js | 47 method = noSuchMethod; |
| 48 // implementation where we cannot bind this reliably here until we trust | 48 f = JS('', '(i) => #(#, i)', noSuchMethod, obj); |
| 49 // types more. | 49 } else { |
| 50 if (sig == null) return f; | 50 // All other members |
| 51 | 51 if (f == null) f = JS('', '#[#]', obj, name); |
| 52 f = JS('', '#.bind(#)', f, obj); | 52 method = f; |
| 53 f = JS('', '#.bind(#)', f, obj); | |
| 54 } | |
| 55 // TODO(jmesserly): should we canonicalize tearoffs so we don't need to | |
| 56 // define ==/hashCode? Then we'd only need the signature. | |
| 57 // Another idea here is to have a type that maps to Funtion.prototype, | |
|
vsm
2017/06/30 18:08:47
Funtion -> Function
| |
| 58 // similar to all other JS types. That would give us a place to put function | |
| 59 // equality, hashCode, runtimeType, noSuchMethod, and toString, rather than | |
| 60 // it being a special case in every Object member helper. | |
| 53 JS( | 61 JS( |
| 54 '', | 62 '', |
| 55 r'''#[dartx["=="]] = function boundMethodEquals(other) { | 63 '#[dartx["=="]] = ' |
| 56 return other[#] === this[#] && other[#] === this[#]; | 64 '(f) => { let eq = f[#]; return eq != null && eq(#, #); }', |
| 57 }''', | |
| 58 f, | 65 f, |
| 59 _boundMethodTarget, | 66 _tearoffEquals, |
| 60 _boundMethodTarget, | 67 obj, |
| 61 _boundMethodName, | 68 method); |
| 62 _boundMethodName); | 69 JS('', '#[#] = (o, m) => o === # && m === #', f, _tearoffEquals, obj, method); |
| 63 JS('', '#[#] = #', f, _boundMethodTarget, obj); | 70 JS( |
| 64 JS('', '#[#] = #', f, _boundMethodName, name); | 71 '', |
| 65 tag(f, sig); | 72 '#[#] = function() {' |
| 73 'let hash = (17 * 31 + #) & 0x1fffffff;' | |
| 74 'return (hash * 31 + #) & 0x1fffffff; }', | |
| 75 f, | |
| 76 _tearoffHashcode, | |
| 77 hashCode(obj), | |
| 78 hashCode(method)); | |
| 79 tagLazy(f, JS('', '() => #', getMethodType(getType(obj), name))); | |
| 66 return f; | 80 return f; |
| 67 } | 81 } |
| 68 | 82 |
| 69 final _boundMethodTarget = JS('', 'Symbol("_boundMethodTarget")'); | 83 final _tearoffEquals = JS('', 'Symbol("_tearoffEquals")'); |
| 70 final _boundMethodName = JS('', 'Symbol("_boundMethodName")'); | 84 final _tearoffHashcode = JS('', 'Symbol("_tearoffHashcode")'); |
| 71 | 85 |
| 72 /// Instantiate a generic method. | 86 /// Instantiate a generic method. |
| 73 /// | 87 /// |
| 74 /// We need to apply the type arguments both to the function, as well as its | 88 /// We need to apply the type arguments both to the function, as well as its |
| 75 /// associated function type. | 89 /// associated function type. |
| 76 gbind(f, @rest typeArgs) { | 90 gbind(f, @rest typeArgs) { |
| 77 var result = JS('', '#.apply(null, #)', f, typeArgs); | 91 var result = JS('', '#.apply(null, #)', f, typeArgs); |
| 78 var sig = JS('', '#.instantiate(#)', _getRuntimeType(f), typeArgs); | 92 var sig = JS('', '#.instantiate(#)', _getRuntimeType(f), typeArgs); |
| 79 tag(result, sig); | 93 tag(result, sig); |
| 80 return result; | 94 return result; |
| 81 } | 95 } |
| 82 | 96 |
| 83 // Warning: dload, dput, and dsend assume they are never called on methods | 97 // Warning: dload, dput, and dsend assume they are never called on methods |
| 84 // implemented by the Object base class as those methods can always be | 98 // implemented by the Object base class as those methods can always be |
| 85 // statically resolved. | 99 // statically resolved. |
| 86 dload(obj, field) { | 100 dload(obj, field) { |
| 87 var f = _canonicalMember(obj, field); | 101 var f = _canonicalMember(obj, field); |
| 88 | 102 |
| 89 _trackCall(obj); | 103 _trackCall(obj); |
| 90 if (f != null) { | 104 if (f != null) { |
| 91 var type = getType(obj); | 105 var type = getType(obj); |
| 92 | 106 |
| 93 if (hasField(type, f) || hasGetter(type, f)) return JS('', '#[#]', obj, f); | 107 if (hasField(type, f) || hasGetter(type, f)) return JS('', '#[#]', obj, f); |
| 94 if (hasMethod(type, f)) return bind(obj, f, JS('', 'void 0')); | 108 if (hasMethod(type, f)) return bind(obj, f, null); |
| 95 | 109 |
| 96 // Always allow for JS interop objects. | 110 // Always allow for JS interop objects. |
| 97 if (isJsInterop(obj)) return JS('', '#[#]', obj, f); | 111 if (isJsInterop(obj)) return JS('', '#[#]', obj, f); |
| 98 } | 112 } |
| 99 return noSuchMethod( | 113 return noSuchMethod( |
| 100 obj, new InvocationImpl(field, JS('', '[]'), isGetter: true)); | 114 obj, new InvocationImpl(field, JS('', '[]'), isGetter: true)); |
| 101 } | 115 } |
| 102 | 116 |
| 103 // Version of dload that matches legacy mirrors behavior for JS types. | 117 // Version of dload that matches legacy mirrors behavior for JS types. |
| 104 dloadMirror(obj, field) { | 118 dloadMirror(obj, field) { |
| (...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 496 /// in strong mode | 510 /// in strong mode |
| 497 instanceOfOrNull(obj, type) => JS( | 511 instanceOfOrNull(obj, type) => JS( |
| 498 '', | 512 '', |
| 499 '''(() => { | 513 '''(() => { |
| 500 // If strongInstanceOf returns null, convert to false here. | 514 // If strongInstanceOf returns null, convert to false here. |
| 501 if (($obj == null) || $strongInstanceOf($obj, $type, true)) return true; | 515 if (($obj == null) || $strongInstanceOf($obj, $type, true)) return true; |
| 502 return false; | 516 return false; |
| 503 })()'''); | 517 })()'''); |
| 504 | 518 |
| 505 @JSExportName('is') | 519 @JSExportName('is') |
| 506 instanceOf(obj, type) => JS( | 520 bool instanceOf(obj, type) => JS( |
| 507 '', | 521 '', |
| 508 '''(() => { | 522 '''(() => { |
| 509 if ($obj == null) { | 523 if ($obj == null) { |
| 510 return $type == $Null || $_isTop($type); | 524 return $type == $Null || $_isTop($type); |
| 511 } | 525 } |
| 512 let result = $strongInstanceOf($obj, $type); | 526 let result = $strongInstanceOf($obj, $type); |
| 513 if (result !== null) return result; | 527 if (result !== null) return result; |
| 514 if (!dart.__failForWeakModeIsChecks) return false; | 528 if (!dart.__failForWeakModeIsChecks) return false; |
| 515 let actual = $getReifiedType($obj); | 529 let actual = $getReifiedType($obj); |
| 516 let message = 'Strong mode is-check failure: ' + | 530 let message = 'Strong mode is-check failure: ' + |
| (...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 877 hashCode(obj) { | 891 hashCode(obj) { |
| 878 if (obj == null) return 0; | 892 if (obj == null) return 0; |
| 879 | 893 |
| 880 switch (JS('String', 'typeof #', obj)) { | 894 switch (JS('String', 'typeof #', obj)) { |
| 881 case "number": | 895 case "number": |
| 882 return JS('', '# & 0x1FFFFFFF', obj); | 896 return JS('', '# & 0x1FFFFFFF', obj); |
| 883 case "boolean": | 897 case "boolean": |
| 884 // From JSBool.hashCode, see comment there. | 898 // From JSBool.hashCode, see comment there. |
| 885 return JS('', '# ? (2 * 3 * 23 * 3761) : (269 * 811)', obj); | 899 return JS('', '# ? (2 * 3 * 23 * 3761) : (269 * 811)', obj); |
| 886 case "function": | 900 case "function": |
| 887 // TODO(jmesserly): this doesn't work for method tear-offs. | 901 var hashFn = JS('', '#[#]', obj, _tearoffHashcode); |
| 902 if (hashFn != null) return JS('int', '#()', hashFn); | |
| 888 return Primitives.objectHashCode(obj); | 903 return Primitives.objectHashCode(obj); |
| 889 } | 904 } |
| 890 | 905 |
| 891 var extension = getExtensionType(obj); | 906 var extension = getExtensionType(obj); |
| 892 if (extension != null) { | 907 if (extension != null) { |
| 893 return JS('', '#[dartx.hashCode]', obj); | 908 return JS('', '#[dartx.hashCode]', obj); |
| 894 } | 909 } |
| 895 return JS('', '#.hashCode', obj); | 910 return JS('', '#.hashCode', obj); |
| 896 } | 911 } |
| 897 | 912 |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 995 JS('', '# = "+" + #', name, name); | 1010 JS('', '# = "+" + #', name, name); |
| 996 } | 1011 } |
| 997 return name; | 1012 return name; |
| 998 } | 1013 } |
| 999 | 1014 |
| 1000 /// Emulates the implicit "loadLibrary" function provided by a deferred library. | 1015 /// Emulates the implicit "loadLibrary" function provided by a deferred library. |
| 1001 /// | 1016 /// |
| 1002 /// Libraries are not actually deferred in DDC, so this just returns a future | 1017 /// Libraries are not actually deferred in DDC, so this just returns a future |
| 1003 /// that completes immediately. | 1018 /// that completes immediately. |
| 1004 Future loadLibrary() => new Future.value(); | 1019 Future loadLibrary() => new Future.value(); |
| 1020 | |
| 1021 /// Defines lazy statics. | |
| 1022 void defineLazy(to, from) { | |
| 1023 for (var name in getOwnNamesAndSymbols(from)) { | |
| 1024 defineLazyProperty(to, name, getOwnPropertyDescriptor(from, name)); | |
| 1025 } | |
| 1026 } | |
| OLD | NEW |