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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 class Interceptors { 5 class Interceptors {
6 Compiler compiler; 6 Compiler compiler;
7 Interceptors(Compiler this.compiler); 7 Interceptors(Compiler this.compiler);
8 8
9 SourceString mapOperatorToMethodName(Operator op) { 9 SourceString mapOperatorToMethodName(Operator op) {
10 String name = op.source.stringValue; 10 String name = op.source.stringValue;
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 } 122 }
123 new HTracer.singleton().traceCompilation(name); 123 new HTracer.singleton().traceCompilation(name);
124 new HTracer.singleton().traceGraph('builder', graph); 124 new HTracer.singleton().traceGraph('builder', graph);
125 } 125 }
126 return graph; 126 return graph;
127 }); 127 });
128 } 128 }
129 129
130 HGraph compileConstructor(SsaBuilder builder, WorkItem work) { 130 HGraph compileConstructor(SsaBuilder builder, WorkItem work) {
131 // The body of the constructor will be generated in a separate function. 131 // The body of the constructor will be generated in a separate function.
132 ClassElement classElement = work.element.enclosingElement; 132 final ClassElement classElement = work.element.enclosingElement;
133 ConstructorBodyElement bodyElement; 133 return builder.buildFactory(classElement, work.element);
134 // In case of a bailout version, the constructor body has already 134 }
135 // been created. 135
136 if (work.isBailoutVersion()) { 136 HGraph compileConstructorBody(SsaBuilder builder,
floitsch 2012/02/07 17:19:37 remove this method.
karlklose 2012/02/08 14:12:00 Done.
137 for (Link<Element> backendMembers = classElement.backendMembers; 137 FunctionElement element,
138 !backendMembers.isEmpty(); 138 TreeElements elements) {
139 backendMembers = backendMembers.tail) { 139 return builder.buildMethod(element);
140 Element current = backendMembers.head; 140 }
141 if (current.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { 141
142 ConstructorBodyElement temp = current; 142 HGraph compileMethod(SsaBuilder builder,
floitsch 2012/02/07 17:19:38 ditto.
karlklose 2012/02/08 14:12:00 Done.
143 if (temp.constructor == work.element) { 143 FunctionElement element,
144 bodyElement = temp; 144 TreeElements elements) {
145 break; 145 return builder.buildMethod(element);
146 }
147 }
148 }
149 } else {
150 bodyElement = new ConstructorBodyElement(work.element);
151 compiler.enqueue(
152 new WorkItem.toCodegen(bodyElement, work.resolutionTree));
153 classElement.backendMembers =
154 classElement.backendMembers.prepend(bodyElement);
155 }
156 // TODO(floitsch): pass initializer-list to builder.
157 return builder.buildFactory(classElement, bodyElement, work.element);
158 } 146 }
159 } 147 }
160 148
161 /** 149 /**
162 * Keeps track of locals (including parameters and phis) when building. The 150 * Keeps track of locals (including parameters and phis) when building. The
163 * 'this' reference is treated as parameter and hence handled by this class, 151 * 'this' reference is treated as parameter and hence handled by this class,
164 * too. 152 * too.
165 */ 153 */
166 class LocalsHandler { 154 class LocalsHandler {
167 // The values of locals that can be directly accessed (without redirections 155 // The values of locals that can be directly accessed (without redirections
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after
404 joinBlock.addPhi(phi); 392 joinBlock.addPhi(phi);
405 joinedLocals[element] = phi; 393 joinedLocals[element] = phi;
406 } 394 }
407 }); 395 });
408 directLocals = joinedLocals; 396 directLocals = joinedLocals;
409 } 397 }
410 } 398 }
411 399
412 class SsaBuilder implements Visitor { 400 class SsaBuilder implements Visitor {
413 final Compiler compiler; 401 final Compiler compiler;
414 final TreeElements elements; 402 TreeElements elements;
415 final Interceptors interceptors; 403 final Interceptors interceptors;
416 bool methodInterceptionEnabled; 404 bool methodInterceptionEnabled;
417 HGraph graph; 405 HGraph graph;
418 LocalsHandler localsHandler; 406 LocalsHandler localsHandler;
419 407
420 // We build the Ssa graph by simulating a stack machine. 408 // We build the Ssa graph by simulating a stack machine.
421 List<HInstruction> stack; 409 List<HInstruction> stack;
422 410
423 // The current block to add instructions to. Might be null, if we are 411 // The current block to add instructions to. Might be null, if we are
424 // visiting dead code. 412 // visiting dead code.
(...skipping 18 matching lines...) Expand all
443 methodInterceptionEnabled = true; 431 methodInterceptionEnabled = true;
444 } 432 }
445 433
446 HGraph buildMethod(FunctionElement functionElement) { 434 HGraph buildMethod(FunctionElement functionElement) {
447 FunctionExpression function = functionElement.parseNode(compiler); 435 FunctionExpression function = functionElement.parseNode(compiler);
448 openFunction(functionElement, function); 436 openFunction(functionElement, function);
449 function.body.accept(this); 437 function.body.accept(this);
450 return closeFunction(); 438 return closeFunction();
451 } 439 }
452 440
441 /**
442 * Returns the constructor body associated with the given constructor or
443 * creates a new constructor body, if none can be found.
444 */
445 ConstructorBodyElement getConstructorBody(ClassElement classElement,
446 FunctionElement constructor) {
447 assert(constructor.kind === ElementKind.GENERATIVE_CONSTRUCTOR);
448 ConstructorBodyElement bodyElement;
449 for (Link<Element> backendMembers = classElement.backendMembers;
450 !backendMembers.isEmpty();
451 backendMembers = backendMembers.tail) {
452 Element backendMember = backendMembers.head;
453 if (backendMember.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY) {
454 ConstructorBodyElement body = backendMember;
455 if (body.constructor== constructor) {
ngeoffray 2012/02/07 14:25:59 space missing before '=='
karlklose 2012/02/08 14:12:00 Done.
456 bodyElement = backendMember;
457 break;
458 }
459 }
460 }
461 if (bodyElement === null) {
462 bodyElement = new ConstructorBodyElement(constructor);
463 compiler.enqueue(
floitsch 2012/02/07 17:19:38 one line?
karlklose 2012/02/08 14:12:00 Done.
464 new WorkItem.toCompile(bodyElement));
465 classElement.backendMembers =
466 classElement.backendMembers.prepend(bodyElement);
467 }
468 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.
469 bodyElement.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY);
470 return bodyElement;
471 }
472
473 /**
474 * 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
475 * that is used in the invocation [send].
476 */
477 forEachArgument(Send send, FunctionElement target,
478 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.
479 final FunctionParameters parameters = target.computeParameters(compiler);
480 Link<Element> parameterElements = parameters.requiredParameters;
481 for (Link<Node> arguments = send.arguments;
482 !arguments.isEmpty();
483 arguments = arguments.tail) {
484 if (parameterElements.isEmpty()) {
485 parameterElements = parameters.optionalParameters;
486 }
487 forEach(parameterElements.head, arguments.head);
488 parameterElements = parameterElements.tail;
489 };
490 }
491
492 /**
493 * 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.
494 * - Initialize fields with the values of the field initializers of the
495 * current constructor and super constructors or constructors redirected
496 * to, starting from the current constructor.
497 * - Call the the constructor bodies, starting from the constructor(s) in the
498 * super class(es).
499 */
453 HGraph buildFactory(ClassElement classElement, 500 HGraph buildFactory(ClassElement classElement,
454 ConstructorBodyElement bodyElement,
455 FunctionElement functionElement) { 501 FunctionElement functionElement) {
456 FunctionExpression function = functionElement.parseNode(compiler); 502 FunctionExpression function = functionElement.parseNode(compiler);
457 // The initializer list could contain closures. 503 // The initializer list could contain closures.
458 openFunction(functionElement, function); 504 openFunction(functionElement, function);
459 505
460 NodeList initializers = function.initializers; 506 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
507 compiler.resolver.constructorElements;
508 List<FunctionElement> constructors = new List<FunctionElement>();
509 Map<FunctionElement, List<HInstruction>> environments =
510 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.
461 511
462 // Run through the initializers. 512 // Prepare initial environment used to call body of this constructor.
463 if (initializers !== null) { 513 FunctionElement next = functionElement;
ngeoffray 2012/02/07 14:25:59 next -> nextSuperCall ?
karlklose 2012/02/08 14:12:00 Changed to nextConstructor.
514 List<HInstruction> initialEnvironment = new List<HInstruction>();
515 functionElement.functionParameters.forEachParameter((parameter) {
516 initialEnvironment.addLast(localsHandler.readLocal(parameter));
517 });
ngeoffray 2012/02/07 14:25:59 strange indentation.
karlklose 2012/02/08 14:12:00 Removed.
518 environments[functionElement] = initialEnvironment;
519 constructors.addLast(functionElement);
520
521 // Analyze the constructor and all referenced constructors and collect
522 // initializers and constructor bodies.
523 while (next != null) {
524 final FunctionElement constructor = next;
525 next = null;
526 elements = compiler.resolver.resolveMethodElement(constructor);
527 compiler.enqueue(new WorkItem.toCompile(constructor));
floitsch 2012/02/07 17:19:38 remove enqueuing here.
karlklose 2012/02/08 14:12:00 Done.
528 final FunctionExpression functionNode = constructor.parseNode(compiler);
529 final NodeList initializers = functionNode.initializers;
530
531 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.
532
533 // Run through the initializers. Collect all field initializers and
534 // 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.
464 for (Link<Node> link = initializers.nodes; 535 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.
465 !link.isEmpty(); 536 !link.isEmpty();
466 link = link.tail) { 537 link = link.tail) {
467 assert(link.head is Send); 538 assert(link.head is Send);
539
468 if (link.head is !SendSet) { 540 if (link.head is !SendSet) {
469 compiler.unimplemented('SsaBuilder.buildFactory super-init'); 541 Send call = link.head;
542 // 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.
543 if (Initializers.isSuperConstructorCall(link.head)) {
floitsch 2012/02/07 17:19:38 s/link.head/call
karlklose 2012/02/08 14:12:00 Done.
544 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.
545 FunctionExpression superNode = superconstructor.parseNode(compiler);
ngeoffray 2012/02/07 14:25:59 Unused variable.
karlklose 2012/02/08 14:12:00 Done.
546 List<HInstruction> environment = new List<HInstruction>();
547 Link<Element> argumentElements =
548 superconstructor.functionParameters.requiredParameters;
ngeoffray 2012/02/07 14:25:59 This variable seems unnecessary.
karlklose 2012/02/08 14:12:00 Done.
549 // Visit arguments and map the corresponding parameter value to
550 // the resulting HInstruction value.
551 forEachArgument(call, superconstructor, (parameter, node) {
552 visit(node);
553 HInstruction value = pop();
554 updateElementDefinition(parameter, value);
555 // Store environment for invocation of constructor body.
556 environment.addLast(value);
557 argumentElements = argumentElements.tail;
558 });
559 // Setup constructor and environment for later and process it next.
560 constructors.addLast(superconstructor);
561 environments[superconstructor] = environment;
562 next = superconstructor;
563 } else {
564 compiler.unimplemented('SsaBuilder.buildFactory redirect');
565 }
470 } else { 566 } else {
567 // A field initializer.
471 SendSet init = link.head; 568 SendSet init = link.head;
472 Link<Node> arguments = init.arguments; 569 Link<Node> arguments = init.arguments;
473 assert(!arguments.isEmpty() && arguments.tail.isEmpty()); 570 assert(!arguments.isEmpty() && arguments.tail.isEmpty());
474 visit(arguments.head); 571 visit(arguments.head);
475 // We treat the init field-elements like locals. In the context of 572 // We treat the init field-elements like locals. In the context of
476 // the factory this is correct, and simplifies dealing with 573 // the factory this is correct, and simplifies dealing with
477 // parameter-initializers (like A(this.x)). 574 // parameter-initializers (like A(this.x)).
478 localsHandler.updateLocal(elements[init], pop()); 575 localsHandler.updateLocal(elements[init], pop());
479 } 576 }
480 } 577 }
481 } 578 }
482
483 // Call the JavaScript constructor with the fields as argument. 579 // Call the JavaScript constructor with the fields as argument.
484 // TODO(floitsch): allow super calls.
485 // TODO(floitsch): allow inits at field declarations.
486 List<HInstruction> constructorArguments = <HInstruction>[]; 580 List<HInstruction> constructorArguments = <HInstruction>[];
487 for (Element member in classElement.members) { 581 ClassElement element = classElement;
488 if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { 582 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.
583 for (Element member in element.members) {
584 if (member.isInstanceMember() && member.kind == ElementKind.FIELD) {
489 HInstruction value; 585 HInstruction value;
490 if (localsHandler.hasValueForDirectLocal(member)) { 586 if (localsHandler.hasValueForDirectLocal(member)) {
491 value = localsHandler.readLocal(member); 587 value = localsHandler.readLocal(member);
492 } else { 588 } else {
493 value = new HLiteral(null, HType.UNKNOWN); 589 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.
494 add(value); 590 add(value);
591 }
592 constructorArguments.add(value);
ngeoffray 2012/02/07 14:25:59 strange indentation.
karlklose 2012/02/08 14:12:00 Done.
495 } 593 }
496 constructorArguments.add(value);
497 } 594 }
595 element = element.superclass;
498 } 596 }
499 HForeignNew newObject = new HForeignNew(classElement, constructorArguments); 597 HForeignNew newObject = new HForeignNew(classElement, constructorArguments);
500 add(newObject); 598 add(newObject);
501 599 // Generate calls to the constructor bodies.
502 // Call the method body. 600 for (int index = constructors.length - 1; index >= 0; index--) {
503 SourceString methodName = bodyElement.name; 601 FunctionElement constructor = constructors[index];
504 602 List bodyCallInputs = <HInstruction>[];
505 List bodyCallInputs = <HInstruction>[]; 603 bodyCallInputs.add(newObject);
506 bodyCallInputs.add(newObject); 604 int argumentCount = 0;
507 FunctionParameters parameters = functionElement.computeParameters(compiler); 605 List<HInstruction> environment = environments[constructor];
508 parameters.forEachParameter((Element parameterElement) { 606 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.
509 HInstruction currentValue = localsHandler.readLocal(parameterElement); 607 bodyCallInputs.add(value);
510 bodyCallInputs.add(currentValue); 608 argumentCount++;
511 }); 609 }
512 add(new HInvokeDynamicMethod(null, methodName, bodyCallInputs)); 610 Selector selector = new Invocation(argumentCount);
611 ConstructorBodyElement body = this.getConstructorBody(classElement,
612 constructor);
613 // Call the method body.
614 SourceString methodName = body.name;
615 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.
616 }
513 close(new HReturn(newObject)).addSuccessor(graph.exit); 617 close(new HReturn(newObject)).addSuccessor(graph.exit);
514 return closeFunction(); 618 return closeFunction();
515 } 619 }
516 620
517 void openFunction(FunctionElement functionElement, 621 void openFunction(FunctionElement functionElement,
518 FunctionExpression node) { 622 FunctionExpression node) {
519 HBasicBlock block = graph.addNewBlock(); 623 HBasicBlock block = graph.addNewBlock();
520 open(graph.entry); 624 open(graph.entry);
521 625
522 localsHandler.startFunction(functionElement, node); 626 localsHandler.startFunction(functionElement, node);
(...skipping 838 matching lines...) Expand 10 before | Expand all | Expand 10 after
1361 // static call to a factory. 1465 // static call to a factory.
1362 visitStaticSend(node); 1466 visitStaticSend(node);
1363 } else { 1467 } else {
1364 compiler.internalError("Cannot generate code for send", node: node); 1468 compiler.internalError("Cannot generate code for send", node: node);
1365 } 1469 }
1366 } 1470 }
1367 } 1471 }
1368 1472
1369 visitNewExpression(NewExpression node) => visitSend(node.send); 1473 visitNewExpression(NewExpression node) => visitSend(node.send);
1370 1474
1475 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.
1476 localsHandler.updateLocal(element, value);
1477 return value;
1478 }
1479
1371 visitSendSet(SendSet node) { 1480 visitSendSet(SendSet node) {
1372 Operator op = node.assignmentOperator; 1481 Operator op = node.assignmentOperator;
1373 if (node.isIndex) { 1482 if (node.isIndex) {
1374 if (!methodInterceptionEnabled) { 1483 if (!methodInterceptionEnabled) {
1375 assert(op.source.stringValue === '='); 1484 assert(op.source.stringValue === '=');
1376 visitDynamicSend(node); 1485 visitDynamicSend(node);
1377 } else { 1486 } else {
1378 HStatic target = new HStatic( 1487 HStatic target = new HStatic(
1379 interceptors.getIndexAssignmentInterceptor()); 1488 interceptors.getIndexAssignmentInterceptor());
1380 add(target); 1489 add(target);
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
1711 } 1820 }
1712 1821
1713 visitCatchBlock(CatchBlock node) { 1822 visitCatchBlock(CatchBlock node) {
1714 compiler.unimplemented('SsaBuilder.visitCatchBlock', node: node); 1823 compiler.unimplemented('SsaBuilder.visitCatchBlock', node: node);
1715 } 1824 }
1716 1825
1717 visitTypedef(Typedef node) { 1826 visitTypedef(Typedef node) {
1718 compiler.unimplemented('SsaBuilder.visitTypedef', node: node); 1827 compiler.unimplemented('SsaBuilder.visitTypedef', node: node);
1719 } 1828 }
1720 } 1829 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698