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

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: Address comments. 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
« no previous file with comments | « frog/leg/resolver.dart ('k') | frog/leg/ssa/closure.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: frog/leg/ssa/builder.dart
diff --git a/frog/leg/ssa/builder.dart b/frog/leg/ssa/builder.dart
index 354c55fd0718c6242b7711f1f79d72d667f0b6e1..36daffa3037633c2b6bb598ab6054e25b4a6b937 100644
--- a/frog/leg/ssa/builder.dart
+++ b/frog/leg/ssa/builder.dart
@@ -128,32 +128,8 @@ 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);
}
}
@@ -421,7 +397,7 @@ class LocalsHandler {
class SsaBuilder implements Visitor {
final Compiler compiler;
- final TreeElements elements;
+ TreeElements elements;
final Interceptors interceptors;
final WorkItem work;
bool methodInterceptionEnabled;
@@ -463,66 +439,182 @@ 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) {
+ bodyElement = backendMember;
+ break;
+ }
+ }
+ }
+ if (bodyElement === null) {
+ bodyElement = new ConstructorBodyElement(constructor);
+ TreeElements treeElements =
+ compiler.resolver.resolveMethodElement(bodyElement);
+ compiler.enqueue(new WorkItem.toCodegen(bodyElement, treeElements));
+ classElement.backendMembers =
+ classElement.backendMembers.prepend(bodyElement);
+ }
+ assert(bodyElement.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY);
+ return bodyElement;
+ }
+
+ /**
+ * Call [f] for every argument and parameter element of [target]
+ * that is used in the invocation [send].
+ */
+ forEachArgument(Send send, FunctionElement target,
+ f(VariableElement parameter, Node argument)) {
+ 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;
+ }
+ f(parameterElements.head, arguments.head);
+ parameterElements = parameterElements.tail;
+ };
+ }
+
+ /**
+ * Run through the initializers and inline all field initializers. Returns the
+ * next constructor to analyze.
+ */
+ FunctionElement analyzeInitializers(Link<Node> initializers) {
+ FunctionElement nextConstructor;
+ for (Link<Node> link = initializers; !link.isEmpty(); link = link.tail) {
+ assert(link.head is Send);
+ if (link.head is !SendSet) {
+ // A super initializer or constructor redirection.
+ Send call = link.head;
+ if (Initializers.isSuperConstructorCall(call)) {
+ assert(nextConstructor === null);
+ nextConstructor = elements[call];
+ // Visit arguments and map the corresponding parameter value to
+ // the resulting HInstruction value.
+ forEachArgument(call, nextConstructor, (parameter, node) {
+ visit(node);
+ HInstruction value = pop();
+ localsHandler.updateLocal(parameter, value);
+ });
+ } 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());
+ visit(arguments.head);
+ // We treat the init field-elements like locals. In the context of
+ // the factory this is correct, and simplifies dealing with
+ // parameter-initializers (like A(this.x)).
+ localsHandler.updateLocal(elements[init], pop());
+ }
+ }
+ return nextConstructor;
+ }
+
+ /**
+ * Build the factory function corresponding to the constructor
+ * [functionElement]:
+ * - 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) {
- for (Link<Node> link = initializers.nodes;
- !link.isEmpty();
- link = link.tail) {
- assert(link.head is Send);
- if (link.head is !SendSet) {
- compiler.unimplemented('SsaBuilder.buildFactory super-init');
- } else {
- SendSet init = link.head;
- Link<Node> arguments = init.arguments;
- assert(!arguments.isEmpty() && arguments.tail.isEmpty());
- visit(arguments.head);
- // We treat the init field-elements like locals. In the context of
- // the factory this is correct, and simplifies dealing with
- // parameter-initializers (like A(this.x)).
- localsHandler.updateLocal(elements[init], pop());
+ final Map<FunctionElement, TreeElements> constructorElements =
+ compiler.resolver.constructorElements;
ngeoffray 2012/02/09 08:25:51 This variable is unused.
+ List<FunctionElement> constructors = new List<FunctionElement>();
+
+ // Analyze the constructor and all referenced constructors and collect
+ // initializers and constructor bodies.
+ FunctionElement nextConstructor = functionElement;
+ while (nextConstructor != null) {
+ FunctionElement constructor = nextConstructor;
+ constructors.addLast(constructor);
+ nextConstructor = null;
+ elements = compiler.resolver.resolveMethodElement(constructor);
+ FunctionExpression functionNode = constructor.parseNode(compiler);
+ Link<Node> initializers = const EmptyLink<Node>();
+ if (functionNode.initializers !== null) {
+ nextConstructor = analyzeInitializers(functionNode.initializers.nodes);
+ }
+ if (nextConstructor === null) {
+ // No super initializer found. Try to find the default constructor if
+ // the class is not Object.
+ ClassElement enclosingClass = constructor.enclosingElement;
+ ClassElement superClass = enclosingClass.superclass;
+ if (enclosingClass.name != Types.OBJECT) {
floitsch 2012/02/08 15:30:27 use: compiler.coreLibrary.find(const SourceString
karlklose 2012/02/08 17:20:44 Done.
+ assert(superClass !== null);
+ assert(superClass.isResolved);
+ nextConstructor = superClass.lookupConstructor(superClass.name);
+ if (nextConstructor === null &&
+ superClass.canHaveDefaultConstructor()) {
+ nextConstructor = superClass.getSynthesizedConstructor();
+ } else if (nextConstructor === null) {
+ compiler.internalError("no default constructor available");
+ }
}
}
}
ngeoffray 2012/02/09 08:27:03 I would put 'elements' to null here, to make sure
-
// Call the JavaScript constructor with the fields as argument.
- // TODO(floitsch): allow super calls.
- // TODO(floitsch): allow inits at field declarations.
+ // TODO(floitsch,karlklose): move this code to ClassElement and share with
+ // the emitter.
List<HInstruction> constructorArguments = <HInstruction>[];
- for (Element member in classElement.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);
+ ClassElement element = classElement;
+ while (element != null) {
+ for (Element member in element.members) {
+ if (member.isInstanceMember() && member.kind == ElementKind.FIELD) {
+ HInstruction value;
+ if (localsHandler.hasValueForDirectLocal(member)) {
+ value = localsHandler.readLocal(member);
+ } else {
+ // TODO(karlklose): get default value.
+ value = new HLiteral(null, HType.UNKNOWN);
+ add(value);
+ }
+ constructorArguments.add(value);
}
- constructorArguments.add(value);
}
+ 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];
+ ConstructorBodyElement body = this.getConstructorBody(classElement,
+ constructor);
+ List bodyCallInputs = <HInstruction>[];
+ bodyCallInputs.add(newObject);
+ body.functionParameters.forEachParameter((parameter) {
ngeoffray 2012/02/09 08:25:51 To be safe, should that be body.computeParameters(
+ bodyCallInputs.add(localsHandler.readLocal(parameter));
+ });
+ SourceString methodName = body.name;
+ add(new HInvokeDynamicMethod(null, methodName, bodyCallInputs));
+ }
close(new HReturn(newObject)).addSuccessor(graph.exit);
return closeFunction();
}
« no previous file with comments | « frog/leg/resolver.dart ('k') | frog/leg/ssa/closure.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698