| 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; |
| 11 List<Element> compiledFunctions; | 11 List<Element> compiledFunctions; |
| 12 | 12 |
| 13 ReturnInfo(HType this.returnType) | 13 ReturnInfo(HType this.returnType) |
| 14 : compiledFunctions = new List<Element>(); | 14 : compiledFunctions = new List<Element>(); |
| 15 | 15 |
| 16 ReturnInfo.unknownType() | 16 ReturnInfo.unknownType() |
| 17 : this.returnType = null, | 17 : this.returnType = null, |
| 18 compiledFunctions = new List<Element>(); | 18 compiledFunctions = new List<Element>(); |
| 19 | 19 |
| 20 void update(HType type, Recompile recompile) { | 20 void update(HType type, Recompile recompile, Compiler compiler) { |
| 21 HType newType = returnType != null ? returnType.union(type) : type; | 21 HType newType = |
| 22 returnType != null ? returnType.union(type, compiler) : type; |
| 22 if (newType != returnType) { | 23 if (newType != returnType) { |
| 23 if (returnType == null && identical(newType, HType.UNKNOWN)) { | 24 if (returnType == null && identical(newType, HType.UNKNOWN)) { |
| 24 // If the first actual piece of information is not providing any type | 25 // If the first actual piece of information is not providing any type |
| 25 // information there is no need to recompile callers. | 26 // information there is no need to recompile callers. |
| 26 compiledFunctions.clear(); | 27 compiledFunctions.clear(); |
| 27 } | 28 } |
| 28 returnType = newType; | 29 returnType = newType; |
| 29 if (recompile != null) { | 30 if (recompile != null) { |
| 30 compiledFunctions.forEach(recompile); | 31 compiledFunctions.forEach(recompile); |
| 31 } | 32 } |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 return result; | 114 return result; |
| 114 } | 115 } |
| 115 | 116 |
| 116 static const HTypeList ALL_UNKNOWN = const HTypeList.withAllUnknown(); | 117 static const HTypeList ALL_UNKNOWN = const HTypeList.withAllUnknown(); |
| 117 | 118 |
| 118 bool get allUnknown => types == null; | 119 bool get allUnknown => types == null; |
| 119 bool get hasNamedArguments => namedArguments != null; | 120 bool get hasNamedArguments => namedArguments != null; |
| 120 int get length => types.length; | 121 int get length => types.length; |
| 121 HType operator[](int index) => types[index]; | 122 HType operator[](int index) => types[index]; |
| 122 | 123 |
| 123 HTypeList union(HTypeList other) { | 124 HTypeList union(HTypeList other, Compiler compiler) { |
| 124 if (allUnknown) return this; | 125 if (allUnknown) return this; |
| 125 if (other.allUnknown) return other; | 126 if (other.allUnknown) return other; |
| 126 if (length != other.length) return HTypeList.ALL_UNKNOWN; | 127 if (length != other.length) return HTypeList.ALL_UNKNOWN; |
| 127 bool onlyUnknown = true; | 128 bool onlyUnknown = true; |
| 128 HTypeList result = this; | 129 HTypeList result = this; |
| 129 for (int i = 0; i < length; i++) { | 130 for (int i = 0; i < length; i++) { |
| 130 HType newType = this[i].union(other[i]); | 131 HType newType = this[i].union(other[i], compiler); |
| 131 if (result == this && newType != this[i]) { | 132 if (result == this && newType != this[i]) { |
| 132 // Create a new argument types object with the matching types copied. | 133 // Create a new argument types object with the matching types copied. |
| 133 result = new HTypeList(length); | 134 result = new HTypeList(length); |
| 134 result.types.setRange(0, i, this.types); | 135 result.types.setRange(0, i, this.types); |
| 135 } | 136 } |
| 136 if (result != this) { | 137 if (result != this) { |
| 137 result.types[i] = newType; | 138 result.types[i] = newType; |
| 138 } | 139 } |
| 139 if (result[i] != HType.UNKNOWN) onlyUnknown = false; | 140 if (result[i] != HType.UNKNOWN) onlyUnknown = false; |
| 140 } | 141 } |
| 141 return onlyUnknown ? HTypeList.ALL_UNKNOWN : result; | 142 return onlyUnknown ? HTypeList.ALL_UNKNOWN : result; |
| 142 } | 143 } |
| 143 | 144 |
| 144 /** | 145 /** |
| 145 * Create the union of this [HTypeList] object with the types used by | 146 * Create the union of this [HTypeList] object with the types used by |
| 146 * the [node]. If the union results in exactly the same types the receiver | 147 * the [node]. If the union results in exactly the same types the receiver |
| 147 * is returned. Otherwise a different [HTypeList] object is returned | 148 * is returned. Otherwise a different [HTypeList] object is returned |
| 148 * with the type union information. | 149 * with the type union information. |
| 149 */ | 150 */ |
| 150 HTypeList unionWithInvoke(HInvoke node, HTypeMap types) { | 151 HTypeList unionWithInvoke(HInvoke node, HTypeMap types, Compiler compiler) { |
| 151 // Union an all unknown list with something stays all unknown. | 152 // Union an all unknown list with something stays all unknown. |
| 152 if (allUnknown) return this; | 153 if (allUnknown) return this; |
| 153 | 154 |
| 154 bool allUnknown = true; | 155 bool allUnknown = true; |
| 155 if (length != node.inputs.length - 1) { | 156 if (length != node.inputs.length - 1) { |
| 156 return HTypeList.ALL_UNKNOWN; | 157 return HTypeList.ALL_UNKNOWN; |
| 157 } | 158 } |
| 158 | 159 |
| 159 bool onlyUnknown = true; | 160 bool onlyUnknown = true; |
| 160 HTypeList result = this; | 161 HTypeList result = this; |
| 161 for (int i = 0; i < length; i++) { | 162 for (int i = 0; i < length; i++) { |
| 162 HType newType = this[i].union(types[node.inputs[i + 1]]); | 163 HType newType = this[i].union(types[node.inputs[i + 1]], compiler); |
| 163 if (result == this && newType != this[i]) { | 164 if (result == this && newType != this[i]) { |
| 164 // Create a new argument types object with the matching types copied. | 165 // Create a new argument types object with the matching types copied. |
| 165 result = new HTypeList(length); | 166 result = new HTypeList(length); |
| 166 result.types.setRange(0, i, this.types); | 167 result.types.setRange(0, i, this.types); |
| 167 } | 168 } |
| 168 if (result != this) { | 169 if (result != this) { |
| 169 result.types[i] = newType; | 170 result.types[i] = newType; |
| 170 } | 171 } |
| 171 if (result[i] != HType.UNKNOWN) onlyUnknown = false; | 172 if (result[i] != HType.UNKNOWN) onlyUnknown = false; |
| 172 } | 173 } |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 300 void registerFieldType(Map<Element, HType> typeMap, | 301 void registerFieldType(Map<Element, HType> typeMap, |
| 301 Element field, | 302 Element field, |
| 302 HType type) { | 303 HType type) { |
| 303 assert(field.isField()); | 304 assert(field.isField()); |
| 304 HType before = optimisticFieldType(field); | 305 HType before = optimisticFieldType(field); |
| 305 | 306 |
| 306 HType oldType = typeMap[field]; | 307 HType oldType = typeMap[field]; |
| 307 HType newType; | 308 HType newType; |
| 308 | 309 |
| 309 if (oldType != null) { | 310 if (oldType != null) { |
| 310 newType = oldType.union(type); | 311 newType = oldType.union(type, compiler); |
| 311 } else { | 312 } else { |
| 312 newType = type; | 313 newType = type; |
| 313 } | 314 } |
| 314 typeMap[field] = newType; | 315 typeMap[field] = newType; |
| 315 if (oldType != newType) { | 316 if (oldType != newType) { |
| 316 scheduleRecompilation(field); | 317 scheduleRecompilation(field); |
| 317 } | 318 } |
| 318 } | 319 } |
| 319 | 320 |
| 320 void registerConstructor(Element element) { | 321 void registerConstructor(Element element) { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 396 if (initializerType == null && constructorType == null) { | 397 if (initializerType == null && constructorType == null) { |
| 397 // If there are no constructor type information return UNKNOWN. This | 398 // If there are no constructor type information return UNKNOWN. This |
| 398 // ensures that the function will be recompiled if useful constructor | 399 // ensures that the function will be recompiled if useful constructor |
| 399 // type information becomes available. | 400 // type information becomes available. |
| 400 return HType.UNKNOWN; | 401 return HType.UNKNOWN; |
| 401 } | 402 } |
| 402 // A type set through the constructor overrides the type from the | 403 // A type set through the constructor overrides the type from the |
| 403 // initializer list. | 404 // initializer list. |
| 404 HType result = constructorType != null ? constructorType : initializerType; | 405 HType result = constructorType != null ? constructorType : initializerType; |
| 405 HType type = fieldTypeMap[field]; | 406 HType type = fieldTypeMap[field]; |
| 406 if (type != null) result = result.union(type); | 407 if (type != null) result = result.union(type, compiler); |
| 407 return result; | 408 return result; |
| 408 } | 409 } |
| 409 | 410 |
| 410 void registerOptimizedFunction(FunctionElement element, | 411 void registerOptimizedFunction(FunctionElement element, |
| 411 Element field, | 412 Element field, |
| 412 HType type) { | 413 HType type) { |
| 413 assert(field.isField()); | 414 assert(field.isField()); |
| 414 if (Elements.isStaticOrTopLevel(element)) { | 415 if (Elements.isStaticOrTopLevel(element)) { |
| 415 optimizedStaticFunctions.putIfAbsent( | 416 optimizedStaticFunctions.putIfAbsent( |
| 416 field, () => new Set<Element>()); | 417 field, () => new Set<Element>()); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 Compiler get compiler => backend.compiler; | 474 Compiler get compiler => backend.compiler; |
| 474 | 475 |
| 475 void registerStaticInvocation(HInvokeStatic node, HTypeMap types) { | 476 void registerStaticInvocation(HInvokeStatic node, HTypeMap types) { |
| 476 Element element = node.element; | 477 Element element = node.element; |
| 477 assert(invariant(node, element.isDeclaration)); | 478 assert(invariant(node, element.isDeclaration)); |
| 478 HTypeList oldTypes = staticTypeMap[element]; | 479 HTypeList oldTypes = staticTypeMap[element]; |
| 479 if (oldTypes == null) { | 480 if (oldTypes == null) { |
| 480 staticTypeMap[element] = new HTypeList.fromStaticInvocation(node, types); | 481 staticTypeMap[element] = new HTypeList.fromStaticInvocation(node, types); |
| 481 } else { | 482 } else { |
| 482 if (oldTypes.allUnknown) return; | 483 if (oldTypes.allUnknown) return; |
| 483 HTypeList newTypes = oldTypes.unionWithInvoke(node, types); | 484 HTypeList newTypes = |
| 485 oldTypes.unionWithInvoke(node, types, backend.compiler); |
| 484 if (identical(newTypes, oldTypes)) return; | 486 if (identical(newTypes, oldTypes)) return; |
| 485 staticTypeMap[element] = newTypes; | 487 staticTypeMap[element] = newTypes; |
| 486 if (optimizedStaticFunctions.contains(element)) { | 488 if (optimizedStaticFunctions.contains(element)) { |
| 487 backend.scheduleForRecompilation(element); | 489 backend.scheduleForRecompilation(element); |
| 488 } | 490 } |
| 489 } | 491 } |
| 490 } | 492 } |
| 491 | 493 |
| 492 void registerNonCallStaticUse(HStatic node) { | 494 void registerNonCallStaticUse(HStatic node) { |
| 493 // When a static is used for anything else than a call target we cannot | 495 // When a static is used for anything else than a call target we cannot |
| (...skipping 21 matching lines...) Expand all Loading... |
| 515 resolverWorld.hasInvokedGetter(element, compiler))) { | 517 resolverWorld.hasInvokedGetter(element, compiler))) { |
| 516 return; | 518 return; |
| 517 } | 519 } |
| 518 | 520 |
| 519 HTypeList providedTypes = | 521 HTypeList providedTypes = |
| 520 new HTypeList.fromDynamicInvocation(node, selector, types); | 522 new HTypeList.fromDynamicInvocation(node, selector, types); |
| 521 if (!selectorTypeMap.containsKey(selector)) { | 523 if (!selectorTypeMap.containsKey(selector)) { |
| 522 selectorTypeMap[selector] = providedTypes; | 524 selectorTypeMap[selector] = providedTypes; |
| 523 } else { | 525 } else { |
| 524 HTypeList oldTypes = selectorTypeMap[selector]; | 526 HTypeList oldTypes = selectorTypeMap[selector]; |
| 525 HTypeList newTypes = oldTypes.unionWithInvoke(node, types); | 527 HTypeList newTypes = |
| 528 oldTypes.unionWithInvoke(node, types, backend.compiler); |
| 526 if (identical(newTypes, oldTypes)) return; | 529 if (identical(newTypes, oldTypes)) return; |
| 527 selectorTypeMap[selector] = newTypes; | 530 selectorTypeMap[selector] = newTypes; |
| 528 } | 531 } |
| 529 | 532 |
| 530 // If we're not compiling, we don't have to do anything. | 533 // If we're not compiling, we don't have to do anything. |
| 531 if (compiler.phase != Compiler.PHASE_COMPILING) return; | 534 if (compiler.phase != Compiler.PHASE_COMPILING) return; |
| 532 | 535 |
| 533 // Run through all optimized functions and figure out if they need | 536 // Run through all optimized functions and figure out if they need |
| 534 // to be recompiled because of this new invocation. | 537 // to be recompiled because of this new invocation. |
| 535 optimizedFunctions.filterBySelector(selector).forEach((Element element) { | 538 optimizedFunctions.filterBySelector(selector).forEach((Element element) { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 582 HTypeList found = null; | 585 HTypeList found = null; |
| 583 selectorTypeMap.visitMatching(element, | 586 selectorTypeMap.visitMatching(element, |
| 584 (Selector selector, HTypeList types) { | 587 (Selector selector, HTypeList types) { |
| 585 if (selector.argumentCount != signature.parameterCount || | 588 if (selector.argumentCount != signature.parameterCount || |
| 586 selector.namedArgumentCount > 0) { | 589 selector.namedArgumentCount > 0) { |
| 587 types = types.unionWithOptionalParameters(selector, | 590 types = types.unionWithOptionalParameters(selector, |
| 588 signature, | 591 signature, |
| 589 defaultValueTypes); | 592 defaultValueTypes); |
| 590 } | 593 } |
| 591 assert(types.allUnknown || types.length == signature.parameterCount); | 594 assert(types.allUnknown || types.length == signature.parameterCount); |
| 592 found = (found == null) ? types : found.union(types); | 595 found = (found == null) ? types : found.union(types, compiler); |
| 593 return !found.allUnknown; | 596 return !found.allUnknown; |
| 594 }); | 597 }); |
| 595 return found != null ? found : HTypeList.ALL_UNKNOWN; | 598 return found != null ? found : HTypeList.ALL_UNKNOWN; |
| 596 } | 599 } |
| 597 | 600 |
| 598 void registerOptimizedFunction(Element element, | 601 void registerOptimizedFunction(Element element, |
| 599 HTypeList parameterTypes, | 602 HTypeList parameterTypes, |
| 600 OptionalParameterTypes defaultValueTypes) { | 603 OptionalParameterTypes defaultValueTypes) { |
| 601 if (Elements.isStaticOrTopLevelFunction(element)) { | 604 if (Elements.isStaticOrTopLevelFunction(element)) { |
| 602 if (parameterTypes.allUnknown) { | 605 if (parameterTypes.allUnknown) { |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 834 | 837 |
| 835 /** | 838 /** |
| 836 * Documentation wanted -- johnniwinther | 839 * Documentation wanted -- johnniwinther |
| 837 * | 840 * |
| 838 * Invariant: [element] must be a declaration element. | 841 * Invariant: [element] must be a declaration element. |
| 839 */ | 842 */ |
| 840 void registerReturnType(FunctionElement element, HType returnType) { | 843 void registerReturnType(FunctionElement element, HType returnType) { |
| 841 assert(invariant(element, element.isDeclaration)); | 844 assert(invariant(element, element.isDeclaration)); |
| 842 ReturnInfo info = returnInfo[element]; | 845 ReturnInfo info = returnInfo[element]; |
| 843 if (info != null) { | 846 if (info != null) { |
| 844 info.update(returnType, scheduleForRecompilation); | 847 info.update(returnType, scheduleForRecompilation, compiler); |
| 845 } else { | 848 } else { |
| 846 returnInfo[element] = new ReturnInfo(returnType); | 849 returnInfo[element] = new ReturnInfo(returnType); |
| 847 } | 850 } |
| 848 } | 851 } |
| 849 | 852 |
| 850 /** | 853 /** |
| 851 * Retrieve the return type of the function [callee]. The type is optimistic | 854 * Retrieve the return type of the function [callee]. The type is optimistic |
| 852 * in the sense that is is based on the compilation of [callee]. If [callee] | 855 * in the sense that is is based on the compilation of [callee]. If [callee] |
| 853 * is recompiled the return type might change to someting broader. For that | 856 * is recompiled the return type might change to someting broader. For that |
| 854 * reason [caller] is registered for recompilation if this happens. If the | 857 * reason [caller] is registered for recompilation if this happens. If the |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 947 print("Inferred return types:"); | 950 print("Inferred return types:"); |
| 948 print("----------------------"); | 951 print("----------------------"); |
| 949 dumpReturnTypes(); | 952 dumpReturnTypes(); |
| 950 print(""); | 953 print(""); |
| 951 print("Inferred field types:"); | 954 print("Inferred field types:"); |
| 952 print("------------------------"); | 955 print("------------------------"); |
| 953 fieldTypes.dump(); | 956 fieldTypes.dump(); |
| 954 print(""); | 957 print(""); |
| 955 } | 958 } |
| 956 } | 959 } |
| OLD | NEW |