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; |
| 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 type = getType(obj); |
| 54 var setter = getSetterType(type, f); | |
|
Jennifer Messerly
2017/01/24 03:51:03
Possibly calling this setterType would be a bit mo
Jacob
2017/01/24 19:12:32
agreed. cleaned up.
| |
| 55 if (JS('bool', '# != void 0', setter)) { | |
| 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]', setter))) { | |
| 59 return JS('', '#[#] = #', obj, f, value); | |
| 60 } | |
| 61 } else { | |
| 62 var field = getFieldType(type, f); | |
| 63 // TODO(jacobr): propagate metadata tracking which fields are private. | |
|
Jennifer Messerly
2017/01/24 03:51:03
What does this mean? It shouldn't be possible to g
Jacob
2017/01/24 19:12:32
Done.
It means I got distracted writing the commen
| |
| 64 if (JS('bool', '# != void 0', field)) { | |
| 65 // TODO(jacobr): throw a type error instead of a NoSuchMethodError if | |
| 66 // the type of the field doesn't match. | |
| 67 if (instanceOfOrNull(value, field)) { | |
| 68 return JS('', '#[#] = #', obj, f, value); | |
| 69 } | |
| 70 } | |
| 71 } | |
| 48 } | 72 } |
| 49 return noSuchMethod( | 73 return noSuchMethod( |
| 50 obj, new InvocationImpl(field, JS('', '[#]', value), isSetter: true)); | 74 obj, new InvocationImpl(field, JS('', '[#]', value), isSetter: true)); |
| 51 } | 75 } |
| 52 | 76 |
| 53 /// Check that a function of a given type can be applied to | 77 /// Check that a function of a given type can be applied to |
| 54 /// actuals. | 78 /// actuals. |
| 55 _checkApply(type, actuals) => JS( | 79 _checkApply(type, actuals) => JS( |
| 56 '', | 80 '', |
| 57 '''(() => { | 81 '''(() => { |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 82 if (names.length == 0) return false; | 106 if (names.length == 0) return false; |
| 83 for (var name of names) { | 107 for (var name of names) { |
| 84 if (!($hasOwnProperty.call($type.named, name))) { | 108 if (!($hasOwnProperty.call($type.named, name))) { |
| 85 return false; | 109 return false; |
| 86 } | 110 } |
| 87 $check(opts[name], $type.named[name]); | 111 $check(opts[name], $type.named[name]); |
| 88 } | 112 } |
| 89 return true; | 113 return true; |
| 90 })()'''); | 114 })()'''); |
| 91 | 115 |
| 92 Symbol _dartSymbol(name) => | 116 _toSymbolName(symbol) => JS( |
| 93 JS('', '#(#.new(#.toString()))', const_, Symbol, name); | 117 '', |
| 118 '''(() => { | |
| 119 let str = $symbol.toString(); | |
| 120 // Strip leading 'Symbol(' and trailing ')' | |
| 121 return str.substring(7, str.length-1); | |
| 122 })()'''); | |
| 123 | |
| 124 _toDisplayName(name) => JS( | |
| 125 '', | |
| 126 '''(() => { | |
| 127 // Names starting with _ are escaped names used to disambiguate Dart and | |
| 128 // JS names. | |
| 129 if ($name[0] === '_') { | |
| 130 // Inverse of | |
| 131 switch($name) { | |
| 132 case '_get': | |
| 133 return '[]'; | |
| 134 case '_set': | |
| 135 return '[]='; | |
| 136 case '_negate': | |
| 137 return 'unary-'; | |
| 138 case '_constructor': | |
| 139 case '_prototype': | |
| 140 return $name.substring(1); | |
| 141 } | |
| 142 } | |
| 143 return $name; | |
| 144 })()'''); | |
| 145 | |
| 146 Symbol _dartSymbol(name) { | |
| 147 return (JS('bool', 'typeof # === "symbol"', name)) | |
| 148 ? JS('', '#(new #.es6(#, #))', const_, _internal.Symbol, | |
| 149 _toSymbolName(name), name) | |
| 150 : JS('', '#(#.new(#))', const_, Symbol, _toDisplayName(name)); | |
| 151 } | |
| 94 | 152 |
| 95 /// Extracts the named argument array from a list of arguments, and returns it. | 153 /// Extracts the named argument array from a list of arguments, and returns it. |
| 96 // TODO(jmesserly): we need to handle named arguments better. | 154 // TODO(jmesserly): we need to handle named arguments better. |
| 97 extractNamedArgs(args) { | 155 extractNamedArgs(args) { |
| 98 if (JS('bool', '#.length > 0', args)) { | 156 if (JS('bool', '#.length > 0', args)) { |
| 99 var last = JS('', '#[#.length - 1]', args, args); | 157 var last = JS('', '#[#.length - 1]', args, args); |
| 100 if (JS( | 158 if (JS( |
| 101 'bool', '# != null && #.__proto__ === Object.prototype', last, last)) { | 159 'bool', '# != null && #.__proto__ === Object.prototype', last, last)) { |
| 102 return JS('', '#.pop()', args); | 160 return JS('', '#.pop()', args); |
| 103 } | 161 } |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 114 | 172 |
| 115 function callNSM() { | 173 function callNSM() { |
| 116 return $noSuchMethod(originalTarget, new $InvocationImpl( | 174 return $noSuchMethod(originalTarget, new $InvocationImpl( |
| 117 $name, $args, | 175 $name, $args, |
| 118 {namedArguments: $extractNamedArgs($args), isMethod: true})); | 176 {namedArguments: $extractNamedArgs($args), isMethod: true})); |
| 119 } | 177 } |
| 120 if (!($f instanceof Function)) { | 178 if (!($f instanceof Function)) { |
| 121 // We're not a function (and hence not a method either) | 179 // We're not a function (and hence not a method either) |
| 122 // Grab the `call` method if it's not a function. | 180 // Grab the `call` method if it's not a function. |
| 123 if ($f != null) { | 181 if ($f != null) { |
| 124 $ftype = $getMethodType($f, 'call'); | 182 $ftype = $getMethodType($getType($f), 'call'); |
| 125 $f = $f.call; | 183 $f = $f.call; |
| 126 } | 184 } |
| 127 if (!($f instanceof Function)) { | 185 if (!($f instanceof Function)) { |
| 128 return callNSM(); | 186 return callNSM(); |
| 129 } | 187 } |
| 130 } | 188 } |
| 131 // If f is a function, but not a method (no method type) | 189 // If f is a function, but not a method (no method type) |
| 132 // then it should have been a function valued field, so | 190 // then it should have been a function valued field, so |
| 133 // get the type from the function. | 191 // get the type from the function. |
| 134 if ($ftype === void 0) { | 192 if ($ftype === void 0) { |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 296 } | 354 } |
| 297 | 355 |
| 298 /// Shared code for dsend, dindex, and dsetindex. | 356 /// Shared code for dsend, dindex, and dsetindex. |
| 299 _callMethod(obj, name, typeArgs, args, displayName) { | 357 _callMethod(obj, name, typeArgs, args, displayName) { |
| 300 var symbol = _canonicalMember(obj, name); | 358 var symbol = _canonicalMember(obj, name); |
| 301 if (symbol == null) { | 359 if (symbol == null) { |
| 302 return noSuchMethod( | 360 return noSuchMethod( |
| 303 obj, new InvocationImpl(displayName, args, isMethod: true)); | 361 obj, new InvocationImpl(displayName, args, isMethod: true)); |
| 304 } | 362 } |
| 305 var f = obj != null ? JS('', '#[#]', obj, symbol) : null; | 363 var f = obj != null ? JS('', '#[#]', obj, symbol) : null; |
| 306 var ftype = getMethodType(obj, symbol); | 364 var type = getType(obj); |
| 365 var ftype = getMethodType(type, symbol); | |
| 366 // No such method if dart object and ftype is missing. | |
| 307 return _checkAndCall(f, ftype, obj, typeArgs, args, displayName); | 367 return _checkAndCall(f, ftype, obj, typeArgs, args, displayName); |
| 308 } | 368 } |
| 309 | 369 |
| 310 dsend(obj, method, @rest args) => _callMethod(obj, method, null, args, method); | 370 dsend(obj, method, @rest args) => _callMethod(obj, method, null, args, method); |
| 311 | 371 |
| 312 dgsend(obj, typeArgs, method, @rest args) => | 372 dgsend(obj, typeArgs, method, @rest args) => |
| 313 _callMethod(obj, method, typeArgs, args, method); | 373 _callMethod(obj, method, typeArgs, args, method); |
| 314 | 374 |
| 315 dindex(obj, index) => | 375 dindex(obj, index) => |
| 316 _callMethod(obj, '_get', null, JS('', '[#]', index), '[]'); | 376 _callMethod(obj, '_get', null, JS('', '[#]', index), '[]'); |
| (...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 841 name = '+' + name; | 901 name = '+' + name; |
| 842 } | 902 } |
| 843 return name; | 903 return name; |
| 844 } | 904 } |
| 845 | 905 |
| 846 /// Emulates the implicit "loadLibrary" function provided by a deferred library. | 906 /// Emulates the implicit "loadLibrary" function provided by a deferred library. |
| 847 /// | 907 /// |
| 848 /// Libraries are not actually deferred in DDC, so this just returns a future | 908 /// Libraries are not actually deferred in DDC, so this just returns a future |
| 849 /// that completes immediately. | 909 /// that completes immediately. |
| 850 Future loadLibrary() => new Future.value(); | 910 Future loadLibrary() => new Future.value(); |
| OLD | NEW |