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

Unified Diff: frog/leg/ssa/builder.dart

Issue 9327001: Implement super initializers. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebase and update test expectations. Created 8 years, 10 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
Index: frog/leg/ssa/builder.dart
diff --git a/frog/leg/ssa/builder.dart b/frog/leg/ssa/builder.dart
index 2b775977c74ef1969cb3798c52f6743c6ccb4fc6..e2503881d77568058d32add1a9efc2df44208d4a 100644
--- a/frog/leg/ssa/builder.dart
+++ b/frog/leg/ssa/builder.dart
@@ -129,32 +129,20 @@ class SsaBuilderTask extends CompilerTask {
HGraph compileConstructor(SsaBuilder builder, WorkItem work) {
// The body of the constructor will be generated in a separate function.
- ClassElement classElement = work.element.enclosingElement;
- ConstructorBodyElement bodyElement;
- // In case of a bailout version, the constructor body has already
- // been created.
- if (work.isBailoutVersion()) {
- for (Link<Element> backendMembers = classElement.backendMembers;
- !backendMembers.isEmpty();
- backendMembers = backendMembers.tail) {
- Element current = backendMembers.head;
- if (current.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY) {
- ConstructorBodyElement temp = current;
- if (temp.constructor == work.element) {
- bodyElement = temp;
- break;
- }
- }
- }
- } else {
- bodyElement = new ConstructorBodyElement(work.element);
- compiler.enqueue(
- new WorkItem.toCodegen(bodyElement, work.resolutionTree));
- classElement.backendMembers =
- classElement.backendMembers.prepend(bodyElement);
- }
- // TODO(floitsch): pass initializer-list to builder.
- return builder.buildFactory(classElement, bodyElement, work.element);
+ final ClassElement classElement = work.element.enclosingElement;
+ return builder.buildFactory(classElement, work.element);
+ }
+
+ HGraph compileConstructorBody(SsaBuilder builder,
floitsch 2012/02/07 17:19:37 remove this method.
karlklose 2012/02/08 14:12:00 Done.
+ FunctionElement element,
+ TreeElements elements) {
+ return builder.buildMethod(element);
+ }
+
+ HGraph compileMethod(SsaBuilder builder,
floitsch 2012/02/07 17:19:38 ditto.
karlklose 2012/02/08 14:12:00 Done.
+ FunctionElement element,
+ TreeElements elements) {
+ return builder.buildMethod(element);
}
}
@@ -411,7 +399,7 @@ class LocalsHandler {
class SsaBuilder implements Visitor {
final Compiler compiler;
- final TreeElements elements;
+ TreeElements elements;
final Interceptors interceptors;
bool methodInterceptionEnabled;
HGraph graph;
@@ -450,24 +438,133 @@ class SsaBuilder implements Visitor {
return closeFunction();
}
+ /**
+ * Returns the constructor body associated with the given constructor or
+ * creates a new constructor body, if none can be found.
+ */
+ ConstructorBodyElement getConstructorBody(ClassElement classElement,
+ FunctionElement constructor) {
+ assert(constructor.kind === ElementKind.GENERATIVE_CONSTRUCTOR);
+ ConstructorBodyElement bodyElement;
+ for (Link<Element> backendMembers = classElement.backendMembers;
+ !backendMembers.isEmpty();
+ backendMembers = backendMembers.tail) {
+ Element backendMember = backendMembers.head;
+ if (backendMember.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY) {
+ ConstructorBodyElement body = backendMember;
+ if (body.constructor== constructor) {
ngeoffray 2012/02/07 14:25:59 space missing before '=='
karlklose 2012/02/08 14:12:00 Done.
+ bodyElement = backendMember;
+ break;
+ }
+ }
+ }
+ if (bodyElement === null) {
+ bodyElement = new ConstructorBodyElement(constructor);
+ compiler.enqueue(
floitsch 2012/02/07 17:19:38 one line?
karlklose 2012/02/08 14:12:00 Done.
+ new WorkItem.toCompile(bodyElement));
+ classElement.backendMembers =
+ classElement.backendMembers.prepend(bodyElement);
+ }
+ assert(bodyElement !== null &&
floitsch 2012/02/07 17:19:38 bodyElement is trivially non null. I would remove
karlklose 2012/02/08 14:12:00 Done.
+ bodyElement.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY);
+ return bodyElement;
+ }
+
+ /**
+ * Call [forEach] for every argument and parameter and element of [target]
ngeoffray 2012/02/07 14:25:59 Shouldn't it just be 'argument'? If there are rema
karlklose 2012/02/08 14:12:00 Done. I do not use environments anymore, so addSta
+ * that is used in the invocation [send].
+ */
+ forEachArgument(Send send, FunctionElement target,
+ forEach(VariableElement parameter, Node argument)) {
floitsch 2012/02/07 17:19:38 please name to something else. Even 'f' would be b
karlklose 2012/02/08 14:12:00 Done.
+ final FunctionParameters parameters = target.computeParameters(compiler);
+ Link<Element> parameterElements = parameters.requiredParameters;
+ for (Link<Node> arguments = send.arguments;
+ !arguments.isEmpty();
+ arguments = arguments.tail) {
+ if (parameterElements.isEmpty()) {
+ parameterElements = parameters.optionalParameters;
+ }
+ forEach(parameterElements.head, arguments.head);
+ parameterElements = parameterElements.tail;
+ };
+ }
+
+ /**
+ * Build the factory function corresponding to the constructor [bodyElement]:
floitsch 2012/02/07 17:19:38 s/bodyElement/functionElement.
karlklose 2012/02/08 14:12:00 Done.
+ * - Initialize fields with the values of the field initializers of the
+ * current constructor and super constructors or constructors redirected
+ * to, starting from the current constructor.
+ * - Call the the constructor bodies, starting from the constructor(s) in the
+ * super class(es).
+ */
HGraph buildFactory(ClassElement classElement,
- ConstructorBodyElement bodyElement,
FunctionElement functionElement) {
FunctionExpression function = functionElement.parseNode(compiler);
// The initializer list could contain closures.
openFunction(functionElement, function);
- NodeList initializers = function.initializers;
-
- // Run through the initializers.
- if (initializers !== null) {
+ final Map<FunctionElement, TreeElements> constructorElements =
ngeoffray 2012/02/07 14:25:59 Why is this one final and not the others? For cons
karlklose 2012/02/08 14:12:00 Done, I removed unused variables and the environme
+ compiler.resolver.constructorElements;
+ List<FunctionElement> constructors = new List<FunctionElement>();
+ Map<FunctionElement, List<HInstruction>> environments =
+ new Map<FunctionElement, List<HInstruction>>();
ngeoffray 2012/02/07 14:25:59 If this method was a LinkedHashMap, would you need
karlklose 2012/02/08 14:12:00 see above.
+
+ // Prepare initial environment used to call body of this constructor.
+ FunctionElement next = functionElement;
ngeoffray 2012/02/07 14:25:59 next -> nextSuperCall ?
karlklose 2012/02/08 14:12:00 Changed to nextConstructor.
+ List<HInstruction> initialEnvironment = new List<HInstruction>();
+ functionElement.functionParameters.forEachParameter((parameter) {
+ initialEnvironment.addLast(localsHandler.readLocal(parameter));
+ });
ngeoffray 2012/02/07 14:25:59 strange indentation.
karlklose 2012/02/08 14:12:00 Removed.
+ environments[functionElement] = initialEnvironment;
+ constructors.addLast(functionElement);
+
+ // Analyze the constructor and all referenced constructors and collect
+ // initializers and constructor bodies.
+ while (next != null) {
+ final FunctionElement constructor = next;
+ next = null;
+ elements = compiler.resolver.resolveMethodElement(constructor);
+ compiler.enqueue(new WorkItem.toCompile(constructor));
floitsch 2012/02/07 17:19:38 remove enqueuing here.
karlklose 2012/02/08 14:12:00 Done.
+ final FunctionExpression functionNode = constructor.parseNode(compiler);
+ final NodeList initializers = functionNode.initializers;
+
+ if (initializers === null) continue;
ngeoffray 2012/02/07 14:25:59 break?
floitsch 2012/02/07 17:19:38 We have to find the implicit super-constructor ins
karlklose 2012/02/08 14:12:00 Done.
karlklose 2012/02/08 14:12:00 Changed to set initializers to an empty list.
+
+ // Run through the initializers. Collect all field initializers and
+ // analyze referenced superinitializers and constructor redirections.
ngeoffray 2012/02/07 14:25:59 Maybe add a function for the code running through
karlklose 2012/02/08 14:12:00 Done.
for (Link<Node> link = initializers.nodes;
floitsch 2012/02/07 17:19:38 once you evaluate the initializers with the curren
karlklose 2012/02/08 14:12:00 Done.
!link.isEmpty();
link = link.tail) {
assert(link.head is Send);
+
if (link.head is !SendSet) {
- compiler.unimplemented('SsaBuilder.buildFactory super-init');
+ Send call = link.head;
+ // A super initializer or constructor redirection.
floitsch 2012/02/07 17:19:38 move comment one line up.
karlklose 2012/02/08 14:12:00 Done.
+ if (Initializers.isSuperConstructorCall(link.head)) {
floitsch 2012/02/07 17:19:38 s/link.head/call
karlklose 2012/02/08 14:12:00 Done.
+ FunctionElement superconstructor = elements[link.head];
floitsch 2012/02/07 17:19:38 superConstructor and s/link.head/call.
karlklose 2012/02/08 14:12:00 Done.
+ FunctionExpression superNode = superconstructor.parseNode(compiler);
ngeoffray 2012/02/07 14:25:59 Unused variable.
karlklose 2012/02/08 14:12:00 Done.
+ List<HInstruction> environment = new List<HInstruction>();
+ Link<Element> argumentElements =
+ superconstructor.functionParameters.requiredParameters;
ngeoffray 2012/02/07 14:25:59 This variable seems unnecessary.
karlklose 2012/02/08 14:12:00 Done.
+ // Visit arguments and map the corresponding parameter value to
+ // the resulting HInstruction value.
+ forEachArgument(call, superconstructor, (parameter, node) {
+ visit(node);
+ HInstruction value = pop();
+ updateElementDefinition(parameter, value);
+ // Store environment for invocation of constructor body.
+ environment.addLast(value);
+ argumentElements = argumentElements.tail;
+ });
+ // Setup constructor and environment for later and process it next.
+ constructors.addLast(superconstructor);
+ environments[superconstructor] = environment;
+ next = superconstructor;
+ } else {
+ compiler.unimplemented('SsaBuilder.buildFactory redirect');
+ }
} else {
+ // A field initializer.
SendSet init = link.head;
Link<Node> arguments = init.arguments;
assert(!arguments.isEmpty() && arguments.tail.isEmpty());
@@ -479,37 +576,44 @@ class SsaBuilder implements Visitor {
}
}
}
-
// Call the JavaScript constructor with the fields as argument.
- // TODO(floitsch): allow super calls.
- // TODO(floitsch): allow inits at field declarations.
List<HInstruction> constructorArguments = <HInstruction>[];
- for (Element member in classElement.members) {
- if (member.isInstanceMember() && member.kind == ElementKind.FIELD) {
+ ClassElement element = classElement;
+ while (element != null) {
floitsch 2012/02/07 17:19:38 add TODO to share this code with the emitter. Ther
karlklose 2012/02/08 14:12:00 Done.
+ for (Element member in element.members) {
+ if (member.isInstanceMember() && member.kind == ElementKind.FIELD) {
HInstruction value;
if (localsHandler.hasValueForDirectLocal(member)) {
value = localsHandler.readLocal(member);
} else {
- value = new HLiteral(null, HType.UNKNOWN);
- add(value);
- }
+ value = new HLiteral(null, HType.UNKNOWN);
floitsch 2012/02/07 17:19:38 Add TODO that we need to get the default-values if
karlklose 2012/02/08 14:12:00 Done.
+ add(value);
+ }
constructorArguments.add(value);
ngeoffray 2012/02/07 14:25:59 strange indentation.
karlklose 2012/02/08 14:12:00 Done.
+ }
}
+ element = element.superclass;
}
HForeignNew newObject = new HForeignNew(classElement, constructorArguments);
add(newObject);
-
- // Call the method body.
- SourceString methodName = bodyElement.name;
-
- List bodyCallInputs = <HInstruction>[];
- bodyCallInputs.add(newObject);
- FunctionParameters parameters = functionElement.computeParameters(compiler);
- parameters.forEachParameter((Element parameterElement) {
- HInstruction currentValue = localsHandler.readLocal(parameterElement);
- bodyCallInputs.add(currentValue);
- });
- add(new HInvokeDynamicMethod(null, methodName, bodyCallInputs));
+ // Generate calls to the constructor bodies.
+ for (int index = constructors.length - 1; index >= 0; index--) {
+ FunctionElement constructor = constructors[index];
+ List bodyCallInputs = <HInstruction>[];
+ bodyCallInputs.add(newObject);
+ int argumentCount = 0;
+ List<HInstruction> environment = environments[constructor];
+ for (HInstruction value in environment) {
ngeoffray 2012/02/07 14:25:59 Instead of creating a new list and adding the inst
karlklose 2012/02/08 14:12:00 I removed the environments.
+ bodyCallInputs.add(value);
+ argumentCount++;
+ }
+ Selector selector = new Invocation(argumentCount);
+ ConstructorBodyElement body = this.getConstructorBody(classElement,
+ constructor);
+ // Call the method body.
+ SourceString methodName = body.name;
+ add(new HInvokeDynamicMethod(selector, methodName, bodyCallInputs));
ngeoffray 2012/02/07 14:25:59 I believe you don't need a selector for this HInvo
karlklose 2012/02/08 14:12:00 Removed.
+ }
close(new HReturn(newObject)).addSuccessor(graph.exit);
return closeFunction();
}
@@ -1368,6 +1472,11 @@ class SsaBuilder implements Visitor {
visitNewExpression(NewExpression node) => visitSend(node.send);
+ HInstruction updateElementDefinition(Element element, HInstruction value) {
ngeoffray 2012/02/07 14:25:59 Since this method is only used once, I would inlin
karlklose 2012/02/08 14:12:00 Done.
+ localsHandler.updateLocal(element, value);
+ return value;
+ }
+
visitSendSet(SendSet node) {
Operator op = node.assignmentOperator;
if (node.isIndex) {

Powered by Google App Engine
This is Rietveld 408576698