Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(24)

Unified Diff: pkg/compiler/lib/src/ssa/builder_kernel.dart

Issue 2841213002: dart2js-kernel: Bind type variables in generative constructor. (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/ssa/builder_kernel.dart
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 9d1d2bf0699bb4bac62fbfe4174bef5dfd141cbc..8a0e17737cafae284b0c4cb9e45a40fafd42267e 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -158,6 +158,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
if (targetElement is ConstructorBodyElement) {
_targetIsConstructorBody = true;
}
+ _targetStack.add(target);
}
HGraph build() {
@@ -219,67 +220,123 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
return result;
}
+ /// Extend current method parameters with parameters for the class type
+ /// parameters. If the class has type parameters but does not need them, bind
+ /// to `dynamic` (represented as `null`) so the bindings are available for
+ /// building types up the inheritance chain of generative constructors.
void _addClassTypeVariablesIfNeeded(ir.Member constructor) {
var enclosing = constructor.enclosingClass;
- if (rtiNeed.classNeedsRti(astAdapter.getElement(enclosing))) {
- enclosing.typeParameters.forEach((ir.TypeParameter typeParameter) {
- var typeParamElement = astAdapter.getElement(typeParameter);
- HParameterValue param =
- addParameter(typeParamElement, commonMasks.nonNullType);
- // This is a little bit wacky (and n^2) until we make the localsHandler
- // take Kernel DartTypes instead of just the AST DartTypes.
- var typeVariableType = astAdapter
- .getClass(enclosing)
- .typeVariables
- .firstWhere(
- (ResolutionTypeVariableType i) => i.name == typeParameter.name);
- localsHandler.directLocals[
- localsHandler.getTypeVariableAsLocal(typeVariableType)] = param;
- });
- }
+ bool needParameters;
+ enclosing.typeParameters.forEach((ir.TypeParameter typeParameter) {
+ var typeParamElement = astAdapter.getElement(typeParameter);
+ HInstruction param;
+ needParameters ??=
+ rtiNeed.classNeedsRti(astAdapter.getElement(enclosing));
+ if (needParameters) {
+ param = addParameter(typeParamElement, commonMasks.nonNullType);
+ } else {
+ // Unused, so bind to `dynamic`.
+ param = graph.addConstantNull(closedWorld);
+ }
+ // This is a little bit wacky (and n^2) until we make the localsHandler
+ // take Kernel DartTypes instead of just the AST DartTypes.
+ var typeVariableType = astAdapter
+ .getClass(enclosing)
+ .typeVariables
+ .firstWhere(
+ (ResolutionTypeVariableType i) => i.name == typeParameter.name);
+ localsHandler.directLocals[
+ localsHandler.getTypeVariableAsLocal(typeVariableType)] = param;
+ });
}
- /// Builds generative constructors.
+ /// Builds a generative constructor.
+ ///
+ /// Generative constructors are built in stages, in effect inlining the
+ /// initializers and constructor bodies up the inheritance chain.
+ ///
+ /// 1. Extend method parameters with parameters the class's type parameters.
Siggi Cherem (dart-lang) 2017/04/27 00:32:27 with parameters the => with the
+ ///
+ /// 2. Add type checks for value parameters (might need result of (1)).
+ ///
+ /// 3. Walk inheritance chain to build bindings for type parameters of
+ /// superclasses and mixed-in classes.
+ ///
+ /// 4. Collect initializer values. Walk up inheritance chain to collect field
+ /// initializers from field declarations, initializing parameters and
+ /// initializer.
Siggi Cherem (dart-lang) 2017/04/27 00:32:27 "intializer" => "initializer assignments"? or "ini
+ ///
+ /// 5. Create reified type information for instance.
Siggi Cherem (dart-lang) 2017/04/27 00:32:27 nit: for instance => for the object instance? (I r
+ ///
+ /// 6. Allocate instance and assign initializers and reified type information
Siggi Cherem (dart-lang) 2017/04/27 00:32:27 instance => object instance
+ /// to fields by calling JavaScript constructor.
///
- /// Generative constructors are built in two stages.
+ /// 7. Walk inheritance chain to call or inline constructor bodies.
///
- /// First, the field values for every instance field for every class in the
- /// class hierarchy are collected. Then, create a function body that sets
- /// all of the instance fields to the collected values and call the
- /// constructor bodies for all constructors in the hierarchy.
+ /// All the bindings are put in the constructor's locals handler. The
+ /// implication is that a class cannot be extended or mixed-in twice. If we in
+ /// future support repeated uses of a mixin class, we should do so by cloning
Siggi Cherem (dart-lang) 2017/04/27 00:32:27 in future => in the future
+ /// the mixin class in the Kernel input.
void buildConstructor(ir.Constructor constructor) {
+ ir.Class constructedClass = constructor.enclosingClass;
+
openFunction();
_addClassTypeVariablesIfNeeded(constructor);
+ // TODO(sra): Type parameter constraint checks.
+
+ // TODO(sra): Checked mode parameter checks.
+
// Collect field values for the current class.
- // TODO(het): Does kernel always put field initializers in the constructor
- // initializer list? If so then this is unnecessary...
Map<ir.Field, HInstruction> fieldValues =
- _collectFieldValues(constructor.enclosingClass);
+ _collectFieldValues(constructedClass);
List<ir.Constructor> constructorChain = <ir.Constructor>[];
-
_buildInitializers(constructor, constructorChain, fieldValues);
final constructorArguments = <HInstruction>[];
// Doing this instead of fieldValues.forEach because we haven't defined the
// order of the arguments here. We can define that with JElements.
- astAdapter.getClass(constructor.enclosingClass).forEachInstanceField(
+ astAdapter.getClass(constructedClass).forEachInstanceField(
(ClassElement enclosingClass, FieldElement member) {
var value = fieldValues[astAdapter.getFieldFromElement(member)];
+ assert(value != null,
+ 'No value for field ${member} aka ${astAdapter.getFieldFromElement(member)}');
constructorArguments.add(value);
}, includeSuperAndInjectedMembers: true);
- // TODO(het): If the class needs runtime type information, add it as a
- // constructor argument.
+ // Create the runtime type information, if needed.
+ bool hasRtiInput = backend.rtiNeed
+ .classNeedsRtiField(astAdapter.getClass(constructedClass));
+ if (hasRtiInput) {
+ // Read the values of the type arguments and create a HTypeInfoExpression
+ // to set on the newly create object.
+ List<HInstruction> typeArguments = <HInstruction>[];
+ for (ir.DartType typeParameter
+ in constructedClass.thisType.typeArguments) {
+ HInstruction argument = localsHandler.readLocal(localsHandler
+ .getTypeVariableAsLocal(astAdapter.getDartType(typeParameter)
+ as ResolutionTypeVariableType));
+ typeArguments.add(argument);
+ }
+
+ HInstruction typeInfo = new HTypeInfoExpression(
+ TypeInfoExpressionKind.INSTANCE,
+ astAdapter.getClass(constructedClass).thisType,
+ typeArguments,
+ commonMasks.dynamicType);
+ add(typeInfo);
+ constructorArguments.add(typeInfo);
+ }
+
HInstruction newObject = new HCreate(
- astAdapter.getClass(constructor.enclosingClass),
+ astAdapter.getClass(constructedClass),
constructorArguments,
new TypeMask.nonNullExact(
- astAdapter.getClass(constructor.enclosingClass), closedWorld),
+ astAdapter.getClass(constructedClass), closedWorld),
instantiatedTypes: <ResolutionInterfaceType>[
- astAdapter.getClass(constructor.enclosingClass).thisType
+ astAdapter.getClass(constructedClass).thisType
],
- hasRtiInput: false);
+ hasRtiInput: hasRtiInput);
add(newObject);
@@ -316,7 +373,16 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
bodyCallInputs.add(localsHandler.readLocal(scopeData.boxElement));
}
- // TODO(sra): Pass type arguments.
+ // Pass type arguments.
+ ir.Class currentClass = body.enclosingClass;
+ if (backend.rtiNeed.classNeedsRti(astAdapter.getClass(currentClass))) {
+ for (ir.DartType typeParameter in currentClass.thisType.typeArguments) {
+ HInstruction argument = localsHandler.readLocal(localsHandler
+ .getTypeVariableAsLocal(astAdapter.getDartType(typeParameter)
+ as ResolutionTypeVariableType));
+ bodyCallInputs.add(argument);
+ }
+ }
_invokeConstructorBody(body, bodyCallInputs);
}
@@ -341,6 +407,27 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
add(invoke);
}
+ withCurrentIrNode(ir.Node node, f()) {
+ compiler.reporter.withCurrentElement(astAdapter.getElement(node), f);
+ }
+
+ /// Sets context for generating code that is the result of inlining
+ /// [inlinedTarget].
+ inlinedFrom(ir.TreeNode inlinedTarget, f()) {
+ withCurrentIrNode(inlinedTarget, () {
+ SourceInformationBuilder oldSourceInformationBuilder =
+ sourceInformationBuilder;
+ // TODO(sra): Update sourceInformationBuilder to Kernel.
+ // sourceInformationBuilder =
+ // sourceInformationBuilder.forContext(resolvedAst);
+ _targetStack.add(inlinedTarget);
+ var result = f();
+ sourceInformationBuilder = oldSourceInformationBuilder;
+ _targetStack.removeLast();
+ return result;
+ });
+ }
+
/// Maps the instance fields of a class to their SSA values.
Map<ir.Field, HInstruction> _collectFieldValues(ir.Class clazz) {
final fieldValues = <ir.Field, HInstruction>{};
@@ -353,8 +440,10 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
// Gotta update the resolvedAst when we're looking at field values
// outside the constructor.
astAdapter.pushResolvedAst(field);
- field.initializer.accept(this);
- fieldValues[field] = pop();
+ inlinedFrom(field, () {
+ field.initializer.accept(this);
+ fieldValues[field] = pop();
+ });
astAdapter.popResolvedAstStack();
}
}
@@ -368,26 +457,36 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
ir.Constructor constructor,
List<ir.Constructor> constructorChain,
Map<ir.Field, HInstruction> fieldValues) {
+ astAdapter.assertAtResolvedAstFor(constructor);
constructorChain.add(constructor);
+
var foundSuperOrRedirectCall = false;
for (var initializer in constructor.initializers) {
- if (initializer is ir.SuperInitializer ||
- initializer is ir.RedirectingInitializer) {
- foundSuperOrRedirectCall = true;
- var superOrRedirectConstructor = initializer.target;
- var arguments = _normalizeAndBuildArguments(
- superOrRedirectConstructor.function, initializer.arguments);
- _buildInlinedInitializers(superOrRedirectConstructor, arguments,
- constructorChain, fieldValues);
- } else if (initializer is ir.FieldInitializer) {
+ if (initializer is ir.FieldInitializer) {
initializer.value.accept(this);
fieldValues[initializer.field] = pop();
+ } else if (initializer is ir.SuperInitializer) {
+ assert(!foundSuperOrRedirectCall);
+ foundSuperOrRedirectCall = true;
+ _inlineSuperInitializer(
+ initializer, constructorChain, fieldValues, constructor);
+ } else if (initializer is ir.RedirectingInitializer) {
+ assert(!foundSuperOrRedirectCall);
+ foundSuperOrRedirectCall = true;
+ _inlineRedirectingInitializer(
+ initializer, constructorChain, fieldValues, constructor);
+ } else if (initializer is ir.LocalInitializer) {
+ assert(false, 'ir.LocalInitializer not handled');
+ } else if (initializer is ir.InvalidInitializer) {
+ assert(false, 'ir.InvalidInitializer not handled');
}
}
if (!foundSuperOrRedirectCall) {
- assert(constructor.enclosingClass == astAdapter.objectClass,
- 'All constructors have super-constructor initializers, except Object()');
+ assert(
+ constructor.enclosingClass == astAdapter.objectClass,
+ 'All constructors should have super- or redirecting- initializers,'
+ ' except Object()');
}
}
@@ -432,17 +531,82 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
return builtArguments;
}
+ /// Creates localsHandler bindings for type parameters of a Supertype.
+ void _bindSupertypeTypeParameters(ir.Supertype supertype) {
+ ir.Class cls = supertype.classNode;
+ var parameters = cls.typeParameters;
+ var arguments = supertype.typeArguments;
+ assert(arguments.length == parameters.length);
+
+ for (int i = 0; i < parameters.length; i++) {
+ ir.DartType argument = arguments[i];
+ ir.TypeParameter parameter = parameters[i];
+
+ localsHandler.updateLocal(
+ localsHandler.getTypeVariableAsLocal(
+ astAdapter.getDartType(new ir.TypeParameterType(parameter))),
+ typeBuilder.analyzeTypeArgument(
+ astAdapter.getDartType(argument), sourceElement));
+ }
+ }
+
+ /// Inlines the given redirecting [constructor]'s initializers by collecting
+ /// its field values and building its constructor initializers. We visit super
+ /// constructors all the way up to the [Object] constructor.
+ void _inlineRedirectingInitializer(
+ ir.RedirectingInitializer initializer,
+ List<ir.Constructor> constructorChain,
+ Map<ir.Field, HInstruction> fieldValues,
+ ir.Constructor caller) {
+ var superOrRedirectConstructor = initializer.target;
+ var arguments = _normalizeAndBuildArguments(
+ superOrRedirectConstructor.function, initializer.arguments);
+
+ // Redirecting initializer already has [localsHandler] bindings for type
+ // parameters from the redirecting constructor.
+
+ // For redirecting constructors, the fields will be initialized later by the
+ // effective target, so we don't do it here.
+
+ _inlineSuperOrRedirectCommon(initializer, superOrRedirectConstructor,
+ arguments, constructorChain, fieldValues, caller);
+ }
+
/// Inlines the given super [constructor]'s initializers by collecting its
/// field values and building its constructor initializers. We visit super
/// constructors all the way up to the [Object] constructor.
- void _buildInlinedInitializers(
+ void _inlineSuperInitializer(
+ ir.SuperInitializer initializer,
+ List<ir.Constructor> constructorChain,
+ Map<ir.Field, HInstruction> fieldValues,
+ ir.Constructor caller) {
+ var target = initializer.target;
+ var arguments =
+ _normalizeAndBuildArguments(target.function, initializer.arguments);
+
+ ir.Class callerClass = caller.enclosingClass;
+ _bindSupertypeTypeParameters(callerClass.supertype);
+ if (callerClass.mixedInType != null) {
+ _bindSupertypeTypeParameters(callerClass.mixedInType);
+ }
+
+ ir.Class cls = target.enclosingClass;
+
+ inlinedFrom(target, () {
+ fieldValues.addAll(_collectFieldValues(cls));
+ });
+
+ _inlineSuperOrRedirectCommon(
+ initializer, target, arguments, constructorChain, fieldValues, caller);
+ }
+
+ void _inlineSuperOrRedirectCommon(
+ ir.Initializer initializer,
ir.Constructor constructor,
List<HInstruction> arguments,
List<ir.Constructor> constructorChain,
- Map<ir.Field, HInstruction> fieldValues) {
- // TODO(het): Handle RTI if class needs it
- fieldValues.addAll(_collectFieldValues(constructor.enclosingClass));
-
+ Map<ir.Field, HInstruction> fieldValues,
+ ir.Constructor caller) {
var signature = astAdapter.getFunctionSignature(constructor.function);
var index = 0;
signature.orderedForEachParameter((ParameterElement parameter) {
@@ -454,14 +618,28 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
localsHandler.updateLocal(parameter, argument);
});
- // TODO(het): set the locals handler state as if we were inlining the
- // constructor.
- _buildInitializers(constructor, constructorChain, fieldValues);
+ // Set the locals handler state as if we were inlining the constructor.
+ astAdapter.pushResolvedAst(constructor);
+ ResolvedAst resolvedAst = astAdapter.getElement(constructor).resolvedAst;
+ ClosureClassMap oldClosureData = localsHandler.closureData;
+ ClosureClassMap newClosureData =
+ compiler.closureToClassMapper.getClosureToClassMapping(resolvedAst);
+ localsHandler.closureData = newClosureData;
+ if (resolvedAst.kind == ResolvedAstKind.PARSED) {
+ localsHandler.enterScope(
+ resolvedAst.node, astAdapter.getElement(constructor));
+ }
+ inlinedFrom(constructor, () {
+ _buildInitializers(constructor, constructorChain, fieldValues);
+ });
+ localsHandler.closureData = oldClosureData;
+ astAdapter.popResolvedAstStack();
}
/// Builds generative constructor body.
void buildConstructorBody(ir.Constructor constructor) {
openFunction();
+ _addClassTypeVariablesIfNeeded(constructor);
constructor.function.body.accept(this);
closeFunction();
}
@@ -547,22 +725,25 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
// TODO(sra): Re-implement type builder using Kernel types and the
// `target` for context.
@override
- Element get sourceElement => _sourceElementForTarget(target);
+ Element get sourceElement => _sourceElementForTarget(_targetStack.last);
+
+ List<ir.Node> _targetStack = <ir.Node>[];
Element _sourceElementForTarget(ir.Node target) {
// For closure-converted (i.e. local functions) the source element is the
// 'call' method of the class that represents the closure.
- if (target is ir.FunctionExpression) {
+ Element callMethodOfClosureClass() {
LocalFunctionElement element = astAdapter.getElement(target);
ClosureClassMap classMap =
closureToClassMapper.getClosureToClassMapping(element.resolvedAst);
return classMap.callElement;
}
+
+ if (target is ir.FunctionExpression) {
+ return callMethodOfClosureClass();
+ }
if (target is ir.FunctionDeclaration) {
- LocalFunctionElement element = astAdapter.getElement(target);
- ClosureClassMap classMap =
- closureToClassMapper.getClosureToClassMapping(element.resolvedAst);
- return classMap.callElement;
+ return callMethodOfClosureClass();
}
Element element = astAdapter.getElement(target);
return element;
@@ -2020,36 +2201,44 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
values.add(_defaultValueForParameter(parameter));
}
- if (arguments.named.isEmpty) return values;
-
- var namedValues = <String, HInstruction>{};
- for (ir.NamedExpression argument in arguments.named) {
- argument.value.accept(this);
- namedValues[argument.name] = pop();
- }
+ if (arguments.named.isNotEmpty) {
+ var namedValues = <String, HInstruction>{};
+ for (ir.NamedExpression argument in arguments.named) {
+ argument.value.accept(this);
+ namedValues[argument.name] = pop();
+ }
- // Visit named arguments in parameter-position order, selecting provided or
- // default value.
- // TODO(sra): Ensure the stored order is canonical so we don't have to
- // sort. The old builder uses CallStructure.makeArgumentList which depends
- // on the old element model.
- var namedParameters = target.namedParameters.toList()
- ..sort((ir.VariableDeclaration a, ir.VariableDeclaration b) =>
- a.name.compareTo(b.name));
- for (ir.VariableDeclaration parameter in namedParameters) {
- HInstruction value = namedValues[parameter.name];
- if (value == null) {
- values.add(_defaultValueForParameter(parameter));
- } else {
- values.add(value);
- namedValues.remove(parameter.name);
+ // Visit named arguments in parameter-position order, selecting provided
+ // or default value.
+ // TODO(sra): Ensure the stored order is canonical so we don't have to
+ // sort. The old builder uses CallStructure.makeArgumentList which depends
+ // on the old element model.
+ var namedParameters = target.namedParameters.toList()
+ ..sort((ir.VariableDeclaration a, ir.VariableDeclaration b) =>
+ a.name.compareTo(b.name));
+ for (ir.VariableDeclaration parameter in namedParameters) {
+ HInstruction value = namedValues[parameter.name];
+ if (value == null) {
+ values.add(_defaultValueForParameter(parameter));
+ } else {
+ values.add(value);
+ namedValues.remove(parameter.name);
+ }
}
+ assert(namedValues.isEmpty);
}
- assert(namedValues.isEmpty);
return values;
}
+ void _addTypeArguments(List<HInstruction> values, ir.Arguments arguments) {
+ // need to translate type to
+ for (ir.DartType type in arguments.types) {
+ values.add(typeBuilder.analyzeTypeArgument(
+ astAdapter.getDartType(type), sourceElement));
+ }
+ }
+
HInstruction _defaultValueForParameter(ir.VariableDeclaration parameter) {
ir.Expression initializer = parameter.initializer;
if (initializer == null) return graph.addConstantNull(closedWorld);
@@ -2074,6 +2263,15 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
List<HInstruction> arguments =
_visitArgumentsForStaticTarget(target.function, invocation.arguments);
+ // Factory constructors take type parameters; other static methods ignore
+ // them.
+ if (target.kind == ir.ProcedureKind.Factory) {
+ if (backend.rtiNeed
+ .classNeedsRti(astAdapter.getClass(target.enclosingClass))) {
+ _addTypeArguments(arguments, invocation.arguments);
+ }
+ }
+
_pushStaticInvocation(target, arguments, typeMask);
}
@@ -2786,6 +2984,10 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
// TODO(sra): For JS-interop targets, process arguments differently.
List<HInstruction> arguments =
_visitArgumentsForStaticTarget(target.function, invocation.arguments);
+ if (backend.rtiNeed
+ .classNeedsRti(astAdapter.getClass(target.enclosingClass))) {
+ _addTypeArguments(arguments, invocation.arguments);
+ }
TypeMask typeMask = new TypeMask.nonNullExact(
astAdapter.getClass(target.enclosingClass), closedWorld);
_pushStaticInvocation(target, arguments, typeMask);
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698