Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(40)

Side by Side Diff: tool/input_sdk/private/ddc_runtime/operations.dart

Issue 2061373003: implement user-defined nSM, Object members on functions (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: fix Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 _canonicalFieldName(obj, name, args, displayName) => JS('', '''(() => { 9 class _Invocation extends Invocation {
10 $name = $canonicalMember($obj, $name); 10 final Symbol memberName;
11 if ($name) return $name; 11 final List positionalArguments;
12 // TODO(jmesserly): in the future we might have types that "overlay" Dart 12 final Map<Symbol, dynamic> namedArguments;
13 // methods while also exposing the full native API, e.g. dart:html vs 13 final bool isMethod;
14 // dart:dom. To support that we'd need to fall back to the normal name 14 final bool isGetter;
15 // if an extension method wasn't found. 15 final bool isSetter;
16 $throwNoSuchMethodFunc($obj, $displayName, $args);
17 })()''');
18 16
19 dload(obj, field) => JS('', '''(() => { 17 _Invocation(String memberName, this.positionalArguments,
20 $field = $_canonicalFieldName($obj, $field, [], $field); 18 {namedArguments,
21 $_trackCall($obj, $field); 19 this.isMethod: false,
22 if ($hasMethod($obj, $field)) { 20 this.isGetter: false,
23 return $bind($obj, $field); 21 this.isSetter: false})
22 : memberName = _dartSymbol(memberName),
23 namedArguments = _namedArgsToSymbols(namedArguments);
24
25 static Map<Symbol, dynamic> _namedArgsToSymbols(namedArgs) {
26 if (namedArgs == null) return {};
27 return new Map.fromIterable(
28 getOwnPropertyNames(namedArgs),
29 key: _dartSymbol,
30 value: (k) => JS('', '#[#]', namedArgs, k));
24 } 31 }
25 // TODO(vsm): Implement NSM robustly. An 'in' check breaks on certain 32 }
26 // types. hasOwnProperty doesn't chase the proto chain.
27 // Also, do we want an NSM on regular JS objects?
28 // See: https://github.com/dart-lang/dev_compiler/issues/169
29 let result = $obj[$field];
30 return result;
31 })()''');
32 33
33 dput(obj, field, value) => JS('', '''(() => { 34 dload(obj, field) {
34 $field = $_canonicalFieldName($obj, $field, [$value], $field); 35 var f = _canonicalMember(obj, field);
35 $_trackCall($obj, $field); 36 _trackCall(obj, f);
37 if (f != null) {
38 if (hasMethod(obj, f)) return bind(obj, f, JS('', 'void 0'));
39 return JS('', '#[#]', obj, f);
40 }
41 return noSuchMethod(obj,
42 new _Invocation(field, JS('', '[]'), isGetter: true));
43 }
36 44
37 // TODO(vsm): Implement NSM and type checks. 45 dput(obj, field, value) {
38 // See: https://github.com/dart-lang/dev_compiler/issues/170 46 var f = _canonicalMember(obj, field);
39 $obj[$field] = $value; 47 _trackCall(obj, f);
40 return $value; 48 if (f != null) {
41 })()'''); 49 return JS('', '#[#] = #', obj, f, value);
50 }
51 return noSuchMethod(obj,
52 new _Invocation(field, JS('', '[#]', value), isSetter: true));
53 }
42 54
43 /// Check that a function of a given type can be applied to 55 /// Check that a function of a given type can be applied to
44 /// actuals. 56 /// actuals.
45 _checkApply(type, actuals) => JS('', '''(() => { 57 _checkApply(type, actuals) => JS('', '''(() => {
46 if ($actuals.length < $type.args.length) return false; 58 if ($actuals.length < $type.args.length) return false;
47 let index = 0; 59 let index = 0;
48 for(let i = 0; i < $type.args.length; ++i) { 60 for(let i = 0; i < $type.args.length; ++i) {
49 if (!$instanceOfOrNull($actuals[i], $type.args[i])) return false; 61 if (!$instanceOfOrNull($actuals[i], $type.args[i])) return false;
50 ++index; 62 ++index;
51 } 63 }
(...skipping 18 matching lines...) Expand all
70 if (names.length == 0) return false; 82 if (names.length == 0) return false;
71 for (var name of names) { 83 for (var name of names) {
72 if (!($hasOwnProperty.call($type.named, name))) { 84 if (!($hasOwnProperty.call($type.named, name))) {
73 return false; 85 return false;
74 } 86 }
75 if (!$instanceOfOrNull(opts[name], $type.named[name])) return false; 87 if (!$instanceOfOrNull(opts[name], $type.named[name])) return false;
76 } 88 }
77 return true; 89 return true;
78 })()'''); 90 })()''');
79 91
80 _dartSymbol(name) => JS('', ''' 92 Symbol _dartSymbol(name) =>
81 $const_($Symbol.new($name.toString())) 93 JS('', '#(#.new(#.toString()))', const_, Symbol, name);
82 ''');
83 94
84 throwNoSuchMethod(obj, name, pArgs, nArgs, extras) => JS('', '''(() => { 95 // TODO(jmesserly): we need to handle named arguments better.
85 $throw_(new $NoSuchMethodError($obj, $_dartSymbol($name), $pArgs, $nArgs, $ext ras));
86 })()''');
87
88 throwNoSuchMethodFunc(obj, name, pArgs, opt_func) => JS('', '''(() => {
89 if ($obj === void 0) $obj = $opt_func;
90 $throwNoSuchMethod($obj, $name, $pArgs);
91 })()''');
92
93 _checkAndCall(f, ftype, obj, typeArgs, args, name) => JS('', '''(() => { 96 _checkAndCall(f, ftype, obj, typeArgs, args, name) => JS('', '''(() => {
94 $_trackCall($obj, $name); 97 $_trackCall($obj, $name);
95 98
96 let originalFunction = $f; 99 let originalTarget = obj === void 0 ? f : obj;
100
101 function callNSM() {
102 let namedArgs = null;
103 if (args.length > 0 &&
104 args[args.length - 1].__proto__ == Object.prototype) {
105 namedArgs = args.pop();
106 }
107 return $noSuchMethod(originalTarget, new $_Invocation(
108 $name, $args, {namedArguments: namedArgs, isMethod: true}));
109 }
97 if (!($f instanceof Function)) { 110 if (!($f instanceof Function)) {
98 // We're not a function (and hence not a method either) 111 // We're not a function (and hence not a method either)
99 // Grab the `call` method if it's not a function. 112 // Grab the `call` method if it's not a function.
100 if ($f != null) { 113 if ($f != null) {
101 $ftype = $getMethodType($f, 'call'); 114 $ftype = $getMethodType($f, 'call');
102 $f = $f.call; 115 $f = $f.call;
103 } 116 }
104 if (!($f instanceof Function)) { 117 if (!($f instanceof Function)) {
105 $throwNoSuchMethodFunc($obj, $name, $args, originalFunction); 118 return callNSM();
106 } 119 }
107 } 120 }
108 // If f is a function, but not a method (no method type) 121 // If f is a function, but not a method (no method type)
109 // then it should have been a function valued field, so 122 // then it should have been a function valued field, so
110 // get the type from the function. 123 // get the type from the function.
111 if ($ftype === void 0) { 124 if ($ftype === void 0) {
112 $ftype = $_getRuntimeType($f); 125 $ftype = $_getRuntimeType($f);
113 } 126 }
114 127
115 if (!$ftype) { 128 if (!$ftype) {
(...skipping 29 matching lines...) Expand all
145 if ($_checkApply($ftype, $args)) { 158 if ($_checkApply($ftype, $args)) {
146 if ($typeArgs != null) { 159 if ($typeArgs != null) {
147 return $f.apply($obj, $typeArgs).apply($obj, $args); 160 return $f.apply($obj, $typeArgs).apply($obj, $args);
148 } 161 }
149 return $f.apply($obj, $args); 162 return $f.apply($obj, $args);
150 } 163 }
151 164
152 // TODO(leafp): throw a type error (rather than NSM) 165 // TODO(leafp): throw a type error (rather than NSM)
153 // if the arity matches but the types are wrong. 166 // if the arity matches but the types are wrong.
154 // TODO(jmesserly): nSM should include type args? 167 // TODO(jmesserly): nSM should include type args?
155 $throwNoSuchMethodFunc($obj, $name, $args, originalFunction); 168 return callNSM();
156 })()'''); 169 })()''');
157 170
158 dcall(f, @rest args) => _checkAndCall( 171 dcall(f, @rest args) => _checkAndCall(
159 f, _getRuntimeType(f), JS('', 'void 0'), null, args, 'call'); 172 f, _getRuntimeType(f), JS('', 'void 0'), null, args, 'call');
160 173
161
162 dgcall(f, typeArgs, @rest args) => _checkAndCall( 174 dgcall(f, typeArgs, @rest args) => _checkAndCall(
163 f, _getRuntimeType(f), JS('', 'void 0'), typeArgs, args, 'call'); 175 f, _getRuntimeType(f), JS('', 'void 0'), typeArgs, args, 'call');
164 176
165 Map<String, int> _callMethodStats = new Map(); 177 Map<String, int> _callMethodStats = new Map();
166 178
167 List<List<Object>> getDynamicStats() { 179 List<List<Object>> getDynamicStats() {
168 List<List<Object>> ret = []; 180 List<List<Object>> ret = [];
169 181
170 var keys = _callMethodStats.keys.toList(); 182 var keys = _callMethodStats.keys.toList();
171 183
(...skipping 30 matching lines...) Expand all
202 name = "${typeName(actual)}.$name <$src>"; 214 name = "${typeName(actual)}.$name <$src>";
203 if (_callMethodStats.containsKey(name)) { 215 if (_callMethodStats.containsKey(name)) {
204 _callMethodStats[name] = _callMethodStats[name] + 1; 216 _callMethodStats[name] = _callMethodStats[name] + 1;
205 } else { 217 } else {
206 _callMethodStats[name] = 1; 218 _callMethodStats[name] = 1;
207 } 219 }
208 } 220 }
209 221
210 /// Shared code for dsend, dindex, and dsetindex. 222 /// Shared code for dsend, dindex, and dsetindex.
211 _callMethod(obj, name, typeArgs, args, displayName) { 223 _callMethod(obj, name, typeArgs, args, displayName) {
212 var symbol = _canonicalFieldName(obj, name, args, displayName); 224 var symbol = _canonicalMember(obj, name);
225 if (symbol == null) {
226 return noSuchMethod(obj,
227 new _Invocation(displayName, args, isMethod: true));
228 }
213 var f = obj != null ? JS('', '#[#]', obj, symbol) : null; 229 var f = obj != null ? JS('', '#[#]', obj, symbol) : null;
214 var ftype = getMethodType(obj, symbol); 230 var ftype = getMethodType(obj, symbol);
215 return _checkAndCall(f, ftype, obj, typeArgs, args, displayName); 231 return _checkAndCall(f, ftype, obj, typeArgs, args, displayName);
216 } 232 }
217 233
218 dsend(obj, method, @rest args) => _callMethod(obj, method, null, args, method); 234 dsend(obj, method, @rest args) => _callMethod(obj, method, null, args, method);
219 235
220 dgsend(obj, typeArgs, method, @rest args) => 236 dgsend(obj, typeArgs, method, @rest args) =>
221 _callMethod(obj, method, typeArgs, args, method); 237 _callMethod(obj, method, typeArgs, args, method);
222 238
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after
604 // the compiler. 620 // the compiler.
605 hashCode(obj) { 621 hashCode(obj) {
606 if (obj == null) return 0; 622 if (obj == null) return 0;
607 623
608 switch (JS('String', 'typeof #', obj)) { 624 switch (JS('String', 'typeof #', obj)) {
609 case "number": 625 case "number":
610 return JS('','# & 0x1FFFFFFF', obj); 626 return JS('','# & 0x1FFFFFFF', obj);
611 case "boolean": 627 case "boolean":
612 // From JSBool.hashCode, see comment there. 628 // From JSBool.hashCode, see comment there.
613 return JS('', '# ? (2 * 3 * 23 * 3761) : (269 * 811)', obj); 629 return JS('', '# ? (2 * 3 * 23 * 3761) : (269 * 811)', obj);
630 case "function":
631 // TODO(jmesserly): this doesn't work for method tear-offs.
632 return Primitives.objectHashCode(obj);
614 } 633 }
615 634
616 var extension = getExtensionType(obj); 635 var extension = getExtensionType(obj);
617 if (extension != null) { 636 if (extension != null) {
618 return JS('', '#[dartx.hashCode]', obj); 637 return JS('', '#[dartx.hashCode]', obj);
619 } 638 }
620 return JS('', '#.hashCode', obj); 639 return JS('', '#.hashCode', obj);
621 } 640 }
622 641
623 @JSExportName('toString') 642 @JSExportName('toString')
624 String _toString(obj) { 643 String _toString(obj) {
625 if (obj == null) return "null"; 644 if (obj == null) return "null";
626 645
627 var extension = getExtensionType(obj); 646 var extension = getExtensionType(obj);
628 if (extension != null) { 647 if (extension != null) {
629 return JS('String', '#[dartx.toString]()', obj); 648 return JS('String', '#[dartx.toString]()', obj);
630 } 649 }
650 if (JS('bool', 'typeof # == "function"', obj)) {
651 return JS('String', r'"Closure: " + # + " from: " + #',
652 getReifiedType(obj), obj);
653 }
631 // TODO(jmesserly): restore this faster path once ES Symbol is treated as 654 // TODO(jmesserly): restore this faster path once ES Symbol is treated as
632 // an extension type (and thus hits the above code path). 655 // an extension type (and thus hits the above code path).
633 // See https://github.com/dart-lang/dev_compiler/issues/578. 656 // See https://github.com/dart-lang/dev_compiler/issues/578.
634 // return JS('', '"" + #', obj); 657 // return JS('', '"" + #', obj);
635 return JS('String', '#.toString()', obj); 658 return JS('String', '#.toString()', obj);
636 } 659 }
637 660
638 // TODO(jmesserly): is the argument type verified statically? 661 // TODO(jmesserly): is the argument type verified statically?
639 noSuchMethod(obj, Invocation invocation) { 662 noSuchMethod(obj, Invocation invocation) {
640 if (obj == null) { 663 if (obj == null || JS('bool', 'typeof # == "function"', obj)) {
641 throw new NoSuchMethodError( 664 throw new NoSuchMethodError(
642 null, 665 obj,
643 invocation.memberName, 666 invocation.memberName,
644 invocation.positionalArguments, 667 invocation.positionalArguments,
645 invocation.namedArguments); 668 invocation.namedArguments);
646 } 669 }
647 // Delegate to the (possibly user-defined) method on the object. 670 // Delegate to the (possibly user-defined) method on the object.
648 var extension = getExtensionType(obj); 671 var extension = getExtensionType(obj);
649 if (extension != null) { 672 if (extension != null) {
650 return JS('', '#[dartx.noSuchMethod](#)', obj, invocation); 673 return JS('', '#[dartx.noSuchMethod](#)', obj, invocation);
651 } 674 }
652 return JS('', '#.noSuchMethod(#)', obj, invocation); 675 return JS('', '#.noSuchMethod(#)', obj, invocation);
653 } 676 }
654 677
655 constFn(x) => JS('', '() => x'); 678 constFn(x) => JS('', '() => x');
656 679
657 runtimeType(obj) { 680 runtimeType(obj) {
658 // Handle primitives where the method isn't on the object. 681 // Handle primitives where the method isn't on the object.
659 var result = _checkPrimitiveType(obj); 682 var result = _checkPrimitiveType(obj);
660 if (result != null) return wrapType(result); 683 if (result != null) return wrapType(result);
661 684
662 // Delegate to the (possibly user-defined) method on the object. 685 // Delegate to the (possibly user-defined) method on the object.
663 var extension = getExtensionType(obj); 686 var extension = getExtensionType(obj);
664 if (extension != null) { 687 if (extension != null) {
665 return JS('', '#[dartx.runtimeType]', obj); 688 return JS('', '#[dartx.runtimeType]', obj);
666 } 689 }
690 if (JS('bool', 'typeof # == "function"', obj)) {
691 return wrapType(getReifiedType(obj));
692 }
667 return JS('', '#.runtimeType', obj); 693 return JS('', '#.runtimeType', obj);
668 } 694 }
669 695
670 /// Implements Dart's interpolated strings as ES2015 tagged template literals. 696 /// Implements Dart's interpolated strings as ES2015 tagged template literals.
671 /// 697 ///
672 /// For example: dart.str`hello ${name}` 698 /// For example: dart.str`hello ${name}`
673 String str(strings, @rest values) => JS('', '''(() => { 699 String str(strings, @rest values) => JS('', '''(() => {
674 let s = $strings[0]; 700 let s = $strings[0];
675 for (let i = 0, len = $values.length; i < len; ) { 701 for (let i = 0, len = $values.length; i < len; ) {
676 s += $notNull($_toString($values[i])) + $strings[++i]; 702 s += $notNull($_toString($values[i])) + $strings[++i];
677 } 703 }
678 return s; 704 return s;
679 })()'''); 705 })()''');
680 706
681 707
682 final JsIterator = JS('', ''' 708 final JsIterator = JS('', '''
683 class JsIterator { 709 class JsIterator {
684 constructor(dartIterator) { 710 constructor(dartIterator) {
685 this.dartIterator = dartIterator; 711 this.dartIterator = dartIterator;
686 } 712 }
687 next() { 713 next() {
688 let i = this.dartIterator; 714 let i = this.dartIterator;
689 let done = !i.moveNext(); 715 let done = !i.moveNext();
690 return { done: done, value: done ? void 0 : i.current }; 716 return { done: done, value: done ? void 0 : i.current };
691 } 717 }
692 } 718 }
693 '''); 719 ''');
720
721 _canonicalMember(obj, name) {
722 // Private names are symbols and are already canonical.
723 if (JS('bool', 'typeof # === "symbol"', name)) return name;
724
725 if (obj != null && getExtensionType(obj) != null) {
726 return JS('', 'dartx.#', name);
727 }
728
729 // Check for certain names that we can't use in JS
730 if (name == 'constructor' || name == 'prototype') {
731 name = '+' + name;
732 }
733 return name;
734 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698