Chromium Code Reviews| 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 6183f3f0d4b94b20eba12d886b0df92944d3b88a..546eebc113ea1b24625a631aa6dc0b8c9c60abdf 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/selector.dart'; |
| import 'graph_builder.dart'; |
| @@ -127,14 +128,166 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder { |
| return result; |
| } |
| + /// Generative constructors are built in several stages. |
|
Siggi Cherem (dart-lang)
2016/11/14 18:22:25
dartdoc nit: Consider making the first comment a d
Harry Terkelsen
2016/11/14 23:23:40
oops :) when I started that comment I thought ther
|
| + /// |
| + /// 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 |
|
Siggi Cherem (dart-lang)
2016/11/14 18:22:25
good question for tomorrow :)?
Harry Terkelsen
2016/11/14 23:23:40
Acknowledged.
|
| + // 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.getFieldFromNode(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); |
|
Siggi Cherem (dart-lang)
2016/11/14 18:22:25
just checking - this might change when addressing
Harry Terkelsen
2016/11/14 23:23:40
yes
|
| + |
| + 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); |
| + _buildSuperConstructor(superConstructor, arguments, fieldValues); |
| + } else if (initializer is ir.FieldInitializer) { |
| + initializer.value.accept(this); |
| + fieldValues[initializer.field] = pop(); |
| + } |
| + } |
| + |
| + // If there was no super-call initializer, then call the default constructor |
| + // in the superclass. |
| + if (!foundSuperCall) { |
|
Siggi Cherem (dart-lang)
2016/11/14 18:22:25
I wonder if kernel injects this call always at the
Harry Terkelsen
2016/11/14 23:23:40
Done.
|
| + 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.'); |
| + } |
| + _buildSuperConstructor( |
| + 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; |
| + } |
| + |
| + /// Builds the given super [constructor] by collecting it's field values and |
| + /// building it's initializers. We build super constructors all the way up |
| + /// to the [Object] constructor. |
| + void _buildSuperConstructor(ir.Constructor constructor, |
|
Siggi Cherem (dart-lang)
2016/11/14 18:22:25
Consider renaming this to avoid giving the impress
Harry Terkelsen
2016/11/14 23:23:40
Done.
|
| + 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); |
| } |
| /// Builds a SSA graph for [procedure]. |
| @@ -147,7 +300,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); |