| 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);
|
|
|