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