| 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 |