| 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 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; | 5 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
| 6 import '../common/names.dart' show Selectors; | 6 import '../common/names.dart' show Selectors; |
| 7 import '../common/tasks.dart' show CompilerTask; | 7 import '../common/tasks.dart' show CompilerTask; |
| 8 import '../compiler.dart' show Compiler; | 8 import '../compiler.dart' show Compiler; |
| 9 import '../constants/constant_system.dart'; | 9 import '../constants/constant_system.dart'; |
| 10 import '../constants/values.dart'; | 10 import '../constants/values.dart'; |
| (...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 463 && | 463 && |
| 464 node.selector.applies(element)) { | 464 node.selector.applies(element)) { |
| 465 MethodElement method = element; | 465 MethodElement method = element; |
| 466 | 466 |
| 467 if (backend.isNative(method)) { | 467 if (backend.isNative(method)) { |
| 468 HInstruction folded = tryInlineNativeMethod(node, method); | 468 HInstruction folded = tryInlineNativeMethod(node, method); |
| 469 if (folded != null) return folded; | 469 if (folded != null) return folded; |
| 470 } else { | 470 } else { |
| 471 // TODO(ngeoffray): If the method has optional parameters, | 471 // TODO(ngeoffray): If the method has optional parameters, |
| 472 // we should pass the default values. | 472 // we should pass the default values. |
| 473 FunctionType type = method.type; | 473 ResolutionFunctionType type = method.type; |
| 474 int optionalParameterCount = | 474 int optionalParameterCount = |
| 475 type.optionalParameterTypes.length + type.namedParameters.length; | 475 type.optionalParameterTypes.length + type.namedParameters.length; |
| 476 if (optionalParameterCount == 0 || | 476 if (optionalParameterCount == 0 || |
| 477 type.parameterTypes.length + optionalParameterCount == | 477 type.parameterTypes.length + optionalParameterCount == |
| 478 node.selector.argumentCount) { | 478 node.selector.argumentCount) { |
| 479 node.element = method; | 479 node.element = method; |
| 480 } | 480 } |
| 481 } | 481 } |
| 482 return node; | 482 return node; |
| 483 } | 483 } |
| 484 | 484 |
| 485 // Replace method calls through fields with a closure call on the value of | 485 // Replace method calls through fields with a closure call on the value of |
| 486 // the field. This usually removes the demand for the call-through stub and | 486 // the field. This usually removes the demand for the call-through stub and |
| 487 // makes the field load available to further optimization, e.g. LICM. | 487 // makes the field load available to further optimization, e.g. LICM. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 521 // TODO(ngeoffray): There are some cases where we could still inline in | 521 // TODO(ngeoffray): There are some cases where we could still inline in |
| 522 // checked mode if we know the arguments have the right type. And we could | 522 // checked mode if we know the arguments have the right type. And we could |
| 523 // do the closure conversion as well as the return type annotation check. | 523 // do the closure conversion as well as the return type annotation check. |
| 524 | 524 |
| 525 if (!node.isInterceptedCall) return null; | 525 if (!node.isInterceptedCall) return null; |
| 526 | 526 |
| 527 // TODO(sra): Check for legacy methods with bodies in the native strings. | 527 // TODO(sra): Check for legacy methods with bodies in the native strings. |
| 528 // foo() native 'return something'; | 528 // foo() native 'return something'; |
| 529 // They should not be used. | 529 // They should not be used. |
| 530 | 530 |
| 531 FunctionType type = method.type; | 531 ResolutionFunctionType type = method.type; |
| 532 if (type.namedParameters.isNotEmpty) return null; | 532 if (type.namedParameters.isNotEmpty) return null; |
| 533 | 533 |
| 534 // Return types on native methods don't need to be checked, since the | 534 // Return types on native methods don't need to be checked, since the |
| 535 // declaration has to be truthful. | 535 // declaration has to be truthful. |
| 536 | 536 |
| 537 // The call site might omit optional arguments. The inlined code must | 537 // The call site might omit optional arguments. The inlined code must |
| 538 // preserve the number of arguments, so check only the actual arguments. | 538 // preserve the number of arguments, so check only the actual arguments. |
| 539 | 539 |
| 540 List<HInstruction> inputs = node.inputs.sublist(1); | 540 List<HInstruction> inputs = node.inputs.sublist(1); |
| 541 bool canInline = true; | 541 bool canInline = true; |
| 542 if (compiler.options.enableTypeAssertions && inputs.length > 1) { | 542 if (compiler.options.enableTypeAssertions && inputs.length > 1) { |
| 543 // TODO(sra): Check if [input] is guaranteed to pass the parameter | 543 // TODO(sra): Check if [input] is guaranteed to pass the parameter |
| 544 // type check. Consider using a strengthened type check to avoid | 544 // type check. Consider using a strengthened type check to avoid |
| 545 // passing `null` to primitive types since the native methods usually | 545 // passing `null` to primitive types since the native methods usually |
| 546 // have non-nullable primitive parameter types. | 546 // have non-nullable primitive parameter types. |
| 547 canInline = false; | 547 canInline = false; |
| 548 } else { | 548 } else { |
| 549 int inputPosition = 1; // Skip receiver. | 549 int inputPosition = 1; // Skip receiver. |
| 550 void checkParameterType(DartType type) { | 550 void checkParameterType(ResolutionDartType type) { |
| 551 if (inputPosition++ < inputs.length && canInline) { | 551 if (inputPosition++ < inputs.length && canInline) { |
| 552 if (type.unaliased.isFunctionType) { | 552 if (type.unaliased.isFunctionType) { |
| 553 canInline = false; | 553 canInline = false; |
| 554 } | 554 } |
| 555 } | 555 } |
| 556 } | 556 } |
| 557 | 557 |
| 558 type.parameterTypes.forEach(checkParameterType); | 558 type.parameterTypes.forEach(checkParameterType); |
| 559 type.optionalParameterTypes.forEach(checkParameterType); | 559 type.optionalParameterTypes.forEach(checkParameterType); |
| 560 type.namedParameterTypes.forEach(checkParameterType); | 560 type.namedParameterTypes.forEach(checkParameterType); |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 731 simplifyCondition(node.thenBlock, hoisted, false); | 731 simplifyCondition(node.thenBlock, hoisted, false); |
| 732 simplifyCondition(node.elseBlock, hoisted, true); | 732 simplifyCondition(node.elseBlock, hoisted, true); |
| 733 }); | 733 }); |
| 734 } | 734 } |
| 735 simplifyCondition(node.thenBlock, condition, !isNegated); | 735 simplifyCondition(node.thenBlock, condition, !isNegated); |
| 736 simplifyCondition(node.elseBlock, condition, isNegated); | 736 simplifyCondition(node.elseBlock, condition, isNegated); |
| 737 return node; | 737 return node; |
| 738 } | 738 } |
| 739 | 739 |
| 740 HInstruction visitIs(HIs node) { | 740 HInstruction visitIs(HIs node) { |
| 741 DartType type = node.typeExpression; | 741 ResolutionDartType type = node.typeExpression; |
| 742 | 742 |
| 743 if (!node.isRawCheck) { | 743 if (!node.isRawCheck) { |
| 744 return node; | 744 return node; |
| 745 } else if (type.isTypedef) { | 745 } else if (type.isTypedef) { |
| 746 return node; | 746 return node; |
| 747 } else if (type.isFunctionType) { | 747 } else if (type.isFunctionType) { |
| 748 return node; | 748 return node; |
| 749 } | 749 } |
| 750 | 750 |
| 751 if (type.isObject || type.treatAsDynamic) { | 751 if (type.isObject || type.treatAsDynamic) { |
| 752 return graph.addConstantBool(true, closedWorld); | 752 return graph.addConstantBool(true, closedWorld); |
| 753 } | 753 } |
| 754 InterfaceType interfaceType = type; | 754 ResolutionInterfaceType interfaceType = type; |
| 755 ClassEntity element = interfaceType.element; | 755 ClassEntity element = interfaceType.element; |
| 756 HInstruction expression = node.expression; | 756 HInstruction expression = node.expression; |
| 757 if (expression.isInteger(closedWorld)) { | 757 if (expression.isInteger(closedWorld)) { |
| 758 if (element == commonElements.intClass || | 758 if (element == commonElements.intClass || |
| 759 element == commonElements.numClass || | 759 element == commonElements.numClass || |
| 760 commonElements.isNumberOrStringSupertype(element)) { | 760 commonElements.isNumberOrStringSupertype(element)) { |
| 761 return graph.addConstantBool(true, closedWorld); | 761 return graph.addConstantBool(true, closedWorld); |
| 762 } else if (element == commonElements.doubleClass) { | 762 } else if (element == commonElements.doubleClass) { |
| 763 // We let the JS semantics decide for that check. Currently | 763 // We let the JS semantics decide for that check. Currently |
| 764 // the code we emit will always return true. | 764 // the code we emit will always return true. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 803 if (expressionMask.union(typeMask, closedWorld) == typeMask) { | 803 if (expressionMask.union(typeMask, closedWorld) == typeMask) { |
| 804 return graph.addConstantBool(true, closedWorld); | 804 return graph.addConstantBool(true, closedWorld); |
| 805 } else if (expressionMask.isDisjoint(typeMask, closedWorld)) { | 805 } else if (expressionMask.isDisjoint(typeMask, closedWorld)) { |
| 806 return graph.addConstantBool(false, closedWorld); | 806 return graph.addConstantBool(false, closedWorld); |
| 807 } | 807 } |
| 808 } | 808 } |
| 809 return node; | 809 return node; |
| 810 } | 810 } |
| 811 | 811 |
| 812 HInstruction visitTypeConversion(HTypeConversion node) { | 812 HInstruction visitTypeConversion(HTypeConversion node) { |
| 813 DartType type = node.typeExpression; | 813 ResolutionDartType type = node.typeExpression; |
| 814 if (type != null) { | 814 if (type != null) { |
| 815 if (type.isMalformed) { | 815 if (type.isMalformed) { |
| 816 // Malformed types are treated as dynamic statically, but should | 816 // Malformed types are treated as dynamic statically, but should |
| 817 // throw a type error at runtime. | 817 // throw a type error at runtime. |
| 818 return node; | 818 return node; |
| 819 } | 819 } |
| 820 if (type.isTypeVariable) { | 820 if (type.isTypeVariable) { |
| 821 return node; | 821 return node; |
| 822 } | 822 } |
| 823 if (!type.treatAsRaw) { | 823 if (!type.treatAsRaw) { |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 973 } | 973 } |
| 974 | 974 |
| 975 HInstruction receiver = node.getDartReceiver(closedWorld); | 975 HInstruction receiver = node.getDartReceiver(closedWorld); |
| 976 FieldElement field = | 976 FieldElement field = |
| 977 findConcreteFieldForDynamicAccess(receiver, node.selector); | 977 findConcreteFieldForDynamicAccess(receiver, node.selector); |
| 978 if (field == null || !field.isAssignable) return node; | 978 if (field == null || !field.isAssignable) return node; |
| 979 // Use `node.inputs.last` in case the call follows the interceptor calling | 979 // Use `node.inputs.last` in case the call follows the interceptor calling |
| 980 // convention, but is not a call on an interceptor. | 980 // convention, but is not a call on an interceptor. |
| 981 HInstruction value = node.inputs.last; | 981 HInstruction value = node.inputs.last; |
| 982 if (compiler.options.enableTypeAssertions) { | 982 if (compiler.options.enableTypeAssertions) { |
| 983 DartType type = field.type; | 983 ResolutionDartType type = field.type; |
| 984 if (!type.treatAsRaw || | 984 if (!type.treatAsRaw || |
| 985 type.isTypeVariable || | 985 type.isTypeVariable || |
| 986 type.unaliased.isFunctionType) { | 986 type.unaliased.isFunctionType) { |
| 987 // We cannot generate the correct type representation here, so don't | 987 // We cannot generate the correct type representation here, so don't |
| 988 // inline this access. | 988 // inline this access. |
| 989 // TODO(sra): If the input is such that we don't need a type check, we | 989 // TODO(sra): If the input is such that we don't need a type check, we |
| 990 // can skip the test an generate the HFieldSet. | 990 // can skip the test an generate the HFieldSet. |
| 991 return node; | 991 return node; |
| 992 } | 992 } |
| 993 HInstruction other = value.convertType( | 993 HInstruction other = value.convertType( |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1189 return new HTypeInfoReadRaw(source, closedWorld.commonMasks.dynamicType); | 1189 return new HTypeInfoReadRaw(source, closedWorld.commonMasks.dynamicType); |
| 1190 } | 1190 } |
| 1191 | 1191 |
| 1192 // TODO(sra): Consider fusing type expression trees with no type variables, | 1192 // TODO(sra): Consider fusing type expression trees with no type variables, |
| 1193 // as these could be represented like constants. | 1193 // as these could be represented like constants. |
| 1194 | 1194 |
| 1195 return tryCopyInfo() ?? node; | 1195 return tryCopyInfo() ?? node; |
| 1196 } | 1196 } |
| 1197 | 1197 |
| 1198 HInstruction visitTypeInfoReadVariable(HTypeInfoReadVariable node) { | 1198 HInstruction visitTypeInfoReadVariable(HTypeInfoReadVariable node) { |
| 1199 TypeVariableType variable = node.variable; | 1199 ResolutionTypeVariableType variable = node.variable; |
| 1200 HInstruction object = node.object; | 1200 HInstruction object = node.object; |
| 1201 | 1201 |
| 1202 HInstruction finishGroundType(InterfaceType groundType) { | 1202 HInstruction finishGroundType(ResolutionInterfaceType groundType) { |
| 1203 InterfaceType typeAtVariable = | 1203 ResolutionInterfaceType typeAtVariable = |
| 1204 groundType.asInstanceOf(variable.element.enclosingClass); | 1204 groundType.asInstanceOf(variable.element.enclosingClass); |
| 1205 if (typeAtVariable != null) { | 1205 if (typeAtVariable != null) { |
| 1206 int index = variable.element.index; | 1206 int index = variable.element.index; |
| 1207 DartType typeArgument = typeAtVariable.typeArguments[index]; | 1207 ResolutionDartType typeArgument = typeAtVariable.typeArguments[index]; |
| 1208 HInstruction replacement = new HTypeInfoExpression( | 1208 HInstruction replacement = new HTypeInfoExpression( |
| 1209 TypeInfoExpressionKind.COMPLETE, | 1209 TypeInfoExpressionKind.COMPLETE, |
| 1210 typeArgument, | 1210 typeArgument, |
| 1211 const <HInstruction>[], | 1211 const <HInstruction>[], |
| 1212 closedWorld.commonMasks.dynamicType); | 1212 closedWorld.commonMasks.dynamicType); |
| 1213 return replacement; | 1213 return replacement; |
| 1214 } | 1214 } |
| 1215 return node; | 1215 return node; |
| 1216 } | 1216 } |
| 1217 | 1217 |
| 1218 /// Read the type variable from an allocation of type [createdClass], where | 1218 /// Read the type variable from an allocation of type [createdClass], where |
| 1219 /// [selectTypeArgumentFromObjectCreation] extracts the type argument from | 1219 /// [selectTypeArgumentFromObjectCreation] extracts the type argument from |
| 1220 /// the allocation for factory constructor call. | 1220 /// the allocation for factory constructor call. |
| 1221 HInstruction finishSubstituted(ClassElement createdClass, | 1221 HInstruction finishSubstituted(ClassElement createdClass, |
| 1222 HInstruction selectTypeArgumentFromObjectCreation(int index)) { | 1222 HInstruction selectTypeArgumentFromObjectCreation(int index)) { |
| 1223 HInstruction instructionForTypeVariable(TypeVariableType tv) { | 1223 HInstruction instructionForTypeVariable(ResolutionTypeVariableType tv) { |
| 1224 return selectTypeArgumentFromObjectCreation( | 1224 return selectTypeArgumentFromObjectCreation( |
| 1225 createdClass.thisType.typeArguments.indexOf(tv)); | 1225 createdClass.thisType.typeArguments.indexOf(tv)); |
| 1226 } | 1226 } |
| 1227 | 1227 |
| 1228 DartType type = createdClass.thisType | 1228 ResolutionDartType type = createdClass.thisType |
| 1229 .asInstanceOf(variable.element.enclosingClass) | 1229 .asInstanceOf(variable.element.enclosingClass) |
| 1230 .typeArguments[variable.element.index]; | 1230 .typeArguments[variable.element.index]; |
| 1231 if (type is TypeVariableType) { | 1231 if (type is ResolutionTypeVariableType) { |
| 1232 return instructionForTypeVariable(type); | 1232 return instructionForTypeVariable(type); |
| 1233 } | 1233 } |
| 1234 List<HInstruction> arguments = <HInstruction>[]; | 1234 List<HInstruction> arguments = <HInstruction>[]; |
| 1235 type.forEachTypeVariable((v) { | 1235 type.forEachTypeVariable((v) { |
| 1236 arguments.add(instructionForTypeVariable(v)); | 1236 arguments.add(instructionForTypeVariable(v)); |
| 1237 }); | 1237 }); |
| 1238 HInstruction replacement = new HTypeInfoExpression( | 1238 HInstruction replacement = new HTypeInfoExpression( |
| 1239 TypeInfoExpressionKind.COMPLETE, | 1239 TypeInfoExpressionKind.COMPLETE, |
| 1240 type, | 1240 type, |
| 1241 arguments, | 1241 arguments, |
| (...skipping 888 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2130 if (dominatedUsers.isEmpty) return; | 2130 if (dominatedUsers.isEmpty) return; |
| 2131 | 2131 |
| 2132 HTypeKnown newInput = new HTypeKnown.pinned(convertedType, input); | 2132 HTypeKnown newInput = new HTypeKnown.pinned(convertedType, input); |
| 2133 dominator.addBefore(dominator.first, newInput); | 2133 dominator.addBefore(dominator.first, newInput); |
| 2134 dominatedUsers.forEach((HInstruction user) { | 2134 dominatedUsers.forEach((HInstruction user) { |
| 2135 user.changeUse(input, newInput); | 2135 user.changeUse(input, newInput); |
| 2136 }); | 2136 }); |
| 2137 } | 2137 } |
| 2138 | 2138 |
| 2139 void visitIs(HIs instruction) { | 2139 void visitIs(HIs instruction) { |
| 2140 DartType type = instruction.typeExpression; | 2140 ResolutionDartType type = instruction.typeExpression; |
| 2141 if (!instruction.isRawCheck) { | 2141 if (!instruction.isRawCheck) { |
| 2142 return; | 2142 return; |
| 2143 } else if (type.isTypedef) { | 2143 } else if (type.isTypedef) { |
| 2144 return; | 2144 return; |
| 2145 } | 2145 } |
| 2146 InterfaceType interfaceType = type; | 2146 ResolutionInterfaceType interfaceType = type; |
| 2147 ClassEntity cls = interfaceType.element; | 2147 ClassEntity cls = interfaceType.element; |
| 2148 | 2148 |
| 2149 List<HBasicBlock> trueTargets = <HBasicBlock>[]; | 2149 List<HBasicBlock> trueTargets = <HBasicBlock>[]; |
| 2150 List<HBasicBlock> falseTargets = <HBasicBlock>[]; | 2150 List<HBasicBlock> falseTargets = <HBasicBlock>[]; |
| 2151 | 2151 |
| 2152 collectTargets(instruction, trueTargets, falseTargets); | 2152 collectTargets(instruction, trueTargets, falseTargets); |
| 2153 | 2153 |
| 2154 if (trueTargets.isEmpty && falseTargets.isEmpty) return; | 2154 if (trueTargets.isEmpty && falseTargets.isEmpty) return; |
| 2155 | 2155 |
| 2156 TypeMask convertedType = new TypeMask.nonNullSubtype(cls, closedWorld); | 2156 TypeMask convertedType = new TypeMask.nonNullSubtype(cls, closedWorld); |
| (...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2753 | 2753 |
| 2754 keyedValues.forEach((receiver, values) { | 2754 keyedValues.forEach((receiver, values) { |
| 2755 result.keyedValues[receiver] = | 2755 result.keyedValues[receiver] = |
| 2756 new Map<HInstruction, HInstruction>.from(values); | 2756 new Map<HInstruction, HInstruction>.from(values); |
| 2757 }); | 2757 }); |
| 2758 | 2758 |
| 2759 result.nonEscapingReceivers.addAll(nonEscapingReceivers); | 2759 result.nonEscapingReceivers.addAll(nonEscapingReceivers); |
| 2760 return result; | 2760 return result; |
| 2761 } | 2761 } |
| 2762 } | 2762 } |
| OLD | NEW |