| 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 ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * A special element for the extra parameter taken by intercepted | 8 * A special element for the extra parameter taken by intercepted |
| 9 * methods. We need to implement [TypedElement.type] because our | 9 * methods. We need to implement [TypedElement.type] because our |
| 10 * optimizers may look at its declared type. | 10 * optimizers may look at its declared type. |
| (...skipping 1628 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1639 ClassElement enclosingClass = callee.getEnclosingClass(); | 1639 ClassElement enclosingClass = callee.getEnclosingClass(); |
| 1640 if (backend.classNeedsRti(enclosingClass)) { | 1640 if (backend.classNeedsRti(enclosingClass)) { |
| 1641 // If [enclosingClass] needs RTI, we have to give a value to its | 1641 // If [enclosingClass] needs RTI, we have to give a value to its |
| 1642 // type parameters. | 1642 // type parameters. |
| 1643 ClassElement currentClass = caller.getEnclosingClass(); | 1643 ClassElement currentClass = caller.getEnclosingClass(); |
| 1644 // For a super constructor call, the type is the supertype of | 1644 // For a super constructor call, the type is the supertype of |
| 1645 // [currentClass]. For a redirecting constructor, the type is | 1645 // [currentClass]. For a redirecting constructor, the type is |
| 1646 // the current type. [InterfaceType.asInstanceOf] takes care | 1646 // the current type. [InterfaceType.asInstanceOf] takes care |
| 1647 // of both. | 1647 // of both. |
| 1648 InterfaceType type = currentClass.thisType.asInstanceOf(enclosingClass); | 1648 InterfaceType type = currentClass.thisType.asInstanceOf(enclosingClass); |
| 1649 Link<DartType> typeVariables = enclosingClass.typeVariables; | 1649 List<DartType> arguments = type.typeArguments; |
| 1650 type.typeArguments.forEach((DartType argument) { | 1650 List<DartType> typeVariables = enclosingClass.typeVariables; |
| 1651 localsHandler.updateLocal( | 1651 if (!type.isRaw) { |
| 1652 typeVariables.head.element, | 1652 assert(arguments.length == typeVariables.length); |
| 1653 analyzeTypeArgument(argument)); | 1653 Iterator<DartType> variables = typeVariables.iterator; |
| 1654 typeVariables = typeVariables.tail; | 1654 type.typeArguments.forEach((DartType argument) { |
| 1655 }); | 1655 variables.moveNext(); |
| 1656 // If the supertype is a raw type, we need to set to null the | 1656 localsHandler.updateLocal( |
| 1657 // type variables. | 1657 variables.current.element, |
| 1658 assert(typeVariables.isEmpty | 1658 analyzeTypeArgument(argument)); |
| 1659 || enclosingClass.typeVariables == typeVariables); | 1659 }); |
| 1660 while (!typeVariables.isEmpty) { | 1660 } else { |
| 1661 localsHandler.updateLocal(typeVariables.head.element, | 1661 // If the supertype is a raw type, we need to set to null the |
| 1662 graph.addConstantNull(compiler)); | 1662 // type variables. |
| 1663 typeVariables = typeVariables.tail; | 1663 for (DartType variable in typeVariables) { |
| 1664 localsHandler.updateLocal(variable.element, |
| 1665 graph.addConstantNull(compiler)); |
| 1666 } |
| 1664 } | 1667 } |
| 1665 } | 1668 } |
| 1666 | 1669 |
| 1667 // For redirecting constructors, the fields have already been | 1670 // For redirecting constructors, the fields have already been |
| 1668 // initialized by the caller. | 1671 // initialized by the caller. |
| 1669 if (callee.getEnclosingClass() != caller.getEnclosingClass()) { | 1672 if (callee.getEnclosingClass() != caller.getEnclosingClass()) { |
| 1670 inlinedFrom(callee, () { | 1673 inlinedFrom(callee, () { |
| 1671 buildFieldInitializers(callee.enclosingElement.implementation, | 1674 buildFieldInitializers(callee.enclosingElement.implementation, |
| 1672 fieldValues); | 1675 fieldValues); |
| 1673 }); | 1676 }); |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1960 // would be of the form: | 1963 // would be of the form: |
| 1961 // [getTypeArgumentByIndex(this, 0), .., getTypeArgumentByIndex(this, k)] | 1964 // [getTypeArgumentByIndex(this, 0), .., getTypeArgumentByIndex(this, k)] |
| 1962 // and k is the number of type arguments of this. If this is the case, | 1965 // and k is the number of type arguments of this. If this is the case, |
| 1963 // we can simply copy the list from this. | 1966 // we can simply copy the list from this. |
| 1964 | 1967 |
| 1965 // These locals are modified by [isIndexedTypeArgumentGet]. | 1968 // These locals are modified by [isIndexedTypeArgumentGet]. |
| 1966 HInstruction source; // The source of the type arguments. | 1969 HInstruction source; // The source of the type arguments. |
| 1967 bool allIndexed = true; | 1970 bool allIndexed = true; |
| 1968 int expectedIndex = 0; | 1971 int expectedIndex = 0; |
| 1969 ClassElement contextClass; // The class of `this`. | 1972 ClassElement contextClass; // The class of `this`. |
| 1970 Link typeVariables; // The list of 'remaining type variables' of `this`. | 1973 int remainingTypeVariables; // The number of 'remaining type variables' |
| 1974 // of `this`. |
| 1971 | 1975 |
| 1972 /// Helper to identify instructions that read a type variable without | 1976 /// Helper to identify instructions that read a type variable without |
| 1973 /// substitution (that is, directly use the index). These instructions | 1977 /// substitution (that is, directly use the index). These instructions |
| 1974 /// are of the form: | 1978 /// are of the form: |
| 1975 /// HInvokeStatic(getTypeArgumentByIndex, this, index) | 1979 /// HInvokeStatic(getTypeArgumentByIndex, this, index) |
| 1976 /// | 1980 /// |
| 1977 /// Return `true` if [instruction] is of that form and the index is the | 1981 /// Return `true` if [instruction] is of that form and the index is the |
| 1978 /// next index in the sequence (held in [expectedIndex]). | 1982 /// next index in the sequence (held in [expectedIndex]). |
| 1979 bool isIndexedTypeArgumentGet(HInstruction instruction) { | 1983 bool isIndexedTypeArgumentGet(HInstruction instruction) { |
| 1980 if (instruction is! HInvokeStatic) return false; | 1984 if (instruction is! HInvokeStatic) return false; |
| 1981 HInvokeStatic invoke = instruction; | 1985 HInvokeStatic invoke = instruction; |
| 1982 if (invoke.element != backend.getGetTypeArgumentByIndex()) { | 1986 if (invoke.element != backend.getGetTypeArgumentByIndex()) { |
| 1983 return false; | 1987 return false; |
| 1984 } | 1988 } |
| 1985 HConstant index = invoke.inputs[1]; | 1989 HConstant index = invoke.inputs[1]; |
| 1986 HInstruction newSource = invoke.inputs[0]; | 1990 HInstruction newSource = invoke.inputs[0]; |
| 1987 if (newSource is! HThis) { | 1991 if (newSource is! HThis) { |
| 1988 return false; | 1992 return false; |
| 1989 } | 1993 } |
| 1990 if (source == null) { | 1994 if (source == null) { |
| 1991 // This is the first match. Extract the context class for the type | 1995 // This is the first match. Extract the context class for the type |
| 1992 // variables and get the list of type variables to keep track of how | 1996 // variables and get the list of type variables to keep track of how |
| 1993 // many arguments we need to process. | 1997 // many arguments we need to process. |
| 1994 source = newSource; | 1998 source = newSource; |
| 1995 contextClass = source.sourceElement.getEnclosingClass(); | 1999 contextClass = source.sourceElement.getEnclosingClass(); |
| 1996 typeVariables = contextClass.typeVariables; | 2000 remainingTypeVariables = contextClass.typeVariables.length; |
| 1997 } else { | 2001 } else { |
| 1998 assert(source == newSource); | 2002 assert(source == newSource); |
| 1999 } | 2003 } |
| 2000 // If there are no more type variables, then there are more type | 2004 // If there are no more type variables, then there are more type |
| 2001 // arguments for the new object than the source has, and it can't be | 2005 // arguments for the new object than the source has, and it can't be |
| 2002 // a copy. Otherwise remove one argument. | 2006 // a copy. Otherwise remove one argument. |
| 2003 if (typeVariables.isEmpty) return false; | 2007 if (remainingTypeVariables == 0) return false; |
| 2004 typeVariables = typeVariables.tail; | 2008 remainingTypeVariables--; |
| 2005 // Check that the index is the one we expect. | 2009 // Check that the index is the one we expect. |
| 2006 IntConstant constant = index.constant; | 2010 IntConstant constant = index.constant; |
| 2007 return constant.value == expectedIndex++; | 2011 return constant.value == expectedIndex++; |
| 2008 } | 2012 } |
| 2009 | 2013 |
| 2010 List<HInstruction> typeArguments = <HInstruction>[]; | 2014 List<HInstruction> typeArguments = <HInstruction>[]; |
| 2011 classElement.typeVariables.forEach((TypeVariableType typeVariable) { | 2015 classElement.typeVariables.forEach((TypeVariableType typeVariable) { |
| 2012 HInstruction argument = localsHandler.readLocal(typeVariable.element); | 2016 HInstruction argument = localsHandler.readLocal(typeVariable.element); |
| 2013 if (allIndexed && !isIndexedTypeArgumentGet(argument)) { | 2017 if (allIndexed && !isIndexedTypeArgumentGet(argument)) { |
| 2014 allIndexed = false; | 2018 allIndexed = false; |
| 2015 } | 2019 } |
| 2016 typeArguments.add(argument); | 2020 typeArguments.add(argument); |
| 2017 }); | 2021 }); |
| 2018 | 2022 |
| 2019 if (source != null && allIndexed && typeVariables.isEmpty) { | 2023 if (source != null && allIndexed && remainingTypeVariables == 0) { |
| 2020 copyRuntimeTypeInfo(source, newObject); | 2024 copyRuntimeTypeInfo(source, newObject); |
| 2021 } else { | 2025 } else { |
| 2022 newObject = | 2026 newObject = |
| 2023 callSetRuntimeTypeInfo(classElement, typeArguments, newObject); | 2027 callSetRuntimeTypeInfo(classElement, typeArguments, newObject); |
| 2024 } | 2028 } |
| 2025 } | 2029 } |
| 2026 | 2030 |
| 2027 // Generate calls to the constructor bodies. | 2031 // Generate calls to the constructor bodies. |
| 2028 HInstruction interceptor = null; | 2032 HInstruction interceptor = null; |
| 2029 for (int index = constructors.length - 1; index >= 0; index--) { | 2033 for (int index = constructors.length - 1; index >= 0; index--) { |
| (...skipping 1930 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3960 } | 3964 } |
| 3961 } else if (isGrowableListConstructorCall) { | 3965 } else if (isGrowableListConstructorCall) { |
| 3962 push(buildLiteralList(<HInstruction>[])); | 3966 push(buildLiteralList(<HInstruction>[])); |
| 3963 stack.last.instructionType = elementType; | 3967 stack.last.instructionType = elementType; |
| 3964 } else { | 3968 } else { |
| 3965 ClassElement cls = constructor.getEnclosingClass(); | 3969 ClassElement cls = constructor.getEnclosingClass(); |
| 3966 if (cls.isAbstract && constructor.isGenerativeConstructor()) { | 3970 if (cls.isAbstract && constructor.isGenerativeConstructor()) { |
| 3967 generateAbstractClassInstantiationError(send, cls.name); | 3971 generateAbstractClassInstantiationError(send, cls.name); |
| 3968 return; | 3972 return; |
| 3969 } | 3973 } |
| 3970 if (backend.classNeedsRti(cls)) { | 3974 potentiallyAddTypeArguments(inputs, cls, expectedType); |
| 3971 Link<DartType> typeVariable = cls.typeVariables; | |
| 3972 expectedType.typeArguments.forEach((DartType argument) { | |
| 3973 inputs.add(analyzeTypeArgument(argument)); | |
| 3974 typeVariable = typeVariable.tail; | |
| 3975 }); | |
| 3976 assert(typeVariable.isEmpty); | |
| 3977 } | |
| 3978 | 3975 |
| 3979 addInlinedInstantiation(expectedType); | 3976 addInlinedInstantiation(expectedType); |
| 3980 pushInvokeStatic(node, constructor, inputs, elementType); | 3977 pushInvokeStatic(node, constructor, inputs, elementType); |
| 3981 removeInlinedInstantiation(expectedType); | 3978 removeInlinedInstantiation(expectedType); |
| 3982 } | 3979 } |
| 3983 HInstruction newInstance = stack.last; | 3980 HInstruction newInstance = stack.last; |
| 3984 if (isFixedList) { | 3981 if (isFixedList) { |
| 3985 // Overwrite the element type, in case the allocation site has | 3982 // Overwrite the element type, in case the allocation site has |
| 3986 // been inlined. | 3983 // been inlined. |
| 3987 newInstance.instructionType = elementType; | 3984 newInstance.instructionType = elementType; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 4003 // Finally, if we called a redirecting factory constructor, check the type. | 4000 // Finally, if we called a redirecting factory constructor, check the type. |
| 4004 if (isRedirected) { | 4001 if (isRedirected) { |
| 4005 HInstruction checked = potentiallyCheckType(newInstance, type); | 4002 HInstruction checked = potentiallyCheckType(newInstance, type); |
| 4006 if (checked != newInstance) { | 4003 if (checked != newInstance) { |
| 4007 pop(); | 4004 pop(); |
| 4008 stack.add(checked); | 4005 stack.add(checked); |
| 4009 } | 4006 } |
| 4010 } | 4007 } |
| 4011 } | 4008 } |
| 4012 | 4009 |
| 4010 void potentiallyAddTypeArguments(List<HInstruction> inputs, ClassElement cls, |
| 4011 InterfaceType expectedType) { |
| 4012 if (!backend.classNeedsRti(cls)) return; |
| 4013 assert(expectedType.typeArguments.isEmpty || |
| 4014 cls.typeVariables.length == expectedType.typeArguments.length); |
| 4015 expectedType.typeArguments.forEach((DartType argument) { |
| 4016 inputs.add(analyzeTypeArgument(argument)); |
| 4017 }); |
| 4018 } |
| 4019 |
| 4013 /// In checked mode checks the [type] of [node] to be well-bounded. The method | 4020 /// In checked mode checks the [type] of [node] to be well-bounded. The method |
| 4014 /// returns [:true:] if an error can be statically determined. | 4021 /// returns [:true:] if an error can be statically determined. |
| 4015 bool checkTypeVariableBounds(ast.NewExpression node, InterfaceType type) { | 4022 bool checkTypeVariableBounds(ast.NewExpression node, InterfaceType type) { |
| 4016 if (!compiler.enableTypeAssertions) return false; | 4023 if (!compiler.enableTypeAssertions) return false; |
| 4017 | 4024 |
| 4018 Map<DartType, Set<DartType>> seenChecksMap = | 4025 Map<DartType, Set<DartType>> seenChecksMap = |
| 4019 new Map<DartType, Set<DartType>>(); | 4026 new Map<DartType, Set<DartType>>(); |
| 4020 bool definitelyFails = false; | 4027 bool definitelyFails = false; |
| 4021 | 4028 |
| 4022 addTypeVariableBoundCheck(GenericType instance, | 4029 addTypeVariableBoundCheck(GenericType instance, |
| (...skipping 662 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4685 calleeSignature.orderedOptionalParameters; | 4692 calleeSignature.orderedOptionalParameters; |
| 4686 List<Element> callerOptionals = | 4693 List<Element> callerOptionals = |
| 4687 callerSignature.orderedOptionalParameters; | 4694 callerSignature.orderedOptionalParameters; |
| 4688 int i = 0; | 4695 int i = 0; |
| 4689 for (; i < callerOptionals.length; i++) { | 4696 for (; i < callerOptionals.length; i++) { |
| 4690 inputs.add(localsHandler.readLocal(callerOptionals[i])); | 4697 inputs.add(localsHandler.readLocal(callerOptionals[i])); |
| 4691 } | 4698 } |
| 4692 for (; i < calleeOptionals.length; i++) { | 4699 for (; i < calleeOptionals.length; i++) { |
| 4693 inputs.add(handleConstantForOptionalParameter(calleeOptionals[i])); | 4700 inputs.add(handleConstantForOptionalParameter(calleeOptionals[i])); |
| 4694 } | 4701 } |
| 4695 | 4702 potentiallyAddTypeArguments(inputs, element.getEnclosingClass(), |
| 4696 if (backend.classNeedsRti(element.getEnclosingClass())) { | 4703 elements.getType(node.expression)); |
| 4697 ClassElement cls = function.getEnclosingClass(); | |
| 4698 Link<DartType> typeVariable = cls.typeVariables; | |
| 4699 InterfaceType type = elements.getType(node.expression); | |
| 4700 type.typeArguments.forEach((DartType argument) { | |
| 4701 inputs.add(analyzeTypeArgument(argument)); | |
| 4702 typeVariable = typeVariable.tail; | |
| 4703 }); | |
| 4704 assert(typeVariable.isEmpty); | |
| 4705 } | |
| 4706 pushInvokeStatic(node, element, inputs); | 4704 pushInvokeStatic(node, element, inputs); |
| 4707 value = pop(); | 4705 value = pop(); |
| 4708 } else if (node.expression == null) { | 4706 } else if (node.expression == null) { |
| 4709 value = graph.addConstantNull(compiler); | 4707 value = graph.addConstantNull(compiler); |
| 4710 } else { | 4708 } else { |
| 4711 visit(node.expression); | 4709 visit(node.expression); |
| 4712 value = pop(); | 4710 value = pop(); |
| 4713 value = potentiallyCheckType(value, returnType); | 4711 value = potentiallyCheckType(value, returnType); |
| 4714 } | 4712 } |
| 4715 | 4713 |
| (...skipping 1346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6062 for (DartType parameter in type.parameterTypes) { | 6060 for (DartType parameter in type.parameterTypes) { |
| 6063 parameter.accept(this, builder); | 6061 parameter.accept(this, builder); |
| 6064 inputs.add(builder.pop()); | 6062 inputs.add(builder.pop()); |
| 6065 } | 6063 } |
| 6066 | 6064 |
| 6067 for (DartType parameter in type.optionalParameterTypes) { | 6065 for (DartType parameter in type.optionalParameterTypes) { |
| 6068 parameter.accept(this, builder); | 6066 parameter.accept(this, builder); |
| 6069 inputs.add(builder.pop()); | 6067 inputs.add(builder.pop()); |
| 6070 } | 6068 } |
| 6071 | 6069 |
| 6072 Link<DartType> namedParameterTypes = type.namedParameterTypes; | 6070 List<DartType> namedParameterTypes = type.namedParameterTypes; |
| 6073 for (String name in type.namedParameters) { | 6071 List<String> names = type.namedParameters; |
| 6074 ast.DartString dartString = new ast.DartString.literal(name); | 6072 for (int index = 0; index < names.length; index++) { |
| 6073 ast.DartString dartString = new ast.DartString.literal(names[index]); |
| 6075 inputs.add( | 6074 inputs.add( |
| 6076 builder.graph.addConstantString(dartString, builder.compiler)); | 6075 builder.graph.addConstantString(dartString, builder.compiler)); |
| 6077 namedParameterTypes.head.accept(this, builder); | 6076 namedParameterTypes[index].accept(this, builder); |
| 6078 inputs.add(builder.pop()); | 6077 inputs.add(builder.pop()); |
| 6079 namedParameterTypes = namedParameterTypes.tail; | |
| 6080 } | 6078 } |
| 6081 | 6079 |
| 6082 ClassElement cls = builder.compiler.findHelper('RuntimeFunctionType'); | 6080 ClassElement cls = builder.compiler.findHelper('RuntimeFunctionType'); |
| 6083 builder.push(new HFunctionType(inputs, type, new TypeMask.exact(cls))); | 6081 builder.push(new HFunctionType(inputs, type, new TypeMask.exact(cls))); |
| 6084 } | 6082 } |
| 6085 | 6083 |
| 6086 void visitMalformedType(MalformedType type, SsaBuilder builder) { | 6084 void visitMalformedType(MalformedType type, SsaBuilder builder) { |
| 6087 visitDynamicType(builder.compiler.types.dynamicType, builder); | 6085 visitDynamicType(builder.compiler.types.dynamicType, builder); |
| 6088 } | 6086 } |
| 6089 | 6087 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 6114 DartType unaliased = type.unalias(builder.compiler); | 6112 DartType unaliased = type.unalias(builder.compiler); |
| 6115 if (unaliased is TypedefType) throw 'unable to unalias $type'; | 6113 if (unaliased is TypedefType) throw 'unable to unalias $type'; |
| 6116 unaliased.accept(this, builder); | 6114 unaliased.accept(this, builder); |
| 6117 } | 6115 } |
| 6118 | 6116 |
| 6119 void visitDynamicType(DynamicType type, SsaBuilder builder) { | 6117 void visitDynamicType(DynamicType type, SsaBuilder builder) { |
| 6120 ClassElement cls = builder.compiler.findHelper('DynamicRuntimeType'); | 6118 ClassElement cls = builder.compiler.findHelper('DynamicRuntimeType'); |
| 6121 builder.push(new HDynamicType(type, new TypeMask.exact(cls))); | 6119 builder.push(new HDynamicType(type, new TypeMask.exact(cls))); |
| 6122 } | 6120 } |
| 6123 } | 6121 } |
| OLD | NEW |