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 Function.prototype, |
| 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 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
885 hashCode(obj) { | 899 hashCode(obj) { |
886 if (obj == null) return 0; | 900 if (obj == null) return 0; |
887 | 901 |
888 switch (JS('String', 'typeof #', obj)) { | 902 switch (JS('String', 'typeof #', obj)) { |
889 case "number": | 903 case "number": |
890 return JS('', '# & 0x1FFFFFFF', obj); | 904 return JS('', '# & 0x1FFFFFFF', obj); |
891 case "boolean": | 905 case "boolean": |
892 // From JSBool.hashCode, see comment there. | 906 // From JSBool.hashCode, see comment there. |
893 return JS('', '# ? (2 * 3 * 23 * 3761) : (269 * 811)', obj); | 907 return JS('', '# ? (2 * 3 * 23 * 3761) : (269 * 811)', obj); |
894 case "function": | 908 case "function": |
895 // TODO(jmesserly): this doesn't work for method tear-offs. | 909 var hashFn = JS('', '#[#]', obj, _tearoffHashcode); |
| 910 if (hashFn != null) return JS('int', '#()', hashFn); |
896 return Primitives.objectHashCode(obj); | 911 return Primitives.objectHashCode(obj); |
897 } | 912 } |
898 | 913 |
899 var extension = getExtensionType(obj); | 914 var extension = getExtensionType(obj); |
900 if (extension != null) { | 915 if (extension != null) { |
901 return JS('', '#[dartx.hashCode]', obj); | 916 return JS('', '#[dartx.hashCode]', obj); |
902 } | 917 } |
903 return JS('', '#.hashCode', obj); | 918 return JS('', '#.hashCode', obj); |
904 } | 919 } |
905 | 920 |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1003 JS('', '# = "+" + #', name, name); | 1018 JS('', '# = "+" + #', name, name); |
1004 } | 1019 } |
1005 return name; | 1020 return name; |
1006 } | 1021 } |
1007 | 1022 |
1008 /// Emulates the implicit "loadLibrary" function provided by a deferred library. | 1023 /// Emulates the implicit "loadLibrary" function provided by a deferred library. |
1009 /// | 1024 /// |
1010 /// Libraries are not actually deferred in DDC, so this just returns a future | 1025 /// Libraries are not actually deferred in DDC, so this just returns a future |
1011 /// that completes immediately. | 1026 /// that completes immediately. |
1012 Future loadLibrary() => new Future.value(); | 1027 Future loadLibrary() => new Future.value(); |
| 1028 |
| 1029 /// Defines lazy statics. |
| 1030 void defineLazy(to, from) { |
| 1031 for (var name in getOwnNamesAndSymbols(from)) { |
| 1032 defineLazyProperty(to, name, getOwnPropertyDescriptor(from, name)); |
| 1033 } |
| 1034 } |
OLD | NEW |