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

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

Issue 2498493003: kernel->ssa: get simple constructors working (Closed)
Patch Set: respond to comments Created 4 years, 1 month 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 | « pkg/compiler/lib/src/ssa/builder.dart ('k') | 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 510815a424e88b96d68f91c936709882ddb80546..6a5ee2c5238237761ab0cfd6ee5b5d8cedddf340 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -16,6 +16,7 @@ import '../js_backend/backend.dart' show JavaScriptBackend;
import '../kernel/kernel.dart';
import '../resolution/tree_elements.dart';
import '../tree/dartstring.dart';
+import '../tree/nodes.dart' show FunctionExpression, Node;
import '../types/masks.dart';
import '../universe/call_structure.dart' show CallStructure;
import '../universe/selector.dart';
@@ -139,14 +140,170 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
return result;
}
+ /// Builds generative constructors.
+ ///
+ /// Generative constructors are built in two stages.
+ ///
+ /// 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.
void buildConstructor(ir.Constructor constructor) {
- // TODO(het): Actually handle this correctly
- HBasicBlock block = graph.addNewBlock();
- open(graph.entry);
- close(new HGoto()).addSuccessor(block);
- open(block);
- closeAndGotoExit(new HGoto());
- graph.finalize();
+ openFunction();
+
+ // 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);
+
+ _buildInitializers(constructor, fieldValues);
+
+ final constructorArguments = <HInstruction>[];
+ astAdapter.getClass(constructor.enclosingClass).forEachInstanceField(
+ (ClassElement enclosingClass, FieldElement member) {
+ var value = fieldValues[astAdapter.getFieldFromElement(member)];
+ constructorArguments.add(value);
+ }, includeSuperAndInjectedMembers: true);
+
+ // TODO(het): If the class needs runtime type information, add it as a
+ // constructor argument.
+ HInstruction create = new HCreate(
+ astAdapter.getClass(constructor.enclosingClass),
+ constructorArguments,
+ new TypeMask.nonNullExact(
+ astAdapter.getClass(constructor.enclosingClass),
+ compiler.closedWorld),
+ instantiatedTypes: <DartType>[
+ astAdapter.getClass(constructor.enclosingClass).thisType
+ ],
+ hasRtiInput: false);
+
+ add(create);
+
+ // Generate calls to the constructor bodies.
+
+ closeAndGotoExit(new HReturn(create, null));
+ closeFunction();
+ }
+
+ /// Maps the fields of a class to their SSA values.
+ Map<ir.Field, HInstruction> _collectFieldValues(ir.Class clazz) {
+ final fieldValues = <ir.Field, HInstruction>{};
+
+ for (var field in clazz.fields) {
+ if (field.initializer == null) {
+ fieldValues[field] = graph.addConstantNull(compiler);
+ } else {
+ field.initializer.accept(this);
+ fieldValues[field] = pop();
+ }
+ }
+
+ return fieldValues;
+ }
+
+ /// Collects field initializers all the way up the inheritance chain.
+ void _buildInitializers(
+ ir.Constructor constructor, Map<ir.Field, HInstruction> fieldValues) {
+ var foundSuperCall = false;
+ for (var initializer in constructor.initializers) {
+ if (initializer is ir.SuperInitializer) {
+ foundSuperCall = true;
+ var superConstructor = initializer.target;
+ var arguments = _normalizeAndBuildArguments(
+ superConstructor.function, initializer.arguments);
+ _buildInlinedSuperInitializers(
+ superConstructor, arguments, fieldValues);
+ } else if (initializer is ir.FieldInitializer) {
+ initializer.value.accept(this);
+ fieldValues[initializer.field] = pop();
+ }
+ }
+
+ // TODO(het): does kernel always set the super initializer at the end?
+ // If there was no super-call initializer, then call the default constructor
+ // in the superclass.
+ if (!foundSuperCall) {
+ if (constructor.enclosingClass != astAdapter.objectClass) {
+ var superclass = constructor.enclosingClass.superclass;
+ var defaultConstructor = superclass.constructors
+ .firstWhere((c) => c.name == '', orElse: () => null);
+ if (defaultConstructor == null) {
+ compiler.reporter.internalError(
+ NO_LOCATION_SPANNABLE, 'Could not find default constructor.');
+ }
+ _buildInlinedSuperInitializers(
+ defaultConstructor, <HInstruction>[], fieldValues);
+ }
+ }
+ }
+
+ List<HInstruction> _normalizeAndBuildArguments(
+ ir.FunctionNode function, ir.Arguments arguments) {
+ var signature = astAdapter.getFunctionSignature(function);
+ var builtArguments = <HInstruction>[];
+ var positionalIndex = 0;
+ signature.forEachRequiredParameter((_) {
+ arguments.positional[positionalIndex++].accept(this);
+ builtArguments.add(pop());
+ });
+ if (!signature.optionalParametersAreNamed) {
+ signature.forEachOptionalParameter((ParameterElement element) {
+ if (positionalIndex < arguments.positional.length) {
+ arguments.positional[positionalIndex++].accept(this);
+ builtArguments.add(pop());
+ } else {
+ var constantValue =
+ backend.constants.getConstantValue(element.constant);
+ assert(invariant(element, constantValue != null,
+ message: 'No constant computed for $element'));
+ builtArguments.add(graph.addConstant(constantValue, compiler));
+ }
+ });
+ } else {
+ signature.orderedOptionalParameters.forEach((ParameterElement element) {
+ var correspondingNamed = arguments.named.firstWhere(
+ (named) => named.name == element.name,
+ orElse: () => null);
+ if (correspondingNamed != null) {
+ correspondingNamed.value.accept(this);
+ builtArguments.add(pop());
+ } else {
+ var constantValue =
+ backend.constants.getConstantValue(element.constant);
+ assert(invariant(element, constantValue != null,
+ message: 'No constant computed for $element'));
+ builtArguments.add(graph.addConstant(constantValue, compiler));
+ }
+ });
+ }
+
+ return builtArguments;
+ }
+
+ /// Inlines the given super [constructor]'s initializers by collecting it's
+ /// field values and building its constructor initializers. We visit super
+ /// constructors all the way up to the [Object] constructor.
+ void _buildInlinedSuperInitializers(ir.Constructor constructor,
+ List<HInstruction> arguments, Map<ir.Field, HInstruction> fieldValues) {
+ // TODO(het): Handle RTI if class needs it
+ fieldValues.addAll(_collectFieldValues(constructor.enclosingClass));
+
+ var signature = astAdapter.getFunctionSignature(constructor.function);
+ var index = 0;
+ signature.orderedForEachParameter((ParameterElement parameter) {
+ HInstruction argument = arguments[index++];
+ // Because we are inlining the initializer, we must update
+ // what was given as parameter. This will be used in case
+ // there is a parameter check expression in the initializer.
+ parameters[parameter] = argument;
+ localsHandler.updateLocal(parameter, argument);
+ });
+
+ // TODO(het): set the locals handler state as if we were inlining the
+ // constructor.
+ _buildInitializers(constructor, fieldValues);
}
HTypeConversion buildFunctionTypeConversion(
@@ -175,7 +332,12 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
void openFunction() {
HBasicBlock block = graph.addNewBlock();
open(graph.entry);
- localsHandler.startFunction(targetElement, resolvedAst.node);
+
+ Node function;
+ if (resolvedAst.kind == ResolvedAstKind.PARSED) {
+ function = resolvedAst.node;
+ }
+ localsHandler.startFunction(targetElement, function);
close(new HGoto()).addSuccessor(block);
open(block);
« no previous file with comments | « pkg/compiler/lib/src/ssa/builder.dart ('k') | pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698