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 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 |
476 void registerStaticInvocation(HInvokeStatic node, HTypeMap types) { | 452 void registerStaticInvocation(HInvokeStatic node, HTypeMap types) { |
477 Element element = node.element; | 453 Element element = node.element; |
478 assert(invariant(node, element.isDeclaration)); | 454 assert(invariant(node, element.isDeclaration)); |
479 HTypeList oldTypes = staticTypeMap[element]; | 455 HTypeList oldTypes = staticTypeMap[element]; |
456 HTypeList newTypes = new HTypeList.fromStaticInvocation(node, types); | |
480 if (oldTypes == null) { | 457 if (oldTypes == null) { |
481 staticTypeMap[element] = new HTypeList.fromStaticInvocation(node, types); | 458 staticTypeMap[element] = newTypes; |
482 } else { | 459 } else { |
483 if (oldTypes.allUnknown) return; | 460 if (oldTypes.allUnknown) return; |
484 HTypeList newTypes = | 461 newTypes = oldTypes.union(newTypes, backend.compiler); |
485 oldTypes.unionWithInvoke(node, types, backend.compiler); | |
486 if (identical(newTypes, oldTypes)) return; | 462 if (identical(newTypes, oldTypes)) return; |
487 staticTypeMap[element] = newTypes; | 463 staticTypeMap[element] = newTypes; |
ahe
2012/11/27 10:19:11
Seems like the above lines should be a helper meth
ngeoffray
2012/11/27 10:41:04
Good refactoring suggestion. Done.
| |
488 if (optimizedStaticFunctions.contains(element)) { | 464 if (optimizedStaticFunctions.contains(element)) { |
489 backend.scheduleForRecompilation(element); | 465 backend.scheduleForRecompilation(element); |
490 } | 466 } |
491 } | 467 } |
492 } | 468 } |
493 | 469 |
494 void registerNonCallStaticUse(HStatic node) { | 470 void registerNonCallStaticUse(HStatic node) { |
495 // When a static is used for anything else than a call target we cannot | 471 // When a static is used for anything else than a call target we cannot |
496 // infer anything about its parameter types. | 472 // infer anything about its parameter types. |
497 Element element = node.element; | 473 Element element = node.element; |
(...skipping 19 matching lines...) Expand all Loading... | |
517 resolverWorld.hasInvokedGetter(element, compiler))) { | 493 resolverWorld.hasInvokedGetter(element, compiler))) { |
518 return; | 494 return; |
519 } | 495 } |
520 | 496 |
521 HTypeList providedTypes = | 497 HTypeList providedTypes = |
522 new HTypeList.fromDynamicInvocation(node, selector, types); | 498 new HTypeList.fromDynamicInvocation(node, selector, types); |
523 if (!selectorTypeMap.containsKey(selector)) { | 499 if (!selectorTypeMap.containsKey(selector)) { |
524 selectorTypeMap[selector] = providedTypes; | 500 selectorTypeMap[selector] = providedTypes; |
525 } else { | 501 } else { |
526 HTypeList oldTypes = selectorTypeMap[selector]; | 502 HTypeList oldTypes = selectorTypeMap[selector]; |
527 HTypeList newTypes = | 503 HTypeList newTypes = oldTypes.union(providedTypes, backend.compiler); |
528 oldTypes.unionWithInvoke(node, types, backend.compiler); | |
529 if (identical(newTypes, oldTypes)) return; | 504 if (identical(newTypes, oldTypes)) return; |
530 selectorTypeMap[selector] = newTypes; | 505 selectorTypeMap[selector] = newTypes; |
ahe
2012/11/27 10:19:11
This method could be reused here.
ahe
2012/11/27 10:19:57
By "this method", I probably mean "that method", a
ngeoffray
2012/11/27 10:41:04
Done.
| |
531 } | 506 } |
532 | 507 |
533 // If we're not compiling, we don't have to do anything. | 508 // If we're not compiling, we don't have to do anything. |
534 if (compiler.phase != Compiler.PHASE_COMPILING) return; | 509 if (compiler.phase != Compiler.PHASE_COMPILING) return; |
535 | 510 |
536 // Run through all optimized functions and figure out if they need | 511 // Run through all optimized functions and figure out if they need |
537 // to be recompiled because of this new invocation. | 512 // to be recompiled because of this new invocation. |
538 optimizedFunctions.filterBySelector(selector).forEach((Element element) { | 513 optimizedFunctions.filterBySelector(selector).forEach((Element element) { |
539 // TODO(kasperl): Maybe check if the element is already marked for | 514 // TODO(kasperl): Maybe check if the element is already marked for |
540 // recompilation? Could be pretty cheap compared to computing | 515 // recompilation? Could be pretty cheap compared to computing |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
651 ClassElement jsNumberClass; | 626 ClassElement jsNumberClass; |
652 ClassElement jsIntClass; | 627 ClassElement jsIntClass; |
653 ClassElement jsDoubleClass; | 628 ClassElement jsDoubleClass; |
654 ClassElement jsFunctionClass; | 629 ClassElement jsFunctionClass; |
655 ClassElement jsNullClass; | 630 ClassElement jsNullClass; |
656 ClassElement jsBoolClass; | 631 ClassElement jsBoolClass; |
657 ClassElement objectInterceptorClass; | 632 ClassElement objectInterceptorClass; |
658 Element jsArrayLength; | 633 Element jsArrayLength; |
659 Element jsStringLength; | 634 Element jsStringLength; |
660 Element getInterceptorMethod; | 635 Element getInterceptorMethod; |
636 Element arrayInterceptor; | |
637 Element boolInterceptor; | |
638 Element doubleInterceptor; | |
639 Element functionInterceptor; | |
640 Element intInterceptor; | |
641 Element nullInterceptor; | |
642 Element numberInterceptor; | |
643 Element stringInterceptor; | |
661 bool _interceptorsAreInitialized = false; | 644 bool _interceptorsAreInitialized = false; |
662 | 645 |
663 final Namer namer; | 646 final Namer namer; |
664 | 647 |
665 /** | 648 /** |
666 * Interface used to determine if an object has the JavaScript | 649 * Interface used to determine if an object has the JavaScript |
667 * indexing behavior. The interface is only visible to specific | 650 * indexing behavior. The interface is only visible to specific |
668 * libraries. | 651 * libraries. |
669 */ | 652 */ |
670 ClassElement jsIndexingBehaviorInterface; | 653 ClassElement jsIndexingBehaviorInterface; |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
781 jsFunctionClass = | 764 jsFunctionClass = |
782 compiler.findInterceptor(const SourceString('JSFunction')); | 765 compiler.findInterceptor(const SourceString('JSFunction')); |
783 jsBoolClass = | 766 jsBoolClass = |
784 compiler.findInterceptor(const SourceString('JSBool')); | 767 compiler.findInterceptor(const SourceString('JSBool')); |
785 jsArrayClass.ensureResolved(compiler); | 768 jsArrayClass.ensureResolved(compiler); |
786 jsArrayLength = | 769 jsArrayLength = |
787 jsArrayClass.lookupLocalMember(const SourceString('length')); | 770 jsArrayClass.lookupLocalMember(const SourceString('length')); |
788 jsStringClass.ensureResolved(compiler); | 771 jsStringClass.ensureResolved(compiler); |
789 jsStringLength = | 772 jsStringLength = |
790 jsStringClass.lookupLocalMember(const SourceString('length')); | 773 jsStringClass.lookupLocalMember(const SourceString('length')); |
774 | |
775 arrayInterceptor = | |
776 compiler.findInterceptor(const SourceString('arrayInterceptor')); | |
777 boolInterceptor = | |
778 compiler.findInterceptor(const SourceString('boolInterceptor')); | |
779 doubleInterceptor = | |
780 compiler.findInterceptor(const SourceString('doubleInterceptor')); | |
781 functionInterceptor = | |
782 compiler.findInterceptor(const SourceString('functionInterceptor')); | |
783 intInterceptor = | |
784 compiler.findInterceptor(const SourceString('intInterceptor')); | |
785 nullInterceptor = | |
786 compiler.findInterceptor(const SourceString('nullInterceptor')); | |
787 stringInterceptor = | |
788 compiler.findInterceptor(const SourceString('stringInterceptor')); | |
789 numberInterceptor = | |
790 compiler.findInterceptor(const SourceString('numberInterceptor')); | |
791 } | 791 } |
792 | 792 |
793 void addInterceptors(ClassElement cls) { | 793 void addInterceptors(ClassElement cls) { |
794 cls.ensureResolved(compiler); | 794 cls.ensureResolved(compiler); |
795 cls.forEachMember((ClassElement classElement, Element member) { | 795 cls.forEachMember((ClassElement classElement, Element member) { |
796 Set<Element> set = interceptedElements.putIfAbsent( | 796 Set<Element> set = interceptedElements.putIfAbsent( |
797 member.name, () => new Set<Element>()); | 797 member.name, () => new Set<Element>()); |
798 set.add(member); | 798 set.add(member); |
799 }, | 799 }, |
800 includeSuperMembers: true); | 800 includeSuperMembers: true); |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1100 print("Inferred return types:"); | 1100 print("Inferred return types:"); |
1101 print("----------------------"); | 1101 print("----------------------"); |
1102 dumpReturnTypes(); | 1102 dumpReturnTypes(); |
1103 print(""); | 1103 print(""); |
1104 print("Inferred field types:"); | 1104 print("Inferred field types:"); |
1105 print("------------------------"); | 1105 print("------------------------"); |
1106 fieldTypes.dump(); | 1106 fieldTypes.dump(); |
1107 print(""); | 1107 print(""); |
1108 } | 1108 } |
1109 } | 1109 } |
OLD | NEW |