Index: pkg/compiler/lib/src/ssa/builder.dart |
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart |
index 77025b0cc96e44c2c2224bc462b7a3d62b9d76ad..fe78ce20bc88ec77df550bc68dd242b7d74b257c 100644 |
--- a/pkg/compiler/lib/src/ssa/builder.dart |
+++ b/pkg/compiler/lib/src/ssa/builder.dart |
@@ -2327,10 +2327,12 @@ class SsaBuilder extends ast.Visitor |
removeInlinedInstantiation(type); |
// Create the runtime type information, if needed. |
if (backend.classNeedsRti(classElement)) { |
- // Read the values of the type arguments and create a list to set on the |
- // newly create object. We can identify the case where the new list |
- // would be of the form: |
+ // Read the values of the type arguments and create a HTypeInfoExpression |
+ // to set on the newly create object. We can identify the case where the |
+ // expression would be of the form: |
+ // |
// [getTypeArgumentByIndex(this, 0), .., getTypeArgumentByIndex(this, k)] |
+ // |
// and k is the number of type arguments of this. If this is the case, |
// we can simply copy the list from this. |
@@ -2343,41 +2345,42 @@ class SsaBuilder extends ast.Visitor |
// of `this`. |
/// Helper to identify instructions that read a type variable without |
- /// substitution (that is, directly use the index). These instructions |
- /// are of the form: |
- /// HInvokeStatic(getTypeArgumentByIndex, this, index) |
+ /// substitution (that is, directly use the index). These are |
+ /// HTypeInfoReadVariable instructions that require no substitution. |
/// |
/// Return `true` if [instruction] is of that form and the index is the |
/// next index in the sequence (held in [expectedIndex]). |
+ |
+ /// TODO: Move this to a simplifier optimization of HTypeInfoExpression. |
bool isIndexedTypeArgumentGet(HInstruction instruction) { |
- if (instruction is! HInvokeStatic) return false; |
- HInvokeStatic invoke = instruction; |
- if (invoke.element != helpers.getTypeArgumentByIndex) { |
- return false; |
- } |
- HConstant index = invoke.inputs[1]; |
- HInstruction newSource = invoke.inputs[0]; |
- if (newSource is! HThis) { |
- return false; |
- } |
- if (source == null) { |
- // This is the first match. Extract the context class for the type |
- // variables and get the list of type variables to keep track of how |
- // many arguments we need to process. |
- source = newSource; |
- contextClass = source.sourceElement.enclosingClass; |
- remainingTypeVariables = contextClass.typeVariables.length; |
- } else { |
- assert(source == newSource); |
+ if (instruction is HTypeInfoReadVariable) { |
+ HInstruction newSource = instruction.inputs[0]; |
+ if (newSource is! HThis) { |
+ return false; |
+ } |
+ if (source == null) { |
+ // This is the first match. Extract the context class for the type |
+ // variables and get the list of type variables to keep track of how |
+ // many arguments we need to process. |
+ source = newSource; |
+ contextClass = source.sourceElement.enclosingClass; |
+ if (needsSubstitutionForTypeVariableAccess(contextClass)) { |
+ return false; |
+ } |
+ remainingTypeVariables = contextClass.typeVariables.length; |
+ } else { |
+ assert(source == newSource); |
+ } |
+ // If there are no more type variables, then there are more type |
+ // arguments for the new object than the source has, and it can't be |
+ // a copy. Otherwise remove one argument. |
+ if (remainingTypeVariables == 0) return false; |
+ remainingTypeVariables--; |
+ // Check that the index is the one we expect. |
+ int index = instruction.variable.element.index; |
+ return index == expectedIndex++; |
} |
- // If there are no more type variables, then there are more type |
- // arguments for the new object than the source has, and it can't be |
- // a copy. Otherwise remove one argument. |
- if (remainingTypeVariables == 0) return false; |
- remainingTypeVariables--; |
- // Check that the index is the one we expect. |
- IntConstantValue constant = index.constant; |
- return constant.primitiveValue == expectedIndex++; |
+ return false; |
} |
List<HInstruction> typeArguments = <HInstruction>[]; |
@@ -2391,10 +2394,18 @@ class SsaBuilder extends ast.Visitor |
}); |
if (source != null && allIndexed && remainingTypeVariables == 0) { |
- copyRuntimeTypeInfo(source, newObject); |
+ HInstruction typeInfo = |
+ new HTypeInfoReadRaw(source, backend.dynamicType); |
+ add(typeInfo); |
+ newObject = callSetRuntimeTypeInfo(typeInfo, newObject); |
} else { |
- newObject = |
- callSetRuntimeTypeInfo(classElement, typeArguments, newObject); |
+ HInstruction typeInfo = new HTypeInfoExpression( |
+ TypeInfoExpressionKind.INSTANCE, |
+ classElement.thisType, |
+ typeArguments, |
+ backend.dynamicType); |
+ add(typeInfo); |
+ newObject = callSetRuntimeTypeInfo(typeInfo, newObject); |
} |
} |
@@ -4710,32 +4721,15 @@ class SsaBuilder extends ast.Visitor |
} |
/** |
- * Generate code to extract the type arguments from the object, substitute |
- * them as an instance of the type we are testing against (if necessary), and |
- * extract the type argument by the index of the variable in the list of type |
- * variables for that class. |
+ * Generate code to extract the type argument from the object. |
*/ |
- HInstruction readTypeVariable(ClassElement cls, TypeVariableElement variable, |
+ HInstruction readTypeVariable(TypeVariableType variable, |
{SourceInformation sourceInformation}) { |
assert(sourceElement.isInstanceMember); |
- |
+ assert(variable is! MethodTypeVariableType); |
HInstruction target = localsHandler.readThis(); |
- HConstant index = graph.addConstantInt(variable.index, compiler); |
- |
- if (needsSubstitutionForTypeVariableAccess(cls)) { |
- // TODO(ahe): Creating a string here is unfortunate. It is slow (due to |
- // string concatenation in the implementation), and may prevent |
- // segmentation of '$'. |
- js.Name substitutionName = backend.namer.runtimeTypeName(cls); |
- HInstruction substitutionNameInstr = |
- graph.addConstantStringFromName(substitutionName, compiler); |
- pushInvokeStatic(null, helpers.getRuntimeTypeArgument, |
- [target, substitutionNameInstr, index], |
- typeMask: backend.dynamicType, sourceInformation: sourceInformation); |
- } else { |
- pushInvokeStatic(null, helpers.getTypeArgumentByIndex, [target, index], |
- typeMask: backend.dynamicType, sourceInformation: sourceInformation); |
- } |
+ push(new HTypeInfoReadVariable(variable, target, backend.dynamicType) |
+ ..sourceInformation = sourceInformation); |
return pop(); |
} |
@@ -4753,6 +4747,9 @@ class SsaBuilder extends ast.Visitor |
HInstruction addTypeVariableReference(TypeVariableType type, |
{SourceInformation sourceInformation}) { |
assert(assertTypeInContext(type)); |
+ if (type is MethodTypeVariableType) { |
+ return graph.addConstantNull(compiler); |
+ } |
Element member = sourceElement; |
bool isClosure = member.enclosingElement.isClosure; |
if (isClosure) { |
@@ -4777,8 +4774,7 @@ class SsaBuilder extends ast.Visitor |
isInConstructorContext) { |
// The type variable is stored on the "enclosing object" and needs to be |
// accessed using the this-reference in the closure. |
- return readTypeVariable(member.enclosingClass, type.element, |
- sourceInformation: sourceInformation); |
+ return readTypeVariable(type, sourceInformation: sourceInformation); |
} else { |
assert(member.isField); |
// The type variable is stored in a parameter of the method. |
@@ -4796,8 +4792,7 @@ class SsaBuilder extends ast.Visitor |
sourceInformation: sourceInformation); |
} else if (member.isInstanceMember) { |
// The type variable is stored on the object. |
- return readTypeVariable(member.enclosingClass, type.element, |
- sourceInformation: sourceInformation); |
+ return readTypeVariable(type, sourceInformation: sourceInformation); |
} else { |
reporter.internalError( |
type.element, 'Unexpected type variable in static context.'); |
@@ -4819,15 +4814,14 @@ class SsaBuilder extends ast.Visitor |
} |
List<HInstruction> inputs = <HInstruction>[]; |
- |
- js.Expression template = |
- rtiEncoder.getTypeRepresentationWithPlaceholders(argument, (variable) { |
- inputs.add(addTypeVariableReference(variable)); |
+ argument.forEachTypeVariable((variable) { |
+ if (variable is! MethodTypeVariableType) { |
+ inputs.add(analyzeTypeArgument(variable)); |
+ } |
}); |
- |
- js.Template code = new js.Template(null, template); |
- HInstruction result = new HForeignCode(code, backend.stringType, inputs, |
- nativeBehavior: native.NativeBehavior.PURE); |
+ HInstruction result = new HTypeInfoExpression( |
+ TypeInfoExpressionKind.COMPLETE, argument, inputs, backend.dynamicType) |
+ ..sourceInformation = sourceInformation; |
add(result); |
return result; |
} |
@@ -4844,25 +4838,27 @@ class SsaBuilder extends ast.Visitor |
}); |
// TODO(15489): Register at codegen. |
registry?.registerInstantiation(type); |
- return callSetRuntimeTypeInfo(type.element, inputs, newObject); |
+ return callSetRuntimeTypeInfoWithTypeArguments( |
+ type.element, inputs, newObject); |
} |
- void copyRuntimeTypeInfo(HInstruction source, HInstruction target) { |
- Element copyHelper = helpers.copyTypeArguments; |
- pushInvokeStatic(null, copyHelper, [source, target], |
- sourceInformation: target.sourceInformation); |
- pop(); |
- } |
- |
- HInstruction callSetRuntimeTypeInfo(ClassElement element, |
+ HInstruction callSetRuntimeTypeInfoWithTypeArguments(ClassElement element, |
List<HInstruction> rtiInputs, HInstruction newObject) { |
- if (!backend.classNeedsRti(element) || element.typeVariables.isEmpty) { |
+ if (!backend.classNeedsRti(element)) { |
return newObject; |
} |
- HInstruction typeInfo = buildLiteralList(rtiInputs); |
+ HInstruction typeInfo = new HTypeInfoExpression( |
+ TypeInfoExpressionKind.INSTANCE, |
+ element.thisType, |
+ rtiInputs, |
+ backend.dynamicType); |
add(typeInfo); |
+ return callSetRuntimeTypeInfo(typeInfo, newObject); |
+ } |
+ HInstruction callSetRuntimeTypeInfo( |
+ HInstruction typeInfo, HInstruction newObject) { |
// Set the runtime type information on the object. |
Element typeInfoSetterElement = helpers.setRuntimeTypeInfo; |
pushInvokeStatic( |
@@ -4877,7 +4873,7 @@ class SsaBuilder extends ast.Visitor |
stack.last is HInvokeStatic || stack.last == newObject, |
message: "Unexpected `stack.last`: Found ${stack.last}, " |
"expected ${newObject} or an HInvokeStatic. " |
- "State: element=$element, rtiInputs=$rtiInputs, stack=$stack.")); |
+ "State: typeInfo=$typeInfo, stack=$stack.")); |
stack.last.instructionType = newObject.instructionType; |
return pop(); |
} |
@@ -5103,8 +5099,7 @@ class SsaBuilder extends ast.Visitor |
List<HInstruction> inputs, ClassElement cls, InterfaceType expectedType, |
{SourceInformation sourceInformation}) { |
if (!backend.classNeedsRti(cls)) return; |
- assert(expectedType.typeArguments.isEmpty || |
- cls.typeVariables.length == expectedType.typeArguments.length); |
+ assert(cls.typeVariables.length == expectedType.typeArguments.length); |
expectedType.typeArguments.forEach((DartType argument) { |
inputs.add( |
analyzeTypeArgument(argument, sourceInformation: sourceInformation)); |
@@ -6814,7 +6809,8 @@ class SsaBuilder extends ast.Visitor |
} |
// TODO(15489): Register at codegen. |
registry?.registerInstantiation(type); |
- return callSetRuntimeTypeInfo(type.element, arguments, object); |
+ return callSetRuntimeTypeInfoWithTypeArguments( |
+ type.element, arguments, object); |
} |
visitLiteralList(ast.LiteralList node) { |