| 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 1650 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1661 if (backend.classNeedsRti(enclosingClass)) { | 1661 if (backend.classNeedsRti(enclosingClass)) { |
| 1662 // If [enclosingClass] needs RTI, we have to give a value to its | 1662 // If [enclosingClass] needs RTI, we have to give a value to its |
| 1663 // type parameters. | 1663 // type parameters. |
| 1664 ClassElement currentClass = caller.enclosingClass; | 1664 ClassElement currentClass = caller.enclosingClass; |
| 1665 // For a super constructor call, the type is the supertype of | 1665 // For a super constructor call, the type is the supertype of |
| 1666 // [currentClass]. For a redirecting constructor, the type is | 1666 // [currentClass]. For a redirecting constructor, the type is |
| 1667 // the current type. [InterfaceType.asInstanceOf] takes care | 1667 // the current type. [InterfaceType.asInstanceOf] takes care |
| 1668 // of both. | 1668 // of both. |
| 1669 InterfaceType type = currentClass.thisType.asInstanceOf(enclosingClass); | 1669 InterfaceType type = currentClass.thisType.asInstanceOf(enclosingClass); |
| 1670 type = localsHandler.substInContext(type); | 1670 type = localsHandler.substInContext(type); |
| 1671 Link<DartType> typeVariables = enclosingClass.typeVariables; | 1671 List<DartType> arguments = type.typeArguments; |
| 1672 type.typeArguments.forEach((DartType argument) { | 1672 List<DartType> typeVariables = enclosingClass.typeVariables; |
| 1673 localsHandler.updateLocal( | 1673 if (!type.isRaw) { |
| 1674 typeVariables.head.element, | 1674 assert(arguments.length == typeVariables.length); |
| 1675 analyzeTypeArgument(argument)); | 1675 Iterator<DartType> variables = typeVariables.iterator; |
| 1676 typeVariables = typeVariables.tail; | 1676 type.typeArguments.forEach((DartType argument) { |
| 1677 }); | 1677 variables.moveNext(); |
| 1678 // If the supertype is a raw type, we need to set to null the | 1678 localsHandler.updateLocal( |
| 1679 // type variables. | 1679 variables.current.element, |
| 1680 assert(typeVariables.isEmpty | 1680 analyzeTypeArgument(argument)); |
| 1681 || enclosingClass.typeVariables == typeVariables); | 1681 }); |
| 1682 while (!typeVariables.isEmpty) { | 1682 } else { |
| 1683 localsHandler.updateLocal(typeVariables.head.element, | 1683 // If the supertype is a raw type, we need to set to null the |
| 1684 graph.addConstantNull(compiler)); | 1684 // type variables. |
| 1685 typeVariables = typeVariables.tail; | 1685 for (DartType variable in typeVariables) { |
| 1686 localsHandler.updateLocal(variable.element, |
| 1687 graph.addConstantNull(compiler)); |
| 1688 } |
| 1686 } | 1689 } |
| 1687 } | 1690 } |
| 1688 | 1691 |
| 1689 // For redirecting constructors, the fields have already been | 1692 // For redirecting constructors, the fields have already been |
| 1690 // initialized by the caller. | 1693 // initialized by the caller. |
| 1691 if (callee.enclosingClass != caller.enclosingClass) { | 1694 if (callee.enclosingClass != caller.enclosingClass) { |
| 1692 inlinedFrom(callee, () { | 1695 inlinedFrom(callee, () { |
| 1693 buildFieldInitializers(callee.enclosingElement.implementation, | 1696 buildFieldInitializers(callee.enclosingElement.implementation, |
| 1694 fieldValues); | 1697 fieldValues); |
| 1695 }); | 1698 }); |
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1977 // would be of the form: | 1980 // would be of the form: |
| 1978 // [getTypeArgumentByIndex(this, 0), .., getTypeArgumentByIndex(this, k)] | 1981 // [getTypeArgumentByIndex(this, 0), .., getTypeArgumentByIndex(this, k)] |
| 1979 // and k is the number of type arguments of this. If this is the case, | 1982 // and k is the number of type arguments of this. If this is the case, |
| 1980 // we can simply copy the list from this. | 1983 // we can simply copy the list from this. |
| 1981 | 1984 |
| 1982 // These locals are modified by [isIndexedTypeArgumentGet]. | 1985 // These locals are modified by [isIndexedTypeArgumentGet]. |
| 1983 HInstruction source; // The source of the type arguments. | 1986 HInstruction source; // The source of the type arguments. |
| 1984 bool allIndexed = true; | 1987 bool allIndexed = true; |
| 1985 int expectedIndex = 0; | 1988 int expectedIndex = 0; |
| 1986 ClassElement contextClass; // The class of `this`. | 1989 ClassElement contextClass; // The class of `this`. |
| 1987 Link typeVariables; // The list of 'remaining type variables' of `this`. | 1990 int remainingTypeVariables; // The number of 'remaining type variables' |
| 1991 // of `this`. |
| 1988 | 1992 |
| 1989 /// Helper to identify instructions that read a type variable without | 1993 /// Helper to identify instructions that read a type variable without |
| 1990 /// substitution (that is, directly use the index). These instructions | 1994 /// substitution (that is, directly use the index). These instructions |
| 1991 /// are of the form: | 1995 /// are of the form: |
| 1992 /// HInvokeStatic(getTypeArgumentByIndex, this, index) | 1996 /// HInvokeStatic(getTypeArgumentByIndex, this, index) |
| 1993 /// | 1997 /// |
| 1994 /// Return `true` if [instruction] is of that form and the index is the | 1998 /// Return `true` if [instruction] is of that form and the index is the |
| 1995 /// next index in the sequence (held in [expectedIndex]). | 1999 /// next index in the sequence (held in [expectedIndex]). |
| 1996 bool isIndexedTypeArgumentGet(HInstruction instruction) { | 2000 bool isIndexedTypeArgumentGet(HInstruction instruction) { |
| 1997 if (instruction is! HInvokeStatic) return false; | 2001 if (instruction is! HInvokeStatic) return false; |
| 1998 HInvokeStatic invoke = instruction; | 2002 HInvokeStatic invoke = instruction; |
| 1999 if (invoke.element != backend.getGetTypeArgumentByIndex()) { | 2003 if (invoke.element != backend.getGetTypeArgumentByIndex()) { |
| 2000 return false; | 2004 return false; |
| 2001 } | 2005 } |
| 2002 HConstant index = invoke.inputs[1]; | 2006 HConstant index = invoke.inputs[1]; |
| 2003 HInstruction newSource = invoke.inputs[0]; | 2007 HInstruction newSource = invoke.inputs[0]; |
| 2004 if (newSource is! HThis) { | 2008 if (newSource is! HThis) { |
| 2005 return false; | 2009 return false; |
| 2006 } | 2010 } |
| 2007 if (source == null) { | 2011 if (source == null) { |
| 2008 // This is the first match. Extract the context class for the type | 2012 // This is the first match. Extract the context class for the type |
| 2009 // variables and get the list of type variables to keep track of how | 2013 // variables and get the list of type variables to keep track of how |
| 2010 // many arguments we need to process. | 2014 // many arguments we need to process. |
| 2011 source = newSource; | 2015 source = newSource; |
| 2012 contextClass = source.sourceElement.enclosingClass; | 2016 contextClass = source.sourceElement.enclosingClass; |
| 2013 typeVariables = contextClass.typeVariables; | 2017 remainingTypeVariables = contextClass.typeVariables.length; |
| 2014 } else { | 2018 } else { |
| 2015 assert(source == newSource); | 2019 assert(source == newSource); |
| 2016 } | 2020 } |
| 2017 // If there are no more type variables, then there are more type | 2021 // If there are no more type variables, then there are more type |
| 2018 // arguments for the new object than the source has, and it can't be | 2022 // arguments for the new object than the source has, and it can't be |
| 2019 // a copy. Otherwise remove one argument. | 2023 // a copy. Otherwise remove one argument. |
| 2020 if (typeVariables.isEmpty) return false; | 2024 if (remainingTypeVariables == 0) return false; |
| 2021 typeVariables = typeVariables.tail; | 2025 remainingTypeVariables--; |
| 2022 // Check that the index is the one we expect. | 2026 // Check that the index is the one we expect. |
| 2023 IntConstant constant = index.constant; | 2027 IntConstant constant = index.constant; |
| 2024 return constant.value == expectedIndex++; | 2028 return constant.value == expectedIndex++; |
| 2025 } | 2029 } |
| 2026 | 2030 |
| 2027 List<HInstruction> typeArguments = <HInstruction>[]; | 2031 List<HInstruction> typeArguments = <HInstruction>[]; |
| 2028 classElement.typeVariables.forEach((TypeVariableType typeVariable) { | 2032 classElement.typeVariables.forEach((TypeVariableType typeVariable) { |
| 2029 HInstruction argument = localsHandler.readLocal(typeVariable.element); | 2033 HInstruction argument = localsHandler.readLocal(typeVariable.element); |
| 2030 if (allIndexed && !isIndexedTypeArgumentGet(argument)) { | 2034 if (allIndexed && !isIndexedTypeArgumentGet(argument)) { |
| 2031 allIndexed = false; | 2035 allIndexed = false; |
| 2032 } | 2036 } |
| 2033 typeArguments.add(argument); | 2037 typeArguments.add(argument); |
| 2034 }); | 2038 }); |
| 2035 | 2039 |
| 2036 if (source != null && allIndexed && typeVariables.isEmpty) { | 2040 if (source != null && allIndexed && remainingTypeVariables == 0) { |
| 2037 copyRuntimeTypeInfo(source, newObject); | 2041 copyRuntimeTypeInfo(source, newObject); |
| 2038 } else { | 2042 } else { |
| 2039 newObject = | 2043 newObject = |
| 2040 callSetRuntimeTypeInfo(classElement, typeArguments, newObject); | 2044 callSetRuntimeTypeInfo(classElement, typeArguments, newObject); |
| 2041 } | 2045 } |
| 2042 } | 2046 } |
| 2043 | 2047 |
| 2044 // Generate calls to the constructor bodies. | 2048 // Generate calls to the constructor bodies. |
| 2045 HInstruction interceptor = null; | 2049 HInstruction interceptor = null; |
| 2046 for (int index = constructors.length - 1; index >= 0; index--) { | 2050 for (int index = constructors.length - 1; index >= 0; index--) { |
| (...skipping 2095 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4142 } | 4146 } |
| 4143 } else if (isGrowableListConstructorCall) { | 4147 } else if (isGrowableListConstructorCall) { |
| 4144 push(buildLiteralList(<HInstruction>[])); | 4148 push(buildLiteralList(<HInstruction>[])); |
| 4145 stack.last.instructionType = elementType; | 4149 stack.last.instructionType = elementType; |
| 4146 } else { | 4150 } else { |
| 4147 ClassElement cls = constructor.enclosingClass; | 4151 ClassElement cls = constructor.enclosingClass; |
| 4148 if (cls.isAbstract && constructor.isGenerativeConstructor) { | 4152 if (cls.isAbstract && constructor.isGenerativeConstructor) { |
| 4149 generateAbstractClassInstantiationError(send, cls.name); | 4153 generateAbstractClassInstantiationError(send, cls.name); |
| 4150 return; | 4154 return; |
| 4151 } | 4155 } |
| 4152 if (backend.classNeedsRti(cls)) { | 4156 potentiallyAddTypeArguments(inputs, cls, expectedType); |
| 4153 Link<DartType> typeVariable = cls.typeVariables; | |
| 4154 expectedType.typeArguments.forEach((DartType argument) { | |
| 4155 inputs.add(analyzeTypeArgument(argument)); | |
| 4156 typeVariable = typeVariable.tail; | |
| 4157 }); | |
| 4158 assert(typeVariable.isEmpty); | |
| 4159 } | |
| 4160 | 4157 |
| 4161 addInlinedInstantiation(expectedType); | 4158 addInlinedInstantiation(expectedType); |
| 4162 pushInvokeStatic(node, constructor, inputs, elementType); | 4159 pushInvokeStatic(node, constructor, inputs, elementType); |
| 4163 removeInlinedInstantiation(expectedType); | 4160 removeInlinedInstantiation(expectedType); |
| 4164 } | 4161 } |
| 4165 HInstruction newInstance = stack.last; | 4162 HInstruction newInstance = stack.last; |
| 4166 if (isFixedList) { | 4163 if (isFixedList) { |
| 4167 // Overwrite the element type, in case the allocation site has | 4164 // Overwrite the element type, in case the allocation site has |
| 4168 // been inlined. | 4165 // been inlined. |
| 4169 newInstance.instructionType = elementType; | 4166 newInstance.instructionType = elementType; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 4185 // Finally, if we called a redirecting factory constructor, check the type. | 4182 // Finally, if we called a redirecting factory constructor, check the type. |
| 4186 if (isRedirected) { | 4183 if (isRedirected) { |
| 4187 HInstruction checked = potentiallyCheckType(newInstance, type); | 4184 HInstruction checked = potentiallyCheckType(newInstance, type); |
| 4188 if (checked != newInstance) { | 4185 if (checked != newInstance) { |
| 4189 pop(); | 4186 pop(); |
| 4190 stack.add(checked); | 4187 stack.add(checked); |
| 4191 } | 4188 } |
| 4192 } | 4189 } |
| 4193 } | 4190 } |
| 4194 | 4191 |
| 4192 void potentiallyAddTypeArguments(List<HInstruction> inputs, ClassElement cls, |
| 4193 InterfaceType expectedType) { |
| 4194 if (!backend.classNeedsRti(cls)) return; |
| 4195 assert(expectedType.typeArguments.isEmpty || |
| 4196 cls.typeVariables.length == expectedType.typeArguments.length); |
| 4197 expectedType.typeArguments.forEach((DartType argument) { |
| 4198 inputs.add(analyzeTypeArgument(argument)); |
| 4199 }); |
| 4200 } |
| 4201 |
| 4195 /// In checked mode checks the [type] of [node] to be well-bounded. The method | 4202 /// In checked mode checks the [type] of [node] to be well-bounded. The method |
| 4196 /// returns [:true:] if an error can be statically determined. | 4203 /// returns [:true:] if an error can be statically determined. |
| 4197 bool checkTypeVariableBounds(ast.NewExpression node, InterfaceType type) { | 4204 bool checkTypeVariableBounds(ast.NewExpression node, InterfaceType type) { |
| 4198 if (!compiler.enableTypeAssertions) return false; | 4205 if (!compiler.enableTypeAssertions) return false; |
| 4199 | 4206 |
| 4200 Map<DartType, Set<DartType>> seenChecksMap = | 4207 Map<DartType, Set<DartType>> seenChecksMap = |
| 4201 new Map<DartType, Set<DartType>>(); | 4208 new Map<DartType, Set<DartType>>(); |
| 4202 bool definitelyFails = false; | 4209 bool definitelyFails = false; |
| 4203 | 4210 |
| 4204 addTypeVariableBoundCheck(GenericType instance, | 4211 addTypeVariableBoundCheck(GenericType instance, |
| (...skipping 676 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4881 targetSignature.orderedOptionalParameters; | 4888 targetSignature.orderedOptionalParameters; |
| 4882 List<Element> redirectingOptionals = | 4889 List<Element> redirectingOptionals = |
| 4883 redirectingSignature.orderedOptionalParameters; | 4890 redirectingSignature.orderedOptionalParameters; |
| 4884 int i = 0; | 4891 int i = 0; |
| 4885 for (; i < redirectingOptionals.length; i++) { | 4892 for (; i < redirectingOptionals.length; i++) { |
| 4886 inputs.add(localsHandler.readLocal(redirectingOptionals[i])); | 4893 inputs.add(localsHandler.readLocal(redirectingOptionals[i])); |
| 4887 } | 4894 } |
| 4888 for (; i < targetOptionals.length; i++) { | 4895 for (; i < targetOptionals.length; i++) { |
| 4889 inputs.add(handleConstantForOptionalParameter(targetOptionals[i])); | 4896 inputs.add(handleConstantForOptionalParameter(targetOptionals[i])); |
| 4890 } | 4897 } |
| 4891 | |
| 4892 ClassElement targetClass = targetConstructor.enclosingClass; | 4898 ClassElement targetClass = targetConstructor.enclosingClass; |
| 4893 if (backend.classNeedsRti(targetClass)) { | 4899 if (backend.classNeedsRti(targetClass)) { |
| 4894 ClassElement cls = redirectingConstructor.enclosingClass; | 4900 ClassElement cls = redirectingConstructor.enclosingClass; |
| 4895 InterfaceType targetType = | 4901 InterfaceType targetType = |
| 4896 redirectingConstructor.computeEffectiveTargetType(cls.thisType); | 4902 redirectingConstructor.computeEffectiveTargetType(cls.thisType); |
| 4897 targetType = localsHandler.substInContext(targetType); | 4903 targetType = localsHandler.substInContext(targetType); |
| 4898 targetType.typeArguments.forEach((DartType argument) { | 4904 targetType.typeArguments.forEach((DartType argument) { |
| 4899 inputs.add(analyzeTypeArgument(argument)); | 4905 inputs.add(analyzeTypeArgument(argument)); |
| 4900 }); | 4906 }); |
| 4901 } | 4907 } |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5195 functionElement.computeEffectiveTargetType(type); | 5201 functionElement.computeEffectiveTargetType(type); |
| 5196 expectedType = localsHandler.substInContext(expectedType); | 5202 expectedType = localsHandler.substInContext(expectedType); |
| 5197 | 5203 |
| 5198 if (constructor.isFactoryConstructor) { | 5204 if (constructor.isFactoryConstructor) { |
| 5199 registry.registerFactoryWithTypeArguments(); | 5205 registry.registerFactoryWithTypeArguments(); |
| 5200 } | 5206 } |
| 5201 | 5207 |
| 5202 ClassElement cls = constructor.enclosingClass; | 5208 ClassElement cls = constructor.enclosingClass; |
| 5203 | 5209 |
| 5204 if (backend.classNeedsRti(cls)) { | 5210 if (backend.classNeedsRti(cls)) { |
| 5205 Link<DartType> typeVariable = cls.typeVariables; | 5211 List<DartType> typeVariable = cls.typeVariables; |
| 5206 expectedType.typeArguments.forEach((DartType argument) { | 5212 expectedType.typeArguments.forEach((DartType argument) { |
| 5207 inputs.add(analyzeTypeArgument(argument)); | 5213 inputs.add(analyzeTypeArgument(argument)); |
| 5208 typeVariable = typeVariable.tail; | |
| 5209 }); | 5214 }); |
| 5210 assert(typeVariable.isEmpty); | 5215 assert(typeVariable.isEmpty); |
| 5211 } | 5216 } |
| 5212 | 5217 |
| 5213 // The instruction type will always be a subtype of the mapLiteralClass, but | 5218 // The instruction type will always be a subtype of the mapLiteralClass, but |
| 5214 // type inference might discover a more specific type, or find nothing (in | 5219 // type inference might discover a more specific type, or find nothing (in |
| 5215 // dart2js unit tests). | 5220 // dart2js unit tests). |
| 5216 TypeMask mapType = new TypeMask.nonNullSubtype(backend.mapLiteralClass); | 5221 TypeMask mapType = new TypeMask.nonNullSubtype(backend.mapLiteralClass); |
| 5217 TypeMask returnTypeMask = TypeMaskFactory.inferredReturnTypeForElement( | 5222 TypeMask returnTypeMask = TypeMaskFactory.inferredReturnTypeForElement( |
| 5218 constructor, compiler); | 5223 constructor, compiler); |
| (...skipping 1114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6333 for (DartType parameter in type.parameterTypes) { | 6338 for (DartType parameter in type.parameterTypes) { |
| 6334 parameter.accept(this, builder); | 6339 parameter.accept(this, builder); |
| 6335 inputs.add(builder.pop()); | 6340 inputs.add(builder.pop()); |
| 6336 } | 6341 } |
| 6337 | 6342 |
| 6338 for (DartType parameter in type.optionalParameterTypes) { | 6343 for (DartType parameter in type.optionalParameterTypes) { |
| 6339 parameter.accept(this, builder); | 6344 parameter.accept(this, builder); |
| 6340 inputs.add(builder.pop()); | 6345 inputs.add(builder.pop()); |
| 6341 } | 6346 } |
| 6342 | 6347 |
| 6343 Link<DartType> namedParameterTypes = type.namedParameterTypes; | 6348 List<DartType> namedParameterTypes = type.namedParameterTypes; |
| 6344 for (String name in type.namedParameters) { | 6349 List<String> names = type.namedParameters; |
| 6345 ast.DartString dartString = new ast.DartString.literal(name); | 6350 for (int index = 0; index < names.length; index++) { |
| 6351 ast.DartString dartString = new ast.DartString.literal(names[index]); |
| 6346 inputs.add( | 6352 inputs.add( |
| 6347 builder.graph.addConstantString(dartString, builder.compiler)); | 6353 builder.graph.addConstantString(dartString, builder.compiler)); |
| 6348 namedParameterTypes.head.accept(this, builder); | 6354 namedParameterTypes[index].accept(this, builder); |
| 6349 inputs.add(builder.pop()); | 6355 inputs.add(builder.pop()); |
| 6350 namedParameterTypes = namedParameterTypes.tail; | |
| 6351 } | 6356 } |
| 6352 | 6357 |
| 6353 ClassElement cls = builder.backend.findHelper('RuntimeFunctionType'); | 6358 ClassElement cls = builder.backend.findHelper('RuntimeFunctionType'); |
| 6354 builder.push(new HFunctionType(inputs, type, new TypeMask.exact(cls))); | 6359 builder.push(new HFunctionType(inputs, type, new TypeMask.exact(cls))); |
| 6355 } | 6360 } |
| 6356 | 6361 |
| 6357 void visitMalformedType(MalformedType type, SsaBuilder builder) { | 6362 void visitMalformedType(MalformedType type, SsaBuilder builder) { |
| 6358 visitDynamicType(const DynamicType(), builder); | 6363 visitDynamicType(const DynamicType(), builder); |
| 6359 } | 6364 } |
| 6360 | 6365 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 6386 if (unaliased is TypedefType) throw 'unable to unalias $type'; | 6391 if (unaliased is TypedefType) throw 'unable to unalias $type'; |
| 6387 unaliased.accept(this, builder); | 6392 unaliased.accept(this, builder); |
| 6388 } | 6393 } |
| 6389 | 6394 |
| 6390 void visitDynamicType(DynamicType type, SsaBuilder builder) { | 6395 void visitDynamicType(DynamicType type, SsaBuilder builder) { |
| 6391 JavaScriptBackend backend = builder.compiler.backend; | 6396 JavaScriptBackend backend = builder.compiler.backend; |
| 6392 ClassElement cls = backend.findHelper('DynamicRuntimeType'); | 6397 ClassElement cls = backend.findHelper('DynamicRuntimeType'); |
| 6393 builder.push(new HDynamicType(type, new TypeMask.exact(cls))); | 6398 builder.push(new HDynamicType(type, new TypeMask.exact(cls))); |
| 6394 } | 6399 } |
| 6395 } | 6400 } |
| OLD | NEW |