OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 part of js_backend; | 5 part of js_backend; |
6 | 6 |
7 typedef void Recompile(Element element); | 7 typedef void Recompile(Element element); |
8 | 8 |
9 class ReturnInfo { | 9 class ReturnInfo { |
10 HType returnType; | 10 HType returnType; |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 result.types[i] = types[node.inputs[i + 1]]; | 94 result.types[i] = types[node.inputs[i + 1]]; |
95 } | 95 } |
96 return result; | 96 return result; |
97 } | 97 } |
98 | 98 |
99 factory HTypeList.fromDynamicInvocation(HInvokeDynamic node, | 99 factory HTypeList.fromDynamicInvocation(HInvokeDynamic node, |
100 Selector selector, | 100 Selector selector, |
101 HTypeMap types) { | 101 HTypeMap types) { |
102 HTypeList result; | 102 HTypeList result; |
103 int argumentsCount = node.inputs.length - 1; | 103 int argumentsCount = node.inputs.length - 1; |
| 104 int startInvokeIndex = HInvoke.ARGUMENTS_OFFSET; |
| 105 |
| 106 if (node.isInterceptorCall) { |
| 107 argumentsCount--; |
| 108 startInvokeIndex++; |
| 109 } |
| 110 |
104 if (selector.namedArgumentCount > 0) { | 111 if (selector.namedArgumentCount > 0) { |
105 result = | 112 result = |
106 new HTypeList.withNamedArguments( | 113 new HTypeList.withNamedArguments( |
107 argumentsCount, selector.namedArguments); | 114 argumentsCount, selector.namedArguments); |
108 } else { | 115 } else { |
109 result = new HTypeList(argumentsCount); | 116 result = new HTypeList(argumentsCount); |
110 } | 117 } |
| 118 |
111 for (int i = 0; i < result.types.length; i++) { | 119 for (int i = 0; i < result.types.length; i++) { |
112 result.types[i] = types[node.inputs[i + 1]]; | 120 result.types[i] = types[node.inputs[i + startInvokeIndex]]; |
113 } | 121 } |
114 return result; | 122 return result; |
115 } | 123 } |
116 | 124 |
117 static const HTypeList ALL_UNKNOWN = const HTypeList.withAllUnknown(); | 125 static const HTypeList ALL_UNKNOWN = const HTypeList.withAllUnknown(); |
118 | 126 |
119 bool get allUnknown => types == null; | 127 bool get allUnknown => types == null; |
120 bool get hasNamedArguments => namedArguments != null; | 128 bool get hasNamedArguments => namedArguments != null; |
121 int get length => types.length; | 129 int get length => types.length; |
122 HType operator[](int index) => types[index]; | 130 HType operator[](int index) => types[index]; |
(...skipping 12 matching lines...) Expand all Loading... |
135 result.types.setRange(0, i, this.types); | 143 result.types.setRange(0, i, this.types); |
136 } | 144 } |
137 if (result != this) { | 145 if (result != this) { |
138 result.types[i] = newType; | 146 result.types[i] = newType; |
139 } | 147 } |
140 if (result[i] != HType.UNKNOWN) onlyUnknown = false; | 148 if (result[i] != HType.UNKNOWN) onlyUnknown = false; |
141 } | 149 } |
142 return onlyUnknown ? HTypeList.ALL_UNKNOWN : result; | 150 return onlyUnknown ? HTypeList.ALL_UNKNOWN : result; |
143 } | 151 } |
144 | 152 |
145 /** | |
146 * Create the union of this [HTypeList] object with the types used by | |
147 * the [node]. If the union results in exactly the same types the receiver | |
148 * is returned. Otherwise a different [HTypeList] object is returned | |
149 * with the type union information. | |
150 */ | |
151 HTypeList unionWithInvoke(HInvoke node, HTypeMap types, Compiler compiler) { | |
152 // Union an all unknown list with something stays all unknown. | |
153 if (allUnknown) return this; | |
154 | |
155 bool allUnknown = true; | |
156 if (length != node.inputs.length - 1) { | |
157 return HTypeList.ALL_UNKNOWN; | |
158 } | |
159 | |
160 bool onlyUnknown = true; | |
161 HTypeList result = this; | |
162 for (int i = 0; i < length; i++) { | |
163 HType newType = this[i].union(types[node.inputs[i + 1]], compiler); | |
164 if (result == this && newType != this[i]) { | |
165 // Create a new argument types object with the matching types copied. | |
166 result = new HTypeList(length); | |
167 result.types.setRange(0, i, this.types); | |
168 } | |
169 if (result != this) { | |
170 result.types[i] = newType; | |
171 } | |
172 if (result[i] != HType.UNKNOWN) onlyUnknown = false; | |
173 } | |
174 return onlyUnknown ? HTypeList.ALL_UNKNOWN : result; | |
175 } | |
176 | |
177 HTypeList unionWithOptionalParameters( | 153 HTypeList unionWithOptionalParameters( |
178 Selector selector, | 154 Selector selector, |
179 FunctionSignature signature, | 155 FunctionSignature signature, |
180 OptionalParameterTypes defaultValueTypes) { | 156 OptionalParameterTypes defaultValueTypes) { |
181 assert(allUnknown || selector.argumentCount == this.length); | 157 assert(allUnknown || selector.argumentCount == this.length); |
182 // Create a new HTypeList for holding types for all parameters. | 158 // Create a new HTypeList for holding types for all parameters. |
183 HTypeList result = new HTypeList(signature.parameterCount); | 159 HTypeList result = new HTypeList(signature.parameterCount); |
184 | 160 |
185 // First fill in the type of the positional arguments. | 161 // First fill in the type of the positional arguments. |
186 int nextTypeIndex = -1; | 162 int nextTypeIndex = -1; |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
466 optimizedStaticFunctions = new Set<Element>(), | 442 optimizedStaticFunctions = new Set<Element>(), |
467 selectorTypeMap = new SelectorMap<HTypeList>(backend.compiler), | 443 selectorTypeMap = new SelectorMap<HTypeList>(backend.compiler), |
468 optimizedFunctions = new FunctionSet(backend.compiler), | 444 optimizedFunctions = new FunctionSet(backend.compiler), |
469 optimizedTypes = new Map<Element, HTypeList>(), | 445 optimizedTypes = new Map<Element, HTypeList>(), |
470 optimizedDefaultValueTypes = | 446 optimizedDefaultValueTypes = |
471 new Map<Element, OptionalParameterTypes>(), | 447 new Map<Element, OptionalParameterTypes>(), |
472 this.backend = backend; | 448 this.backend = backend; |
473 | 449 |
474 Compiler get compiler => backend.compiler; | 450 Compiler get compiler => backend.compiler; |
475 | 451 |
| 452 bool updateTypes(HTypeList oldTypes, HTypeList newTypes, var key, var map) { |
| 453 if (oldTypes.allUnknown) return false; |
| 454 newTypes = oldTypes.union(newTypes, backend.compiler); |
| 455 if (identical(newTypes, oldTypes)) return false; |
| 456 map[key] = newTypes; |
| 457 return true; |
| 458 } |
| 459 |
476 void registerStaticInvocation(HInvokeStatic node, HTypeMap types) { | 460 void registerStaticInvocation(HInvokeStatic node, HTypeMap types) { |
477 Element element = node.element; | 461 Element element = node.element; |
478 assert(invariant(node, element.isDeclaration)); | 462 assert(invariant(node, element.isDeclaration)); |
479 HTypeList oldTypes = staticTypeMap[element]; | 463 HTypeList oldTypes = staticTypeMap[element]; |
| 464 HTypeList newTypes = new HTypeList.fromStaticInvocation(node, types); |
480 if (oldTypes == null) { | 465 if (oldTypes == null) { |
481 staticTypeMap[element] = new HTypeList.fromStaticInvocation(node, types); | |
482 } else { | |
483 if (oldTypes.allUnknown) return; | |
484 HTypeList newTypes = | |
485 oldTypes.unionWithInvoke(node, types, backend.compiler); | |
486 if (identical(newTypes, oldTypes)) return; | |
487 staticTypeMap[element] = newTypes; | 466 staticTypeMap[element] = newTypes; |
| 467 } else if (updateTypes(oldTypes, newTypes, element, staticTypeMap)) { |
488 if (optimizedStaticFunctions.contains(element)) { | 468 if (optimizedStaticFunctions.contains(element)) { |
489 backend.scheduleForRecompilation(element); | 469 backend.scheduleForRecompilation(element); |
490 } | 470 } |
491 } | 471 } |
492 } | 472 } |
493 | 473 |
494 void registerNonCallStaticUse(HStatic node) { | 474 void registerNonCallStaticUse(HStatic node) { |
495 // When a static is used for anything else than a call target we cannot | 475 // When a static is used for anything else than a call target we cannot |
496 // infer anything about its parameter types. | 476 // infer anything about its parameter types. |
497 Element element = node.element; | 477 Element element = node.element; |
(...skipping 19 matching lines...) Expand all Loading... |
517 resolverWorld.hasInvokedGetter(element, compiler))) { | 497 resolverWorld.hasInvokedGetter(element, compiler))) { |
518 return; | 498 return; |
519 } | 499 } |
520 | 500 |
521 HTypeList providedTypes = | 501 HTypeList providedTypes = |
522 new HTypeList.fromDynamicInvocation(node, selector, types); | 502 new HTypeList.fromDynamicInvocation(node, selector, types); |
523 if (!selectorTypeMap.containsKey(selector)) { | 503 if (!selectorTypeMap.containsKey(selector)) { |
524 selectorTypeMap[selector] = providedTypes; | 504 selectorTypeMap[selector] = providedTypes; |
525 } else { | 505 } else { |
526 HTypeList oldTypes = selectorTypeMap[selector]; | 506 HTypeList oldTypes = selectorTypeMap[selector]; |
527 HTypeList newTypes = | 507 updateTypes(oldTypes, providedTypes, selector, selectorTypeMap); |
528 oldTypes.unionWithInvoke(node, types, backend.compiler); | |
529 if (identical(newTypes, oldTypes)) return; | |
530 selectorTypeMap[selector] = newTypes; | |
531 } | 508 } |
532 | 509 |
533 // If we're not compiling, we don't have to do anything. | 510 // If we're not compiling, we don't have to do anything. |
534 if (compiler.phase != Compiler.PHASE_COMPILING) return; | 511 if (compiler.phase != Compiler.PHASE_COMPILING) return; |
535 | 512 |
536 // Run through all optimized functions and figure out if they need | 513 // Run through all optimized functions and figure out if they need |
537 // to be recompiled because of this new invocation. | 514 // to be recompiled because of this new invocation. |
538 optimizedFunctions.filterBySelector(selector).forEach((Element element) { | 515 optimizedFunctions.filterBySelector(selector).forEach((Element element) { |
539 // TODO(kasperl): Maybe check if the element is already marked for | 516 // TODO(kasperl): Maybe check if the element is already marked for |
540 // recompilation? Could be pretty cheap compared to computing | 517 // recompilation? Could be pretty cheap compared to computing |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
651 ClassElement jsNumberClass; | 628 ClassElement jsNumberClass; |
652 ClassElement jsIntClass; | 629 ClassElement jsIntClass; |
653 ClassElement jsDoubleClass; | 630 ClassElement jsDoubleClass; |
654 ClassElement jsFunctionClass; | 631 ClassElement jsFunctionClass; |
655 ClassElement jsNullClass; | 632 ClassElement jsNullClass; |
656 ClassElement jsBoolClass; | 633 ClassElement jsBoolClass; |
657 ClassElement objectInterceptorClass; | 634 ClassElement objectInterceptorClass; |
658 Element jsArrayLength; | 635 Element jsArrayLength; |
659 Element jsStringLength; | 636 Element jsStringLength; |
660 Element getInterceptorMethod; | 637 Element getInterceptorMethod; |
| 638 Element arrayInterceptor; |
| 639 Element boolInterceptor; |
| 640 Element doubleInterceptor; |
| 641 Element functionInterceptor; |
| 642 Element intInterceptor; |
| 643 Element nullInterceptor; |
| 644 Element numberInterceptor; |
| 645 Element stringInterceptor; |
661 bool _interceptorsAreInitialized = false; | 646 bool _interceptorsAreInitialized = false; |
662 | 647 |
663 final Namer namer; | 648 final Namer namer; |
664 | 649 |
665 /** | 650 /** |
666 * Interface used to determine if an object has the JavaScript | 651 * Interface used to determine if an object has the JavaScript |
667 * indexing behavior. The interface is only visible to specific | 652 * indexing behavior. The interface is only visible to specific |
668 * libraries. | 653 * libraries. |
669 */ | 654 */ |
670 ClassElement jsIndexingBehaviorInterface; | 655 ClassElement jsIndexingBehaviorInterface; |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
781 jsFunctionClass = | 766 jsFunctionClass = |
782 compiler.findInterceptor(const SourceString('JSFunction')); | 767 compiler.findInterceptor(const SourceString('JSFunction')); |
783 jsBoolClass = | 768 jsBoolClass = |
784 compiler.findInterceptor(const SourceString('JSBool')); | 769 compiler.findInterceptor(const SourceString('JSBool')); |
785 jsArrayClass.ensureResolved(compiler); | 770 jsArrayClass.ensureResolved(compiler); |
786 jsArrayLength = | 771 jsArrayLength = |
787 jsArrayClass.lookupLocalMember(const SourceString('length')); | 772 jsArrayClass.lookupLocalMember(const SourceString('length')); |
788 jsStringClass.ensureResolved(compiler); | 773 jsStringClass.ensureResolved(compiler); |
789 jsStringLength = | 774 jsStringLength = |
790 jsStringClass.lookupLocalMember(const SourceString('length')); | 775 jsStringClass.lookupLocalMember(const SourceString('length')); |
| 776 |
| 777 arrayInterceptor = |
| 778 compiler.findInterceptor(const SourceString('arrayInterceptor')); |
| 779 boolInterceptor = |
| 780 compiler.findInterceptor(const SourceString('boolInterceptor')); |
| 781 doubleInterceptor = |
| 782 compiler.findInterceptor(const SourceString('doubleInterceptor')); |
| 783 functionInterceptor = |
| 784 compiler.findInterceptor(const SourceString('functionInterceptor')); |
| 785 intInterceptor = |
| 786 compiler.findInterceptor(const SourceString('intInterceptor')); |
| 787 nullInterceptor = |
| 788 compiler.findInterceptor(const SourceString('nullInterceptor')); |
| 789 stringInterceptor = |
| 790 compiler.findInterceptor(const SourceString('stringInterceptor')); |
| 791 numberInterceptor = |
| 792 compiler.findInterceptor(const SourceString('numberInterceptor')); |
791 } | 793 } |
792 | 794 |
793 void addInterceptors(ClassElement cls) { | 795 void addInterceptors(ClassElement cls) { |
794 cls.ensureResolved(compiler); | 796 cls.ensureResolved(compiler); |
795 cls.forEachMember((ClassElement classElement, Element member) { | 797 cls.forEachMember((ClassElement classElement, Element member) { |
796 Set<Element> set = interceptedElements.putIfAbsent( | 798 Set<Element> set = interceptedElements.putIfAbsent( |
797 member.name, () => new Set<Element>()); | 799 member.name, () => new Set<Element>()); |
798 set.add(member); | 800 set.add(member); |
799 }, | 801 }, |
800 includeSuperMembers: true); | 802 includeSuperMembers: true); |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1100 print("Inferred return types:"); | 1102 print("Inferred return types:"); |
1101 print("----------------------"); | 1103 print("----------------------"); |
1102 dumpReturnTypes(); | 1104 dumpReturnTypes(); |
1103 print(""); | 1105 print(""); |
1104 print("Inferred field types:"); | 1106 print("Inferred field types:"); |
1105 print("------------------------"); | 1107 print("------------------------"); |
1106 fieldTypes.dump(); | 1108 fieldTypes.dump(); |
1107 print(""); | 1109 print(""); |
1108 } | 1110 } |
1109 } | 1111 } |
OLD | NEW |