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; |
11 final List positionalArguments; | 11 final List positionalArguments; |
12 final Map<Symbol, dynamic> namedArguments; | 12 final Map<Symbol, dynamic> namedArguments; |
13 final bool isMethod; | 13 final bool isMethod; |
14 final bool isGetter; | 14 final bool isGetter; |
15 final bool isSetter; | 15 final bool isSetter; |
16 | 16 |
17 InvocationImpl(String memberName, this.positionalArguments, | 17 InvocationImpl(memberName, this.positionalArguments, |
18 {namedArguments, | 18 {namedArguments, |
19 this.isMethod: false, | 19 this.isMethod: false, |
20 this.isGetter: false, | 20 this.isGetter: false, |
21 this.isSetter: false}) | 21 this.isSetter: false}) |
22 : memberName = _dartSymbol(memberName), | 22 : memberName = _dartSymbol(memberName), |
23 namedArguments = _namedArgsToSymbols(namedArguments); | 23 namedArguments = _namedArgsToSymbols(namedArguments); |
24 | 24 |
25 static Map<Symbol, dynamic> _namedArgsToSymbols(namedArgs) { | 25 static Map<Symbol, dynamic> _namedArgsToSymbols(namedArgs) { |
26 if (namedArgs == null) return {}; | 26 if (namedArgs == null) return {}; |
27 return new Map.fromIterable(getOwnPropertyNames(namedArgs), | 27 return new Map.fromIterable(getOwnPropertyNames(namedArgs), |
28 key: _dartSymbol, value: (k) => JS('', '#[#]', namedArgs, k)); | 28 key: _dartSymbol, value: (k) => JS('', '#[#]', namedArgs, k)); |
29 } | 29 } |
30 } | 30 } |
31 | 31 |
| 32 // Warning: dload, dput, and dsend assume they are never called on methods |
| 33 // implemented by the Object base class as those methods can always be |
| 34 // statically resolved. |
32 dload(obj, field) { | 35 dload(obj, field) { |
33 var f = _canonicalMember(obj, field); | 36 var f = _canonicalMember(obj, field); |
| 37 |
34 _trackCall(obj); | 38 _trackCall(obj); |
35 if (f != null) { | 39 if (f != null) { |
36 if (hasMethod(obj, f)) return bind(obj, f, JS('', 'void 0')); | 40 var type = getType(obj); |
37 return JS('', '#[#]', obj, f); | 41 |
| 42 if (hasField(type, f) || hasGetter(type, f)) return JS('', '#[#]', obj, f); |
| 43 if (hasMethod(type, f)) return bind(obj, f, JS('', 'void 0')); |
38 } | 44 } |
39 return noSuchMethod( | 45 return noSuchMethod( |
40 obj, new InvocationImpl(field, JS('', '[]'), isGetter: true)); | 46 obj, new InvocationImpl(field, JS('', '[]'), isGetter: true)); |
41 } | 47 } |
42 | 48 |
43 dput(obj, field, value) { | 49 dput(obj, field, value) { |
44 var f = _canonicalMember(obj, field); | 50 var f = _canonicalMember(obj, field); |
45 _trackCall(obj); | 51 _trackCall(obj); |
46 if (f != null) { | 52 if (f != null) { |
47 return JS('', '#[#] = #', obj, f, value); | 53 var objType = getType(obj); |
| 54 var setterType = getSetterType(objType, f); |
| 55 if (JS('bool', '# != void 0', setterType)) { |
| 56 // TODO(jacobr): throw a type error instead of a NoSuchMethodError if |
| 57 // the type of the setter doesn't match. |
| 58 if (instanceOfOrNull(value, JS('', '#.args[0]', setterType))) { |
| 59 return JS('', '#[#] = #', obj, f, value); |
| 60 } |
| 61 } else { |
| 62 var fieldType = getFieldType(objType, f); |
| 63 // TODO(jacobr): add metadata tracking which fields are final and throw |
| 64 // if a setter is called on a final field. |
| 65 if (JS('bool', '# != void 0', fieldType)) { |
| 66 // TODO(jacobr): throw a type error instead of a NoSuchMethodError if |
| 67 // the type of the field doesn't match. |
| 68 if (instanceOfOrNull(value, fieldType)) { |
| 69 return JS('', '#[#] = #', obj, f, value); |
| 70 } |
| 71 } |
| 72 } |
48 } | 73 } |
49 return noSuchMethod( | 74 return noSuchMethod( |
50 obj, new InvocationImpl(field, JS('', '[#]', value), isSetter: true)); | 75 obj, new InvocationImpl(field, JS('', '[#]', value), isSetter: true)); |
51 } | 76 } |
52 | 77 |
53 /// Check that a function of a given type can be applied to | 78 /// Check that a function of a given type can be applied to |
54 /// actuals. | 79 /// actuals. |
55 _checkApply(type, actuals) => JS( | 80 _checkApply(type, actuals) => JS( |
56 '', | 81 '', |
57 '''(() => { | 82 '''(() => { |
(...skipping 24 matching lines...) Expand all Loading... |
82 if (names.length == 0) return false; | 107 if (names.length == 0) return false; |
83 for (var name of names) { | 108 for (var name of names) { |
84 if (!($hasOwnProperty.call($type.named, name))) { | 109 if (!($hasOwnProperty.call($type.named, name))) { |
85 return false; | 110 return false; |
86 } | 111 } |
87 $check(opts[name], $type.named[name]); | 112 $check(opts[name], $type.named[name]); |
88 } | 113 } |
89 return true; | 114 return true; |
90 })()'''); | 115 })()'''); |
91 | 116 |
92 Symbol _dartSymbol(name) => | 117 _toSymbolName(symbol) => JS( |
93 JS('', '#(#.new(#.toString()))', const_, Symbol, name); | 118 '', |
| 119 '''(() => { |
| 120 let str = $symbol.toString(); |
| 121 // Strip leading 'Symbol(' and trailing ')' |
| 122 return str.substring(7, str.length-1); |
| 123 })()'''); |
| 124 |
| 125 _toDisplayName(name) => JS( |
| 126 '', |
| 127 '''(() => { |
| 128 // Names starting with _ are escaped names used to disambiguate Dart and |
| 129 // JS names. |
| 130 if ($name[0] === '_') { |
| 131 // Inverse of |
| 132 switch($name) { |
| 133 case '_get': |
| 134 return '[]'; |
| 135 case '_set': |
| 136 return '[]='; |
| 137 case '_negate': |
| 138 return 'unary-'; |
| 139 case '_constructor': |
| 140 case '_prototype': |
| 141 return $name.substring(1); |
| 142 } |
| 143 } |
| 144 return $name; |
| 145 })()'''); |
| 146 |
| 147 Symbol _dartSymbol(name) { |
| 148 return (JS('bool', 'typeof # === "symbol"', name)) |
| 149 ? JS('', '#(new #.es6(#, #))', const_, _internal.Symbol, |
| 150 _toSymbolName(name), name) |
| 151 : JS('', '#(#.new(#))', const_, Symbol, _toDisplayName(name)); |
| 152 } |
94 | 153 |
95 /// Extracts the named argument array from a list of arguments, and returns it. | 154 /// Extracts the named argument array from a list of arguments, and returns it. |
96 // TODO(jmesserly): we need to handle named arguments better. | 155 // TODO(jmesserly): we need to handle named arguments better. |
97 extractNamedArgs(args) { | 156 extractNamedArgs(args) { |
98 if (JS('bool', '#.length > 0', args)) { | 157 if (JS('bool', '#.length > 0', args)) { |
99 var last = JS('', '#[#.length - 1]', args, args); | 158 var last = JS('', '#[#.length - 1]', args, args); |
100 if (JS( | 159 if (JS( |
101 'bool', '# != null && #.__proto__ === Object.prototype', last, last)) { | 160 'bool', '# != null && #.__proto__ === Object.prototype', last, last)) { |
102 return JS('', '#.pop()', args); | 161 return JS('', '#.pop()', args); |
103 } | 162 } |
(...skipping 10 matching lines...) Expand all Loading... |
114 | 173 |
115 function callNSM() { | 174 function callNSM() { |
116 return $noSuchMethod(originalTarget, new $InvocationImpl( | 175 return $noSuchMethod(originalTarget, new $InvocationImpl( |
117 $name, $args, | 176 $name, $args, |
118 {namedArguments: $extractNamedArgs($args), isMethod: true})); | 177 {namedArguments: $extractNamedArgs($args), isMethod: true})); |
119 } | 178 } |
120 if (!($f instanceof Function)) { | 179 if (!($f instanceof Function)) { |
121 // We're not a function (and hence not a method either) | 180 // We're not a function (and hence not a method either) |
122 // Grab the `call` method if it's not a function. | 181 // Grab the `call` method if it's not a function. |
123 if ($f != null) { | 182 if ($f != null) { |
124 $ftype = $getMethodType($f, 'call'); | 183 $ftype = $getMethodType($getType($f), 'call'); |
125 $f = $f.call; | 184 $f = $f.call; |
126 } | 185 } |
127 if (!($f instanceof Function)) { | 186 if (!($f instanceof Function)) { |
128 return callNSM(); | 187 return callNSM(); |
129 } | 188 } |
130 } | 189 } |
131 // If f is a function, but not a method (no method type) | 190 // If f is a function, but not a method (no method type) |
132 // then it should have been a function valued field, so | 191 // then it should have been a function valued field, so |
133 // get the type from the function. | 192 // get the type from the function. |
134 if ($ftype === void 0) { | 193 if ($ftype === void 0) { |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
296 } | 355 } |
297 | 356 |
298 /// Shared code for dsend, dindex, and dsetindex. | 357 /// Shared code for dsend, dindex, and dsetindex. |
299 _callMethod(obj, name, typeArgs, args, displayName) { | 358 _callMethod(obj, name, typeArgs, args, displayName) { |
300 var symbol = _canonicalMember(obj, name); | 359 var symbol = _canonicalMember(obj, name); |
301 if (symbol == null) { | 360 if (symbol == null) { |
302 return noSuchMethod( | 361 return noSuchMethod( |
303 obj, new InvocationImpl(displayName, args, isMethod: true)); | 362 obj, new InvocationImpl(displayName, args, isMethod: true)); |
304 } | 363 } |
305 var f = obj != null ? JS('', '#[#]', obj, symbol) : null; | 364 var f = obj != null ? JS('', '#[#]', obj, symbol) : null; |
306 var ftype = getMethodType(obj, symbol); | 365 var type = getType(obj); |
| 366 var ftype = getMethodType(type, symbol); |
| 367 // No such method if dart object and ftype is missing. |
307 return _checkAndCall(f, ftype, obj, typeArgs, args, displayName); | 368 return _checkAndCall(f, ftype, obj, typeArgs, args, displayName); |
308 } | 369 } |
309 | 370 |
310 dsend(obj, method, @rest args) => _callMethod(obj, method, null, args, method); | 371 dsend(obj, method, @rest args) => _callMethod(obj, method, null, args, method); |
311 | 372 |
312 dgsend(obj, typeArgs, method, @rest args) => | 373 dgsend(obj, typeArgs, method, @rest args) => |
313 _callMethod(obj, method, typeArgs, args, method); | 374 _callMethod(obj, method, typeArgs, args, method); |
314 | 375 |
315 dindex(obj, index) => | 376 dindex(obj, index) => |
316 _callMethod(obj, '_get', null, JS('', '[#]', index), '[]'); | 377 _callMethod(obj, '_get', null, JS('', '[#]', index), '[]'); |
(...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
841 name = '+' + name; | 902 name = '+' + name; |
842 } | 903 } |
843 return name; | 904 return name; |
844 } | 905 } |
845 | 906 |
846 /// Emulates the implicit "loadLibrary" function provided by a deferred library. | 907 /// Emulates the implicit "loadLibrary" function provided by a deferred library. |
847 /// | 908 /// |
848 /// Libraries are not actually deferred in DDC, so this just returns a future | 909 /// Libraries are not actually deferred in DDC, so this just returns a future |
849 /// that completes immediately. | 910 /// that completes immediately. |
850 Future loadLibrary() => new Future.value(); | 911 Future loadLibrary() => new Future.value(); |
OLD | NEW |