Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 121 } | 121 } |
| 122 new HTracer.singleton().traceCompilation(name); | 122 new HTracer.singleton().traceCompilation(name); |
| 123 new HTracer.singleton().traceGraph('builder', graph); | 123 new HTracer.singleton().traceGraph('builder', graph); |
| 124 } | 124 } |
| 125 return graph; | 125 return graph; |
| 126 }); | 126 }); |
| 127 } | 127 } |
| 128 | 128 |
| 129 HGraph compileConstructor(SsaBuilder builder, WorkItem work) { | 129 HGraph compileConstructor(SsaBuilder builder, WorkItem work) { |
| 130 // The body of the constructor will be generated in a separate function. | 130 // The body of the constructor will be generated in a separate function. |
| 131 ClassElement classElement = work.element.enclosingElement; | 131 final ClassElement classElement = work.element.enclosingElement; |
| 132 ConstructorBodyElement bodyElement; | 132 return builder.buildFactory(classElement, work.element); |
| 133 // In case of a bailout version, the constructor body has already | |
| 134 // been created. | |
| 135 if (work.isBailoutVersion()) { | |
| 136 for (Link<Element> backendMembers = classElement.backendMembers; | |
| 137 !backendMembers.isEmpty(); | |
| 138 backendMembers = backendMembers.tail) { | |
| 139 Element current = backendMembers.head; | |
| 140 if (current.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { | |
| 141 ConstructorBodyElement temp = current; | |
| 142 if (temp.constructor == work.element) { | |
| 143 bodyElement = temp; | |
| 144 break; | |
| 145 } | |
| 146 } | |
| 147 } | |
| 148 } else { | |
| 149 bodyElement = new ConstructorBodyElement(work.element); | |
| 150 compiler.enqueue( | |
| 151 new WorkItem.toCodegen(bodyElement, work.resolutionTree)); | |
| 152 classElement.backendMembers = | |
| 153 classElement.backendMembers.prepend(bodyElement); | |
| 154 } | |
| 155 // TODO(floitsch): pass initializer-list to builder. | |
| 156 return builder.buildFactory(classElement, bodyElement, work.element); | |
| 157 } | 133 } |
| 158 } | 134 } |
| 159 | 135 |
| 160 /** | 136 /** |
| 161 * Keeps track of locals (including parameters and phis) when building. The | 137 * Keeps track of locals (including parameters and phis) when building. The |
| 162 * 'this' reference is treated as parameter and hence handled by this class, | 138 * 'this' reference is treated as parameter and hence handled by this class, |
| 163 * too. | 139 * too. |
| 164 */ | 140 */ |
| 165 class LocalsHandler { | 141 class LocalsHandler { |
| 166 // The values of locals that can be directly accessed (without redirections | 142 // The values of locals that can be directly accessed (without redirections |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 414 joinBlock.addPhi(phi); | 390 joinBlock.addPhi(phi); |
| 415 joinedLocals[element] = phi; | 391 joinedLocals[element] = phi; |
| 416 } | 392 } |
| 417 }); | 393 }); |
| 418 directLocals = joinedLocals; | 394 directLocals = joinedLocals; |
| 419 } | 395 } |
| 420 } | 396 } |
| 421 | 397 |
| 422 class SsaBuilder implements Visitor { | 398 class SsaBuilder implements Visitor { |
| 423 final Compiler compiler; | 399 final Compiler compiler; |
| 424 final TreeElements elements; | 400 TreeElements elements; |
| 425 final Interceptors interceptors; | 401 final Interceptors interceptors; |
| 426 final WorkItem work; | 402 final WorkItem work; |
| 427 bool methodInterceptionEnabled; | 403 bool methodInterceptionEnabled; |
| 428 HGraph graph; | 404 HGraph graph; |
| 429 LocalsHandler localsHandler; | 405 LocalsHandler localsHandler; |
| 430 | 406 |
| 431 // We build the Ssa graph by simulating a stack machine. | 407 // We build the Ssa graph by simulating a stack machine. |
| 432 List<HInstruction> stack; | 408 List<HInstruction> stack; |
| 433 | 409 |
| 434 // The current block to add instructions to. Might be null, if we are | 410 // The current block to add instructions to. Might be null, if we are |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 456 methodInterceptionEnabled = true; | 432 methodInterceptionEnabled = true; |
| 457 } | 433 } |
| 458 | 434 |
| 459 HGraph buildMethod(FunctionElement functionElement) { | 435 HGraph buildMethod(FunctionElement functionElement) { |
| 460 FunctionExpression function = functionElement.parseNode(compiler); | 436 FunctionExpression function = functionElement.parseNode(compiler); |
| 461 openFunction(functionElement, function); | 437 openFunction(functionElement, function); |
| 462 function.body.accept(this); | 438 function.body.accept(this); |
| 463 return closeFunction(); | 439 return closeFunction(); |
| 464 } | 440 } |
| 465 | 441 |
| 442 /** | |
| 443 * Returns the constructor body associated with the given constructor or | |
| 444 * creates a new constructor body, if none can be found. | |
| 445 */ | |
| 446 ConstructorBodyElement getConstructorBody(ClassElement classElement, | |
| 447 FunctionElement constructor) { | |
| 448 assert(constructor.kind === ElementKind.GENERATIVE_CONSTRUCTOR); | |
| 449 ConstructorBodyElement bodyElement; | |
| 450 for (Link<Element> backendMembers = classElement.backendMembers; | |
| 451 !backendMembers.isEmpty(); | |
| 452 backendMembers = backendMembers.tail) { | |
| 453 Element backendMember = backendMembers.head; | |
| 454 if (backendMember.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { | |
| 455 ConstructorBodyElement body = backendMember; | |
| 456 if (body.constructor == constructor) { | |
| 457 bodyElement = backendMember; | |
| 458 break; | |
| 459 } | |
| 460 } | |
| 461 } | |
| 462 if (bodyElement === null) { | |
| 463 bodyElement = new ConstructorBodyElement(constructor); | |
| 464 TreeElements treeElements = | |
| 465 compiler.resolver.resolveMethodElement(bodyElement); | |
| 466 compiler.enqueue(new WorkItem.toCodegen(bodyElement, treeElements)); | |
| 467 classElement.backendMembers = | |
| 468 classElement.backendMembers.prepend(bodyElement); | |
| 469 } | |
| 470 assert(bodyElement.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY); | |
| 471 return bodyElement; | |
| 472 } | |
| 473 | |
| 474 /** | |
| 475 * Call [f] for every argument and parameter element of [target] | |
| 476 * that is used in the invocation [send]. | |
| 477 */ | |
| 478 forEachArgument(Send send, FunctionElement target, | |
| 479 f(VariableElement parameter, Node argument)) { | |
| 480 final FunctionParameters parameters = target.computeParameters(compiler); | |
| 481 Link<Element> parameterElements = parameters.requiredParameters; | |
| 482 for (Link<Node> arguments = send.arguments; | |
| 483 !arguments.isEmpty(); | |
| 484 arguments = arguments.tail) { | |
| 485 if (parameterElements.isEmpty()) { | |
| 486 parameterElements = parameters.optionalParameters; | |
| 487 } | |
| 488 f(parameterElements.head, arguments.head); | |
| 489 parameterElements = parameterElements.tail; | |
| 490 }; | |
| 491 } | |
| 492 | |
| 493 /** | |
| 494 * Run through the initializers and inline all field initializers. Returns the | |
| 495 * next constructor to analyze. | |
| 496 */ | |
| 497 FunctionElement analyzeInitializers(Link<Node> initializers) { | |
| 498 FunctionElement nextConstructor; | |
| 499 for (Link<Node> link = initializers; !link.isEmpty(); link = link.tail) { | |
| 500 assert(link.head is Send); | |
| 501 if (link.head is !SendSet) { | |
| 502 // A super initializer or constructor redirection. | |
| 503 Send call = link.head; | |
| 504 if (Initializers.isSuperConstructorCall(call)) { | |
| 505 assert(nextConstructor === null); | |
| 506 nextConstructor = elements[call]; | |
| 507 // Visit arguments and map the corresponding parameter value to | |
| 508 // the resulting HInstruction value. | |
| 509 forEachArgument(call, nextConstructor, (parameter, node) { | |
| 510 visit(node); | |
| 511 HInstruction value = pop(); | |
| 512 localsHandler.updateLocal(parameter, value); | |
| 513 }); | |
| 514 } else { | |
| 515 compiler.unimplemented('SsaBuilder.buildFactory redirect'); | |
| 516 } | |
| 517 } else { | |
| 518 // A field initializer. | |
| 519 SendSet init = link.head; | |
| 520 Link<Node> arguments = init.arguments; | |
| 521 assert(!arguments.isEmpty() && arguments.tail.isEmpty()); | |
| 522 visit(arguments.head); | |
| 523 // We treat the init field-elements like locals. In the context of | |
| 524 // the factory this is correct, and simplifies dealing with | |
| 525 // parameter-initializers (like A(this.x)). | |
| 526 localsHandler.updateLocal(elements[init], pop()); | |
| 527 } | |
| 528 } | |
| 529 return nextConstructor; | |
| 530 } | |
| 531 | |
| 532 /** | |
| 533 * Build the factory function corresponding to the constructor | |
| 534 * [functionElement]: | |
| 535 * - Initialize fields with the values of the field initializers of the | |
| 536 * current constructor and super constructors or constructors redirected | |
| 537 * to, starting from the current constructor. | |
| 538 * - Call the the constructor bodies, starting from the constructor(s) in the | |
| 539 * super class(es). | |
| 540 */ | |
| 466 HGraph buildFactory(ClassElement classElement, | 541 HGraph buildFactory(ClassElement classElement, |
| 467 ConstructorBodyElement bodyElement, | |
| 468 FunctionElement functionElement) { | 542 FunctionElement functionElement) { |
| 469 FunctionExpression function = functionElement.parseNode(compiler); | 543 FunctionExpression function = functionElement.parseNode(compiler); |
| 470 // The initializer list could contain closures. | 544 // The initializer list could contain closures. |
| 471 openFunction(functionElement, function); | 545 openFunction(functionElement, function); |
| 472 | 546 |
| 473 NodeList initializers = function.initializers; | 547 final Map<FunctionElement, TreeElements> constructorElements = |
| 548 compiler.resolver.constructorElements; | |
|
ngeoffray
2012/02/09 08:25:51
This variable is unused.
| |
| 549 List<FunctionElement> constructors = new List<FunctionElement>(); | |
| 474 | 550 |
| 475 // Run through the initializers. | 551 // Analyze the constructor and all referenced constructors and collect |
| 476 if (initializers !== null) { | 552 // initializers and constructor bodies. |
| 477 for (Link<Node> link = initializers.nodes; | 553 FunctionElement nextConstructor = functionElement; |
| 478 !link.isEmpty(); | 554 while (nextConstructor != null) { |
| 479 link = link.tail) { | 555 FunctionElement constructor = nextConstructor; |
| 480 assert(link.head is Send); | 556 constructors.addLast(constructor); |
| 481 if (link.head is !SendSet) { | 557 nextConstructor = null; |
| 482 compiler.unimplemented('SsaBuilder.buildFactory super-init'); | 558 elements = compiler.resolver.resolveMethodElement(constructor); |
| 483 } else { | 559 FunctionExpression functionNode = constructor.parseNode(compiler); |
| 484 SendSet init = link.head; | 560 Link<Node> initializers = const EmptyLink<Node>(); |
| 485 Link<Node> arguments = init.arguments; | 561 if (functionNode.initializers !== null) { |
| 486 assert(!arguments.isEmpty() && arguments.tail.isEmpty()); | 562 nextConstructor = analyzeInitializers(functionNode.initializers.nodes); |
| 487 visit(arguments.head); | 563 } |
| 488 // We treat the init field-elements like locals. In the context of | 564 if (nextConstructor === null) { |
| 489 // the factory this is correct, and simplifies dealing with | 565 // No super initializer found. Try to find the default constructor if |
| 490 // parameter-initializers (like A(this.x)). | 566 // the class is not Object. |
| 491 localsHandler.updateLocal(elements[init], pop()); | 567 ClassElement enclosingClass = constructor.enclosingElement; |
| 568 ClassElement superClass = enclosingClass.superclass; | |
| 569 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.
| |
| 570 assert(superClass !== null); | |
| 571 assert(superClass.isResolved); | |
| 572 nextConstructor = superClass.lookupConstructor(superClass.name); | |
| 573 if (nextConstructor === null && | |
| 574 superClass.canHaveDefaultConstructor()) { | |
| 575 nextConstructor = superClass.getSynthesizedConstructor(); | |
| 576 } else if (nextConstructor === null) { | |
| 577 compiler.internalError("no default constructor available"); | |
| 578 } | |
| 492 } | 579 } |
| 493 } | 580 } |
| 494 } | 581 } |
|
ngeoffray
2012/02/09 08:27:03
I would put 'elements' to null here, to make sure
| |
| 495 | |
| 496 // Call the JavaScript constructor with the fields as argument. | 582 // Call the JavaScript constructor with the fields as argument. |
| 497 // TODO(floitsch): allow super calls. | 583 // TODO(floitsch,karlklose): move this code to ClassElement and share with |
| 498 // TODO(floitsch): allow inits at field declarations. | 584 // the emitter. |
| 499 List<HInstruction> constructorArguments = <HInstruction>[]; | 585 List<HInstruction> constructorArguments = <HInstruction>[]; |
| 500 for (Element member in classElement.members) { | 586 ClassElement element = classElement; |
| 501 if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { | 587 while (element != null) { |
| 502 HInstruction value; | 588 for (Element member in element.members) { |
| 503 if (localsHandler.hasValueForDirectLocal(member)) { | 589 if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { |
| 504 value = localsHandler.readLocal(member); | 590 HInstruction value; |
| 505 } else { | 591 if (localsHandler.hasValueForDirectLocal(member)) { |
| 506 value = new HLiteral(null, HType.UNKNOWN); | 592 value = localsHandler.readLocal(member); |
| 507 add(value); | 593 } else { |
| 594 // TODO(karlklose): get default value. | |
| 595 value = new HLiteral(null, HType.UNKNOWN); | |
| 596 add(value); | |
| 597 } | |
| 598 constructorArguments.add(value); | |
| 508 } | 599 } |
| 509 constructorArguments.add(value); | |
| 510 } | 600 } |
| 601 element = element.superclass; | |
| 511 } | 602 } |
| 512 HForeignNew newObject = new HForeignNew(classElement, constructorArguments); | 603 HForeignNew newObject = new HForeignNew(classElement, constructorArguments); |
| 513 add(newObject); | 604 add(newObject); |
| 514 | 605 // Generate calls to the constructor bodies. |
| 515 // Call the method body. | 606 for (int index = constructors.length - 1; index >= 0; index--) { |
| 516 SourceString methodName = bodyElement.name; | 607 FunctionElement constructor = constructors[index]; |
| 517 | 608 ConstructorBodyElement body = this.getConstructorBody(classElement, |
| 518 List bodyCallInputs = <HInstruction>[]; | 609 constructor); |
| 519 bodyCallInputs.add(newObject); | 610 List bodyCallInputs = <HInstruction>[]; |
| 520 FunctionParameters parameters = functionElement.computeParameters(compiler); | 611 bodyCallInputs.add(newObject); |
| 521 parameters.forEachParameter((Element parameterElement) { | 612 body.functionParameters.forEachParameter((parameter) { |
|
ngeoffray
2012/02/09 08:25:51
To be safe, should that be body.computeParameters(
| |
| 522 HInstruction currentValue = localsHandler.readLocal(parameterElement); | 613 bodyCallInputs.add(localsHandler.readLocal(parameter)); |
| 523 bodyCallInputs.add(currentValue); | 614 }); |
| 524 }); | 615 SourceString methodName = body.name; |
| 525 add(new HInvokeDynamicMethod(null, methodName, bodyCallInputs)); | 616 add(new HInvokeDynamicMethod(null, methodName, bodyCallInputs)); |
| 617 } | |
| 526 close(new HReturn(newObject)).addSuccessor(graph.exit); | 618 close(new HReturn(newObject)).addSuccessor(graph.exit); |
| 527 return closeFunction(); | 619 return closeFunction(); |
| 528 } | 620 } |
| 529 | 621 |
| 530 void openFunction(FunctionElement functionElement, | 622 void openFunction(FunctionElement functionElement, |
| 531 FunctionExpression node) { | 623 FunctionExpression node) { |
| 532 HBasicBlock block = graph.addNewBlock(); | 624 HBasicBlock block = graph.addNewBlock(); |
| 533 open(graph.entry); | 625 open(graph.entry); |
| 534 | 626 |
| 535 localsHandler.startFunction(functionElement, node); | 627 localsHandler.startFunction(functionElement, node); |
| (...skipping 1237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1773 if (exception.type != null) { | 1865 if (exception.type != null) { |
| 1774 compiler.unimplemented('SsaBuilder catch with type', node: node); | 1866 compiler.unimplemented('SsaBuilder catch with type', node: node); |
| 1775 } | 1867 } |
| 1776 visit(node.block); | 1868 visit(node.block); |
| 1777 } | 1869 } |
| 1778 | 1870 |
| 1779 visitTypedef(Typedef node) { | 1871 visitTypedef(Typedef node) { |
| 1780 compiler.unimplemented('SsaBuilder.visitTypedef', node: node); | 1872 compiler.unimplemented('SsaBuilder.visitTypedef', node: node); |
| 1781 } | 1873 } |
| 1782 } | 1874 } |
| OLD | NEW |