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

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

Issue 9873021: Move frog/leg to lib/compiler/implementation. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 9 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/ssa/closure.dart ('k') | frog/leg/ssa/codegen_helpers.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: frog/leg/ssa/codegen.dart
===================================================================
--- frog/leg/ssa/codegen.dart (revision 5925)
+++ frog/leg/ssa/codegen.dart (working copy)
@@ -1,1565 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-class SsaCodeGeneratorTask extends CompilerTask {
- SsaCodeGeneratorTask(Compiler compiler) : super(compiler);
- String get name() => 'SSA code generator';
-
-
- String generateMethod(WorkItem work, HGraph graph) {
- return measure(() {
- compiler.tracer.traceGraph("codegen", graph);
- Map<Element, String> parameterNames = getParameterNames(work);
- String parameters = Strings.join(parameterNames.getValues(), ', ');
- SsaOptimizedCodeGenerator codegen = new SsaOptimizedCodeGenerator(
- compiler, work, parameters, parameterNames);
- codegen.visitGraph(graph);
- return 'function($parameters) {\n${codegen.buffer}}';
- });
- }
-
- String generateBailoutMethod(WorkItem work, HGraph graph) {
- return measure(() {
- compiler.tracer.traceGraph("codegen-bailout", graph);
- new SsaBailoutPropagator(compiler).visitGraph(graph);
-
- Map<Element, String> parameterNames = getParameterNames(work);
- String parameters = Strings.join(parameterNames.getValues(), ', ');
- SsaUnoptimizedCodeGenerator codegen = new SsaUnoptimizedCodeGenerator(
- compiler, work, parameters, parameterNames);
- codegen.visitGraph(graph);
-
- StringBuffer newParameters = new StringBuffer();
- if (!parameterNames.isEmpty()) newParameters.add('$parameters, ');
- newParameters.add('state');
-
- for (int i = 0; i < codegen.maxBailoutParameters; i++) {
- newParameters.add(', env$i');
- }
-
- return 'function($newParameters) {\n${codegen.setup}${codegen.buffer}}';
- });
- }
-
- Map<Element, String> getParameterNames(WorkItem work) {
- Map<Element, String> parameterNames = new LinkedHashMap<Element, String>();
- FunctionElement function = work.element;
-
- // The dom/html libraries have inline JS code that reference
- // parameter names directly. Long-term such code will be rejected.
- // Now, just don't mangle the parameter name.
- function.computeParameters(compiler).forEachParameter((Element element) {
- parameterNames[element] = function.isNative()
- ? element.name.slowToString()
- : JsNames.getValid('${element.name.slowToString()}');
- });
- return parameterNames;
- }
-}
-
-typedef void ElementAction(Element element);
-
-class SsaCodeGenerator implements HVisitor {
- final Compiler compiler;
- final WorkItem work;
- final StringBuffer buffer;
- final String parameters;
-
- final Map<Element, String> parameterNames;
- final Map<int, String> names;
- final Map<String, int> prefixes;
- final Set<HInstruction> generateAtUseSite;
- final Map<HPhi, String> logicalOperations;
- final Map<Element, ElementAction> breakAction;
- final Map<Element, ElementAction> continueAction;
-
- Element equalsNullElement;
- int indent = 0;
- int expectedPrecedence = JSPrecedence.STATEMENT_PRECEDENCE;
- HGraph currentGraph;
- HBasicBlock currentBlock;
-
- // Records a block-information that is being handled specially.
- // Used to break bad recursion.
- HLabeledBlockInformation currentBlockInformation;
- // The subgraph is used to delimit traversal for some constructions, e.g.,
- // if branches.
- SubGraph subGraph;
-
- LibraryElement get currentLibrary() => work.element.getLibrary();
-
- bool isGenerateAtUseSite(HInstruction instruction) {
- return generateAtUseSite.contains(instruction);
- }
-
- SsaCodeGenerator(this.compiler,
- this.work,
- this.parameters,
- this.parameterNames)
- : names = new Map<int, String>(),
- prefixes = new Map<String, int>(),
- buffer = new StringBuffer(),
- generateAtUseSite = new Set<HInstruction>(),
- logicalOperations = new Map<HPhi, String>(),
- breakAction = new Map<Element, ElementAction>(),
- continueAction = new Map<Element, ElementAction>() {
-
- for (final name in parameterNames.getValues()) {
- prefixes[name] = 0;
- }
-
- equalsNullElement =
- compiler.builder.interceptors.getEqualsNullInterceptor();
- }
-
- abstract visitTypeGuard(HTypeGuard node);
-
- abstract beginGraph(HGraph graph);
- abstract endGraph(HGraph graph);
-
- abstract beginLoop(HBasicBlock block);
- abstract endLoop(HBasicBlock block);
- abstract handleLoopCondition(HLoopBranch node);
-
- abstract startIf(HIf node);
- abstract endIf(HIf node);
- abstract startThen(HIf node);
- abstract endThen(HIf node);
- abstract startElse(HIf node);
- abstract endElse(HIf node);
-
- void beginExpression(int precedence) {
- if (precedence < expectedPrecedence) {
- buffer.add('(');
- }
- }
-
- void endExpression(int precedence) {
- if (precedence < expectedPrecedence) {
- buffer.add(')');
- }
- }
-
- void preGenerateMethod(HGraph graph) {
- new SsaInstructionMerger(generateAtUseSite).visitGraph(graph);
- new SsaConditionMerger(generateAtUseSite,
- logicalOperations).visitGraph(graph);
- }
-
- visitGraph(HGraph graph) {
- preGenerateMethod(graph);
- currentGraph = graph;
- indent++; // We are already inside a function.
- subGraph = new SubGraph(graph.entry, graph.exit);
- beginGraph(graph);
- visitBasicBlock(graph.entry);
- endGraph(graph);
- }
-
- void visitSubGraph(SubGraph newSubGraph) {
- SubGraph oldSubGraph = subGraph;
- subGraph = newSubGraph;
- visitBasicBlock(subGraph.start);
- subGraph = oldSubGraph;
- }
-
- String temporary(HInstruction instruction) {
- int id = instruction.id;
- String name = names[id];
- if (name !== null) return name;
-
- if (instruction is HPhi) {
- HPhi phi = instruction;
- Element element = phi.element;
- if (element != null && element.kind == ElementKind.PARAMETER) {
- name = parameterNames[element];
- names[id] = name;
- return name;
- }
-
- String prefix;
- if (element !== null && !element.name.isEmpty()) {
- prefix = element.name.slowToString();
- } else {
- prefix = 'v';
- }
- if (!prefixes.containsKey(prefix)) {
- prefixes[prefix] = 0;
- return newName(id, prefix);
- } else {
- return newName(id, '${prefix}_${prefixes[prefix]++}');
- }
- } else {
- String prefix = 't';
- if (!prefixes.containsKey(prefix)) prefixes[prefix] = 0;
- return newName(id, '${prefix}${prefixes[prefix]++}');
- }
- }
-
- bool temporaryExists(HInstruction instruction) {
- return names.containsKey(instruction.id);
- }
-
- String newName(int id, String name) {
- String result = JsNames.getValid(name);
- names[id] = result;
- return result;
- }
-
- /**
- * Only visits the arguments starting at inputs[HInvoke.ARGUMENTS_OFFSET].
- */
- void visitArguments(List<HInstruction> inputs) {
- assert(inputs.length >= HInvoke.ARGUMENTS_OFFSET);
- buffer.add('(');
- for (int i = HInvoke.ARGUMENTS_OFFSET; i < inputs.length; i++) {
- if (i != HInvoke.ARGUMENTS_OFFSET) buffer.add(', ');
- use(inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE);
- }
- buffer.add(')');
- }
-
- void define(HInstruction instruction) {
- buffer.add('var ${temporary(instruction)} = ');
- visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE);
- }
-
- void use(HInstruction argument, int expectedPrecedence) {
- if (isGenerateAtUseSite(argument)) {
- visit(argument, expectedPrecedence);
- } else if (argument is HIntegerCheck) {
- HIntegerCheck instruction = argument;
- use(instruction.value, expectedPrecedence);
- } else if (argument is HBoundsCheck) {
- HBoundsCheck instruction = argument;
- use(instruction.index, expectedPrecedence);
- } else if (argument is HTypeGuard) {
- HTypeGuard instruction = argument;
- use(instruction.guarded, expectedPrecedence);
- } else {
- buffer.add(temporary(argument));
- }
- }
-
- visit(HInstruction node, int expectedPrecedence) {
- int oldPrecedence = this.expectedPrecedence;
- this.expectedPrecedence = expectedPrecedence;
- node.accept(this);
- this.expectedPrecedence = oldPrecedence;
- }
-
- void continueAsBreak(LabelElement target) {
- addIndentation();
- buffer.add("break ");
- writeContinueLabel(target);
- buffer.add(";\n");
- }
-
- void implicitContinueAsBreak(TargetElement target) {
- addIndentation();
- buffer.add("break ");
- writeImplicitContinueLabel(target);
- buffer.add(";\n");
- }
-
- void implicitBreakWithLabel(TargetElement target) {
- addIndentation();
- buffer.add("break ");
- writeImplicitLabel(target);
- buffer.add(";\n");
- }
-
- void handleLabeledBlock(HLabeledBlockInformation labeledBlockInfo) {
- addIndentation();
- Link<Element> continueOverrides = const EmptyLink<Element>();
- // If [labeledBlockInfo.isContinue], the block is an artificial
- // block around the body of a loop with an update block, so that
- // continues of the loop can be written as breaks of the body
- // block.
- if (labeledBlockInfo.isContinue) {
- for (LabelElement label in labeledBlockInfo.labels) {
- if (label.isContinueTarget) {
- writeContinueLabel(label);
- buffer.add(':');
- continueAction[label] = continueAsBreak;
- continueOverrides = continueOverrides.prepend(label);
- }
- }
- // For handling unlabeled continues from the body of a loop.
- // TODO(lrn): Consider recording whether the target is in fact
- // a target of an unlabeled continue, and not generate this if it isn't.
- TargetElement target = labeledBlockInfo.target;
- writeImplicitContinueLabel(target);
- buffer.add(':');
- continueAction[target] = implicitContinueAsBreak;
- continueOverrides = continueOverrides.prepend(target);
- } else {
- for (LabelElement label in labeledBlockInfo.labels) {
- if (label.isBreakTarget) {
- writeLabel(label);
- buffer.add(':');
- }
- }
- TargetElement target = labeledBlockInfo.target;
- if (target.isSwitch) {
- // This is an extra block around a switch that is generated
- // as a nested if/else chain. We add an extra break target
- // so that case code can break.
- writeImplicitLabel(target);
- buffer.add(':');
- breakAction[target] = implicitBreakWithLabel;
- }
- }
- buffer.add('{\n');
- indent++;
-
- visitSubGraph(labeledBlockInfo.body);
-
- indent--;
- addIndentation();
- buffer.add('}\n');
-
- if (labeledBlockInfo.joinBlock !== null) {
- visitBasicBlock(labeledBlockInfo.joinBlock);
- }
- if (labeledBlockInfo.isContinue) {
- while (!continueOverrides.isEmpty()) {
- continueAction.remove(continueOverrides.head);
- continueOverrides = continueOverrides.tail;
- }
- } else {
- breakAction.remove(labeledBlockInfo.target);
- }
- }
-
- void emitLogicalOperation(HPhi node, String operation) {
- JSBinaryOperatorPrecedence operatorPrecedence =
- JSPrecedence.binary[operation];
- beginExpression(operatorPrecedence.precedence);
- use(node.inputs[0], operatorPrecedence.left);
- buffer.add(" $operation ");
- use(node.inputs[1], operatorPrecedence.right);
- endExpression(operatorPrecedence.precedence);
- }
-
- visitBasicBlock(HBasicBlock node) {
- // Abort traversal if we are leaving the currently active sub-graph.
- if (!subGraph.contains(node)) return;
-
- // If this node has special behavior attached, handle it.
- // If we reach here again while handling the attached information,
- // e.g., because we call visitSubGraph on a subgraph starting here,
- // don't handle it again.
- if (node.hasLabeledBlockInformation() &&
- node.labeledBlockInformation !== currentBlockInformation) {
- HLabeledBlockInformation oldBlockInformation = currentBlockInformation;
- currentBlockInformation = node.labeledBlockInformation;
- handleLabeledBlock(currentBlockInformation);
- currentBlockInformation = oldBlockInformation;
- return;
- }
-
- currentBlock = node;
-
- if (node.isLoopHeader()) {
- // While loop will be closed by the conditional loop-branch.
- // TODO(floitsch): HACK HACK HACK.
- beginLoop(node);
- }
-
- HInstruction instruction = node.first;
- while (instruction != null) {
- if (instruction === node.last) {
- for (HBasicBlock successor in node.successors) {
- int index = successor.predecessors.indexOf(node);
- successor.forEachPhi((HPhi phi) {
- bool isLogicalOperation = logicalOperations.containsKey(phi);
- // In case the phi is being generated by another
- // instruction.
- if (isLogicalOperation && isGenerateAtUseSite(phi)) return;
- addIndentation();
- if (!temporaryExists(phi)) buffer.add('var ');
- buffer.add('${temporary(phi)} = ');
- if (isLogicalOperation) {
- emitLogicalOperation(phi, logicalOperations[phi]);
- } else {
- use(phi.inputs[index], JSPrecedence.ASSIGNMENT_PRECEDENCE);
- }
- buffer.add(';\n');
- });
- }
- }
-
- if (instruction is HGoto || instruction is HExit || instruction is HTry) {
- visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE);
- return;
- } else if (!isGenerateAtUseSite(instruction)) {
- if (instruction is !HIf && instruction is !HTypeGuard) {
- addIndentation();
- }
- if (instruction.usedBy.isEmpty()
- || instruction is HTypeGuard
- || instruction is HCheck) {
- visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE);
- } else {
- define(instruction);
- }
- // Control flow instructions know how to handle ';'.
- if (instruction is !HControlFlow && instruction is !HTypeGuard) {
- buffer.add(';\n');
- }
- } else if (instruction is HIf) {
- HIf hif = instruction;
- // The "if" is implementing part of a logical expression.
- // Skip directly forward to to its latest successor, since everything
- // in-between must also be generateAtUseSite.
- assert(hif.trueBranch.id < hif.falseBranch.id);
- visitBasicBlock(hif.falseBranch);
- return;
- }
- instruction = instruction.next;
- }
- }
-
- visitInvokeBinary(HInvokeBinary node, String op) {
- if (node.builtin) {
- JSBinaryOperatorPrecedence operatorPrecedences = JSPrecedence.binary[op];
- beginExpression(operatorPrecedences.precedence);
- use(node.left, operatorPrecedences.left);
- buffer.add(' $op ');
- use(node.right, operatorPrecedences.right);
- endExpression(operatorPrecedences.precedence);
- } else {
- visitInvokeStatic(node);
- }
- }
-
- visitInvokeUnary(HInvokeUnary node, String op) {
- if (node.builtin) {
- beginExpression(JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add('$op');
- use(node.operand, JSPrecedence.PREFIX_PRECEDENCE);
- endExpression(JSPrecedence.PREFIX_PRECEDENCE);
- } else {
- visitInvokeStatic(node);
- }
- }
-
- visitEquals(HEquals node) {
- if (node.builtin) {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- use(node.left, JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(' === ');
- use(node.right, JSPrecedence.RELATIONAL_PRECEDENCE);
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- } else if (node.element === equalsNullElement) {
- beginExpression(JSPrecedence.CALL_PRECEDENCE);
- use(node.target, JSPrecedence.CALL_PRECEDENCE);
- buffer.add('(');
- use(node.left, JSPrecedence.ASSIGNMENT_PRECEDENCE);
- buffer.add(')');
- endExpression(JSPrecedence.CALL_PRECEDENCE);
- } else {
- visitInvokeStatic(node);
- }
- }
-
- visitAdd(HAdd node) => visitInvokeBinary(node, '+');
- visitDivide(HDivide node) => visitInvokeBinary(node, '/');
- visitMultiply(HMultiply node) => visitInvokeBinary(node, '*');
- visitSubtract(HSubtract node) => visitInvokeBinary(node, '-');
- // Truncating divide does not have a JS equivalent.
- visitTruncatingDivide(HTruncatingDivide node) => visitInvokeStatic(node);
- // Modulo cannot be mapped to the native operator (different semantics).
- visitModulo(HModulo node) => visitInvokeStatic(node);
-
- visitBitAnd(HBitAnd node) => visitInvokeBinary(node, '&');
- visitBitNot(HBitNot node) => visitInvokeUnary(node, '~');
- visitBitOr(HBitOr node) => visitInvokeBinary(node, '|');
- visitBitXor(HBitXor node) => visitInvokeBinary(node, '^');
-
- // We need to check if the left operand is negative in order to use
- // the native operator.
- visitShiftRight(HShiftRight node) => visitInvokeStatic(node);
-
- // Shift left cannot be mapped to the native operator (different semantics).
- visitShiftLeft(HShiftLeft node) => visitInvokeStatic(node);
-
- visitNegate(HNegate node) => visitInvokeUnary(node, '-');
-
- visitIdentity(HIdentity node) => visitInvokeBinary(node, '===');
- visitLess(HLess node) => visitInvokeBinary(node, '<');
- visitLessEqual(HLessEqual node) => visitInvokeBinary(node, '<=');
- visitGreater(HGreater node) => visitInvokeBinary(node, '>');
- visitGreaterEqual(HGreaterEqual node) => visitInvokeBinary(node, '>=');
-
- visitBoolify(HBoolify node) {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- assert(node.inputs.length == 1);
- use(node.inputs[0], JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(' === true');
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- }
-
- visitExit(HExit node) {
- // Don't do anything.
- }
-
- visitGoto(HGoto node) {
- assert(currentBlock.successors.length == 1);
- List<HBasicBlock> dominated = currentBlock.dominatedBlocks;
- // With the exception of the entry-node which dominates its successor
- // and the exit node, no block finishing with a 'goto' can have more than
- // one dominated block (since it has only one successor).
- // If the successor is dominated by another block, then the other block
- // is responsible for visiting the successor.
- if (dominated.isEmpty()) return;
- if (dominated.length > 2) unreachable();
- if (dominated.length == 2 && currentBlock !== currentGraph.entry) {
- unreachable();
- }
- assert(dominated[0] == currentBlock.successors[0]);
- visitBasicBlock(dominated[0]);
- }
-
- // Used to write the name of labels.
- void writeLabel(LabelElement label) {
- buffer.add('\$${label.labelName}\$${label.target.nestingLevel}');
- }
-
- void writeImplicitLabel(TargetElement target) {
- buffer.add('\$${target.nestingLevel}');
- }
-
- // We sometimes handle continue targets differently from break targets,
- // so we have special continue-only labels.
- void writeContinueLabel(LabelElement label) {
- buffer.add('c\$${label.labelName}\$${label.target.nestingLevel}');
- }
-
- void writeImplicitContinueLabel(TargetElement target) {
- buffer.add('c\$${target.nestingLevel}');
- }
-
- /**
- * Checks if [map] contains an [ElementAction] for [element], and
- * if so calls that action and returns true.
- * Otherwise returns false.
- */
- bool tryCallAction(Map<Element, ElementAction> map, Element element) {
- ElementAction action = map[element];
- if (action === null) return false;
- action(element);
- return true;
- }
-
- visitBreak(HBreak node) {
- assert(currentBlock.successors.length == 1);
- if (node.label !== null) {
- LabelElement label = node.label;
- if (!tryCallAction(breakAction, label)) {
- addIndentation();
- buffer.add("break ");
- writeLabel(label);
- buffer.add(";\n");
- }
- } else {
- TargetElement target = node.target;
- if (!tryCallAction(breakAction, target)) {
- addIndentation();
- buffer.add("break;\n");
- }
- }
- }
-
- visitContinue(HContinue node) {
- assert(currentBlock.successors.length == 1);
- if (node.label !== null) {
- LabelElement label = node.label;
- if (!tryCallAction(continueAction, label)) {
- addIndentation();
- buffer.add("continue ");
- writeLabel(label);
- buffer.add(";\n");
- }
- } else {
- TargetElement target = node.target;
- if (!tryCallAction(continueAction, target)) {
- addIndentation();
- buffer.add("continue;\n");
- }
- }
- }
-
- visitTry(HTry node) {
- addIndentation();
- buffer.add('try {\n');
- indent++;
- List<HBasicBlock> successors = node.block.successors;
- visitBasicBlock(successors[0]);
- indent--;
-
- if (node.finallyBlock != successors[1]) {
- // Printing the catch part.
- addIndentation();
- String name = temporary(node.exception);
- parameterNames[node.exception.element] = name;
- buffer.add('} catch ($name) {\n');
- indent++;
- visitBasicBlock(successors[1]);
- parameterNames.remove(node.exception.element);
- indent--;
- }
-
- if (node.finallyBlock != null) {
- addIndentation();
- buffer.add('} finally {\n');
- indent++;
- visitBasicBlock(node.finallyBlock);
- indent--;
- }
- addIndentation();
- buffer.add('}\n');
-
- visitBasicBlock(node.joinBlock);
- }
-
- visitIf(HIf node) {
- List<HBasicBlock> dominated = node.block.dominatedBlocks;
- HIfBlockInformation info = node.blockInformation;
- startIf(node);
- assert(!isGenerateAtUseSite(node));
- startThen(node);
- assert(node.thenBlock === dominated[0]);
- visitSubGraph(info.thenGraph);
- int preVisitedBlocks = 1;
- endThen(node);
- if (node.hasElse) {
- startElse(node);
- assert(node.elseBlock === dominated[1]);
- visitSubGraph(info.elseGraph);
- preVisitedBlocks = 2;
- endElse(node);
- }
- endIf(node);
- if (info.joinBlock !== null && info.joinBlock.dominator !== node.block) {
- // The join block is dominated by a block in one of the branches.
- // The subgraph traversal never reached it, so we visit it here
- // instead.
- visitBasicBlock(info.joinBlock);
- }
-
- // Visit all the dominated blocks that are not part of the then or else
- // branches, and is not the join block.
- // Depending on how the then/else branches terminate
- // (e.g., return/throw/break) there can be any number of these.
- int dominatedCount = dominated.length;
- for (int i = preVisitedBlocks; i < dominatedCount; i++) {
- HBasicBlock dominatedBlock = dominated[i];
- assert(dominatedBlock.dominator === node.block);
- visitBasicBlock(dominatedBlock);
- }
- }
-
- visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
- beginExpression(JSPrecedence.CALL_PRECEDENCE);
- use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('.');
- // Avoid adding the generative constructor name to the list of
- // seen selectors.
- if (node.inputs[0] is HForeignNew) {
- HForeignNew foreignNew = node.inputs[0];
- // Remove 'this' from the number of arguments.
- int argumentCount = node.inputs.length - 1;
-
- // TODO(ahe): The constructor name was statically resolved in
- // SsaBuilder.buildFactory. Is there a cleaner way to do this?
- node.name.printOn(buffer);
- visitArguments(node.inputs);
- } else {
- buffer.add(compiler.namer.instanceMethodInvocationName(
- currentLibrary, node.name, node.selector));
- visitArguments(node.inputs);
- compiler.registerDynamicInvocation(node.name, node.selector);
- }
- endExpression(JSPrecedence.CALL_PRECEDENCE);
- }
-
- visitInvokeDynamicSetter(HInvokeDynamicSetter node) {
- beginExpression(JSPrecedence.CALL_PRECEDENCE);
- use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('.');
- buffer.add(compiler.namer.setterName(currentLibrary, node.name));
- visitArguments(node.inputs);
- compiler.registerDynamicSetter(node.name);
- endExpression(JSPrecedence.CALL_PRECEDENCE);
- }
-
- visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
- beginExpression(JSPrecedence.CALL_PRECEDENCE);
- use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('.');
- buffer.add(compiler.namer.getterName(currentLibrary, node.name));
- visitArguments(node.inputs);
- compiler.registerDynamicGetter(node.name);
- endExpression(JSPrecedence.CALL_PRECEDENCE);
- }
-
- visitInvokeClosure(HInvokeClosure node) {
- beginExpression(JSPrecedence.CALL_PRECEDENCE);
- use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('.');
- buffer.add(compiler.namer.closureInvocationName(node.selector));
- visitArguments(node.inputs);
- // TODO(floitsch): we should have a separate list for closure invocations.
- compiler.registerDynamicInvocation(Namer.CLOSURE_INVOCATION_NAME,
- node.selector);
- endExpression(JSPrecedence.CALL_PRECEDENCE);
- }
-
- visitInvokeStatic(HInvokeStatic node) {
- beginExpression(JSPrecedence.CALL_PRECEDENCE);
- use(node.target, JSPrecedence.CALL_PRECEDENCE);
- visitArguments(node.inputs);
- endExpression(JSPrecedence.CALL_PRECEDENCE);
- }
-
- visitInvokeSuper(HInvokeSuper node) {
- beginExpression(JSPrecedence.CALL_PRECEDENCE);
- Element superMethod = node.element;
- Element superClass = superMethod.enclosingElement;
- // Remove the element and 'this'.
- int argumentCount = node.inputs.length - 2;
- String className = compiler.namer.isolatePropertyAccess(superClass);
- String methodName;
- if (superMethod.kind == ElementKind.FUNCTION ||
- superMethod.kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
- methodName = compiler.namer.instanceMethodName(
- currentLibrary, superMethod.name, argumentCount);
- } else {
- methodName = compiler.namer.getterName(currentLibrary, superMethod.name);
- // We need to register the name to ensure that the emitter
- // generates the necessary getter.
- // TODO(ahe): This is not optimal for tree-shaking, but we lack
- // API to register the precise information. In this case, the
- // enclosingElement of superMethod needs the getter, no other
- // class (not even its subclasses).
- compiler.registerDynamicGetter(superMethod.name);
- }
- buffer.add('$className.prototype.$methodName.call');
- visitArguments(node.inputs);
- endExpression(JSPrecedence.CALL_PRECEDENCE);
- compiler.registerStaticUse(superMethod);
- }
-
- visitFieldGet(HFieldGet node) {
- String name = JsNames.getValid(node.element.name.slowToString());
- if (node.receiver !== null) {
- beginExpression(JSPrecedence.MEMBER_PRECEDENCE);
- use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('.');
- buffer.add(name);
- beginExpression(JSPrecedence.MEMBER_PRECEDENCE);
- } else {
- buffer.add(name);
- }
- }
-
- visitFieldSet(HFieldSet node) {
- if (node.receiver !== null) {
- beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
- use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('.');
- } else {
- // TODO(ngeoffray): Remove the 'var' once we don't globally box
- // variables used in a try/catch.
- buffer.add('var ');
- }
- String name = JsNames.getValid(node.element.name.slowToString());
- buffer.add(name);
- buffer.add(' = ');
- use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE);
- if (node.receiver !== null) {
- endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
- }
- }
-
- visitForeign(HForeign node) {
- String code = node.code.slowToString();
- List<HInstruction> inputs = node.inputs;
- List<String> parts = code.split('#');
- if (parts.length != inputs.length + 1) {
- compiler.internalError(
- 'Wrong number of arguments for JS', instruction: node);
- }
- beginExpression(JSPrecedence.EXPRESSION_PRECEDENCE);
- buffer.add(parts[0]);
- for (int i = 0; i < inputs.length; i++) {
- use(inputs[i], JSPrecedence.EXPRESSION_PRECEDENCE);
- buffer.add(parts[i + 1]);
- }
- endExpression(JSPrecedence.EXPRESSION_PRECEDENCE);
- }
-
- visitForeignNew(HForeignNew node) {
- String jsClassReference = compiler.namer.isolateAccess(node.element);
- beginExpression(JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('new $jsClassReference(');
- // We can't use 'visitArguments', since our arguments start at input[0].
- List<HInstruction> inputs = node.inputs;
- for (int i = 0; i < inputs.length; i++) {
- if (i != 0) buffer.add(', ');
- use(inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE);
- }
- buffer.add(')');
- endExpression(JSPrecedence.MEMBER_PRECEDENCE);
- }
-
- visitConstant(HConstant node) {
- assert(isGenerateAtUseSite(node));
- // TODO(floitsch): the compile-time constant handler and the codegen
- // need to work together to avoid the parenthesis. See r4928 for an
- // implementation that still dealt with precedence.
- ConstantHandler handler = compiler.constantHandler;
- String name = handler.getNameForConstant(node.constant);
- if (name === null) {
- assert(!node.constant.isObject());
- if (node.constant.isNum()
- && expectedPrecedence == JSPrecedence.MEMBER_PRECEDENCE) {
- buffer.add('(');
- node.constant.writeJsCode(buffer, handler);
- buffer.add(')');
- } else {
- node.constant.writeJsCode(buffer, handler);
- }
- } else {
- buffer.add(compiler.namer.CURRENT_ISOLATE);
- buffer.add(".");
- buffer.add(name);
- }
- }
-
- visitLoopBranch(HLoopBranch node) {
- HBasicBlock branchBlock = currentBlock;
- handleLoopCondition(node);
- List<HBasicBlock> dominated = currentBlock.dominatedBlocks;
- // For a do while loop, the body has already been visited.
- if (!node.isDoWhile()) {
- visitBasicBlock(dominated[0]);
- }
- endLoop(node.block);
- visitBasicBlock(branchBlock.successors[1]);
- // With labeled breaks we can have more dominated blocks.
- if (dominated.length >= 3) {
- for (int i = 2; i < dominated.length; i++) {
- visitBasicBlock(dominated[i]);
- }
- }
- }
-
- visitNot(HNot node) {
- assert(node.inputs.length == 1);
- beginExpression(JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add('!');
- use(node.inputs[0], JSPrecedence.PREFIX_PRECEDENCE);
- endExpression(JSPrecedence.PREFIX_PRECEDENCE);
- }
-
- visitParameterValue(HParameterValue node) {
- assert(isGenerateAtUseSite(node));
- buffer.add(parameterNames[node.element]);
- }
-
- visitPhi(HPhi node) {
- String operation = logicalOperations[node];
- if (operation !== null) {
- emitLogicalOperation(node, operation);
- } else {
- buffer.add('${temporary(node)}');
- }
- }
-
- visitReturn(HReturn node) {
- assert(node.inputs.length == 1);
- HInstruction input = node.inputs[0];
- if (input.isConstantNull()) {
- buffer.add('return;\n');
- } else {
- buffer.add('return ');
- use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE);
- buffer.add(';\n');
- }
- }
-
- visitThis(HThis node) {
- buffer.add('this');
- }
-
- visitThrow(HThrow node) {
- if (node.isRethrow) {
- buffer.add('throw ');
- use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE);
- } else {
- generateThrowWithHelper('captureStackTrace', node.inputs[0]);
- }
- buffer.add(';\n');
- }
-
- visitBoundsCheck(HBoundsCheck node) {
- buffer.add('if (');
- use(node.index, JSPrecedence.RELATIONAL_PRECEDENCE);
- buffer.add(' < 0 || ');
- use(node.index, JSPrecedence.RELATIONAL_PRECEDENCE);
- buffer.add(' >= ');
- use(node.length, JSPrecedence.SHIFT_PRECEDENCE);
- buffer.add(") ");
- generateThrowWithHelper('ioore', node.index);
- }
-
- visitIntegerCheck(HIntegerCheck node) {
- buffer.add('if (');
- use(node.value, JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(' !== (');
- use(node.value, JSPrecedence.BITWISE_OR_PRECEDENCE);
- buffer.add(" | 0)) ");
- generateThrowWithHelper('iae', node.value);
- }
-
- void generateThrowWithHelper(String helperName, HInstruction argument) {
- Element helper = compiler.findHelper(new SourceString(helperName));
- compiler.registerStaticUse(helper);
- buffer.add('throw ');
- beginExpression(JSPrecedence.EXPRESSION_PRECEDENCE);
- beginExpression(JSPrecedence.CALL_PRECEDENCE);
- buffer.add(compiler.namer.isolateAccess(helper));
- visitArguments([null, argument]);
- endExpression(JSPrecedence.CALL_PRECEDENCE);
- endExpression(JSPrecedence.EXPRESSION_PRECEDENCE);
- }
-
- void addIndentation() {
- for (int i = 0; i < indent; i++) {
- buffer.add(' ');
- }
- }
-
- void visitStatic(HStatic node) {
- compiler.registerStaticUse(node.element);
- buffer.add(compiler.namer.isolateAccess(node.element));
- }
-
- void visitStaticStore(HStaticStore node) {
- compiler.registerStaticUse(node.element);
- beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
- buffer.add(compiler.namer.isolateAccess(node.element));
- buffer.add(' = ');
- use(node.inputs[0], JSPrecedence.ASSIGNMENT_PRECEDENCE);
- endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
- }
-
- void visitLiteralList(HLiteralList node) {
- if (node.isConst) {
- // TODO(floitsch): Remove this when CTC handles arrays.
- SourceString name = new SourceString('makeLiteralListConst');
- Element helper = compiler.findHelper(name);
- compiler.registerStaticUse(helper);
- beginExpression(JSPrecedence.CALL_PRECEDENCE);
- buffer.add(compiler.namer.isolateAccess(helper));
- buffer.add('(');
- generateArrayLiteral(node);
- buffer.add(')');
- endExpression(JSPrecedence.CALL_PRECEDENCE);
- } else {
- generateArrayLiteral(node);
- }
- }
-
- void generateArrayLiteral(HLiteralList node) {
- buffer.add('[');
- int len = node.inputs.length;
- for (int i = 0; i < len; i++) {
- if (i != 0) buffer.add(', ');
- use(node.inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE);
- }
- buffer.add(']');
- }
-
- void visitIndex(HIndex node) {
- if (node.builtin) {
- beginExpression(JSPrecedence.MEMBER_PRECEDENCE);
- use(node.inputs[1], JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('[');
- use(node.inputs[2], JSPrecedence.EXPRESSION_PRECEDENCE);
- buffer.add(']');
- endExpression(JSPrecedence.MEMBER_PRECEDENCE);
- } else {
- visitInvokeStatic(node);
- }
- }
-
- void visitIndexAssign(HIndexAssign node) {
- if (node.builtin) {
- beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
- use(node.inputs[1], JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('[');
- use(node.inputs[2], JSPrecedence.EXPRESSION_PRECEDENCE);
- buffer.add('] = ');
- use(node.inputs[3], JSPrecedence.ASSIGNMENT_PRECEDENCE);
- endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
- } else {
- visitInvokeStatic(node);
- }
- }
-
- void visitInvokeInterceptor(HInvokeInterceptor node) {
- if (node.builtinJsName != null) {
- beginExpression(JSPrecedence.CALL_PRECEDENCE);
- use(node.inputs[1], JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('.');
- buffer.add(node.builtinJsName);
- if (node.getter) return;
- buffer.add('(');
- for (int i = 2; i < node.inputs.length; i++) {
- if (i != 2) buffer.add(', ');
- use(node.inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE);
- }
- buffer.add(")");
- endExpression(JSPrecedence.CALL_PRECEDENCE);
- } else {
- return visitInvokeStatic(node);
- }
- }
-
- void checkInt(HInstruction input, String cmp) {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- use(input, JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(' $cmp (');
- use(input, JSPrecedence.BITWISE_OR_PRECEDENCE);
- buffer.add(' | 0)');
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- }
-
- void checkNum(HInstruction input, String cmp) {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add('typeof ');
- use(input, JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add(" $cmp 'number'");
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- }
-
- void checkDouble(HInstruction input, String cmp) {
- checkNum(input, cmp);
- }
-
- void checkString(HInstruction input, String cmp) {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add('typeof ');
- use(input, JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add(" $cmp 'string'");
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- }
-
- void checkBool(HInstruction input, String cmp) {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add('typeof ');
- use(input, JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add(" $cmp 'boolean'");
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- }
-
- void checkObject(HInstruction input, String cmp) {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add('typeof ');
- use(input, JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add(" $cmp 'object'");
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- }
-
- void checkArray(HInstruction input, String cmp) {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- use(input, JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('.constructor $cmp Array');
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- }
-
- void checkNull(HInstruction input) {
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- use(input, JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(" === (void 0)");
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- }
-
- void checkFunction(HInstruction input, Element element) {
- beginExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
- beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add('typeof ');
- use(input, JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add(" === 'function'");
- endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
- buffer.add(" || ");
- beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- checkObject(input, '===');
- buffer.add(" && ");
- checkType(input, element);
- endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
- }
-
- void checkType(HInstruction input, Element element) {
- bool requiresNativeIsCheck =
- compiler.emitter.nativeEmitter.requiresNativeIsCheck(element);
- if (!requiresNativeIsCheck) buffer.add('!!');
- use(input, JSPrecedence.MEMBER_PRECEDENCE);
- buffer.add('.');
- buffer.add(compiler.namer.operatorIs(element));
- if (requiresNativeIsCheck) buffer.add('()');
- }
-
- void handleStringSupertypeCheck(HInstruction input, Element element) {
- // Make sure List and String don't share supertypes, otherwise we
- // would need to check for List too.
- assert(element !== compiler.listClass
- && !Elements.isListSupertype(element, compiler));
- beginExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
- checkString(input, '===');
- buffer.add(' || ');
- beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- checkObject(input, '===');
- buffer.add(' && ');
- checkType(input, element);
- endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
- }
-
- void handleListOrSupertypeCheck(HInstruction input, Element element) {
- // Make sure List and String don't share supertypes, otherwise we
- // would need to check for String too.
- assert(element !== compiler.stringClass
- && !Elements.isStringSupertype(element, compiler));
- beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- checkObject(input, '===');
- buffer.add(' && (');
- beginExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
- checkArray(input, '===');
- buffer.add(' || ');
- checkType(input, element);
- buffer.add(')');
- endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
- endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- }
-
- void visitIs(HIs node) {
- Element element = node.typeExpression;
- if (element.kind === ElementKind.TYPE_VARIABLE) {
- compiler.unimplemented("visitIs for type variables");
- }
- compiler.registerIsCheck(element);
- LibraryElement coreLibrary = compiler.coreLibrary;
- ClassElement objectClass = coreLibrary.find(const SourceString('Object'));
- HInstruction input = node.expression;
- if (node.nullOk) {
- beginExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
- checkNull(input);
- buffer.add(' || ');
- }
-
- if (element === objectClass || element === compiler.dynamicClass) {
- // The constant folder also does this optimization, but we make
- // it safe by assuming it may have not run.
- buffer.add('true');
- } else if (element == compiler.stringClass) {
- checkString(input, '===');
- } else if (element == compiler.doubleClass) {
- checkDouble(input, '===');
- } else if (element == compiler.numClass) {
- checkNum(input, '===');
- } else if (element == compiler.boolClass) {
- checkBool(input, '===');
- } else if (element == compiler.functionClass) {
- checkFunction(input, element);
- } else if (element == compiler.intClass) {
- beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- checkNum(input, '===');
- buffer.add(' && ');
- checkInt(input, '===');
- endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- } else if (Elements.isStringSupertype(element, compiler)) {
- handleStringSupertypeCheck(input, element);
- } else if (element === compiler.listClass
- || Elements.isListSupertype(element, compiler)) {
- handleListOrSupertypeCheck(input, element);
- } else {
- beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- checkObject(input, '===');
- buffer.add(' && ');
- checkType(input, element);
- endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
- }
-
- if (node.nullOk) {
- endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
- }
- }
-}
-
-class SsaOptimizedCodeGenerator extends SsaCodeGenerator {
- SsaOptimizedCodeGenerator(compiler, work, parameters, parameterNames)
- : super(compiler, work, parameters, parameterNames);
-
- void beginGraph(HGraph graph) {}
- void endGraph(HGraph graph) {}
-
- void bailout(HTypeGuard guard, String reason) {
- HInstruction input = guard.guarded;
- Namer namer = compiler.namer;
- Element element = work.element;
- buffer.add('return ');
- if (element.isInstanceMember()) {
- // TODO(ngeoffray): This does not work in case we come from a
- // super call. We must make bailout names unique.
- buffer.add('this.${namer.getBailoutName(element)}');
- } else {
- buffer.add(namer.isolateBailoutAccess(element));
- }
- int parametersCount = parameterNames.length;
- buffer.add('($parameters');
- if (parametersCount != 0) buffer.add(', ');
- if (guard.guarded is !HParameterValue) {
- buffer.add('${guard.state}');
- bool first = true;
- // TODO(ngeoffray): if the bailout method takes more arguments,
- // fill the remaining arguments with undefined.
- // TODO(ngeoffray): try to put a variable at a deterministic
- // location, so that multiple bailout calls put the variable at
- // the same parameter index.
- for (int i = 0; i < guard.inputs.length; i++) {
- buffer.add(', ');
- use(guard.inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE);
- }
- } else {
- assert(guard.guarded is HParameterValue);
- buffer.add(' 0');
- }
- buffer.add(')');
- }
-
- void visitTypeGuard(HTypeGuard node) {
- addIndentation();
- HInstruction input = node.guarded;
- assert(!isGenerateAtUseSite(input) || input.isCodeMotionInvariant());
- if (node.isInteger()) {
- buffer.add('if (');
- checkInt(input, '!==');
- buffer.add(') ');
- bailout(node, 'Not an integer');
- } else if (node.isNumber()) {
- buffer.add('if (');
- checkNum(input, '!==');
- buffer.add(') ');
- bailout(node, 'Not a number');
- } else if (node.isBoolean()) {
- buffer.add('if (');
- checkBool(input, '!==');
- buffer.add(') ');
- bailout(node, 'Not a boolean');
- } else if (node.isString()) {
- buffer.add('if (');
- checkString(input, '!==');
- buffer.add(') ');
- bailout(node, 'Not a string');
- } else if (node.isArray()) {
- buffer.add('if (');
- checkObject(input, '!==');
- buffer.add('||');
- checkArray(input, '!==');
- buffer.add(') ');
- bailout(node, 'Not an array');
- } else if (node.isStringOrArray()) {
- buffer.add('if (');
- checkString(input, '!==');
- buffer.add(' && (');
- checkObject(input, '!==');
- buffer.add('||');
- checkArray(input, '!==');
- buffer.add(')) ');
- bailout(node, 'Not a string or array');
- } else {
- unreachable();
- }
- buffer.add(';\n');
- }
-
- void beginLoop(HBasicBlock block) {
- addIndentation();
- for (LabelElement label in block.loopInformation.labels) {
- writeLabel(label);
- buffer.add(":");
- }
- buffer.add('while (true) {\n');
- indent++;
- }
-
- void endLoop(HBasicBlock block) {
- indent--;
- addIndentation();
- buffer.add('}\n'); // Close 'while' loop.
- }
-
- void handleLoopCondition(HLoopBranch node) {
- buffer.add('if (!');
- use(node.inputs[0], JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add(') break;\n');
- }
-
- void startIf(HIf node) {
- }
-
- void endIf(HIf node) {
- indent--;
- addIndentation();
- buffer.add('}\n');
- }
-
- void startThen(HIf node) {
- addIndentation();
- buffer.add('if (');
- use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE);
- buffer.add(') {\n');
- indent++;
- }
-
- void endThen(HIf node) {
- }
-
- void startElse(HIf node) {
- indent--;
- addIndentation();
- buffer.add('} else {\n');
- indent++;
- }
-
- void endElse(HIf node) {
- }
-}
-
-class SsaUnoptimizedCodeGenerator extends SsaCodeGenerator {
-
- final StringBuffer setup;
- final List<String> labels;
- int labelId = 0;
- int maxBailoutParameters = 0;
-
- SsaUnoptimizedCodeGenerator(compiler, work, parameters, parameterNames)
- : super(compiler, work, parameters, parameterNames),
- setup = new StringBuffer(),
- labels = <String>[];
-
- String pushLabel() {
- String label = 'L${labelId++}';
- labels.addLast(label);
- return label;
- }
-
- String popLabel() {
- return labels.removeLast();
- }
-
- String currentLabel() {
- return labels.last();
- }
-
- void beginGraph(HGraph graph) {
- if (!graph.entry.hasGuards()) return;
- addIndentation();
- buffer.add('switch (state) {\n');
- indent++;
- addIndentation();
- buffer.add('case 0:\n');
- indent++;
-
- // The setup phase of a bailout function sets up the environment for
- // each bailout target. Each bailout target will populate this
- // setup phase. It is put at the beginning of the function.
- setup.add(' switch (state) {\n');
- }
-
- void endGraph(HGraph graph) {
- if (!graph.entry.hasGuards()) return;
- indent--; // Close original case.
- indent--;
- addIndentation();
- buffer.add('}\n'); // Close 'switch'.
- setup.add(' }\n');
- }
-
- // For instructions that reference a guard or a check, we change that
- // reference to the instruction they guard against. Therefore, we must
- // use that instruction when restoring the environment.
- HInstruction unwrap(HInstruction argument) {
- if (argument is HIntegerCheck) {
- HIntegerCheck instruction = argument;
- return unwrap(instruction.value);
- } else if (argument is HBoundsCheck) {
- HBoundsCheck instruction = argument;
- return unwrap(instruction.index);
- } else if (argument is HTypeGuard) {
- HTypeGuard instruction = argument;
- return unwrap(instruction.guarded);
- } else {
- return argument;
- }
- }
-
- void visitTypeGuard(HTypeGuard node) {
- indent--;
- addIndentation();
- buffer.add('case ${node.state}:\n');
- indent++;
- addIndentation();
- buffer.add('state = 0;\n');
-
- setup.add(' case ${node.state}:\n');
- int i = 0;
- for (HInstruction input in node.inputs) {
- HInstruction instruction = unwrap(input);
- setup.add(' ${temporary(instruction)} = env$i;\n');
- i++;
- }
- if (i > maxBailoutParameters) maxBailoutParameters = i;
- setup.add(' break;\n');
- }
-
- void startBailoutCase(List<HTypeGuard> bailouts1,
- List<HTypeGuard> bailouts2) {
- indent--;
- handleBailoutCase(bailouts1);
- handleBailoutCase(bailouts2);
- indent++;
- }
-
- void handleBailoutCase(List<HTypeGuard> guards) {
- for (int i = 0, len = guards.length; i < len; i++) {
- addIndentation();
- buffer.add('case ${guards[i].state}:\n');
- }
- }
-
- void startBailoutSwitch() {
- addIndentation();
- buffer.add('switch (state) {\n');
- indent++;
- addIndentation();
- buffer.add('case 0:\n');
- indent++;
- }
-
- void endBailoutSwitch() {
- indent--; // Close 'case'.
- indent--;
- addIndentation();
- buffer.add('}\n'); // Close 'switch'.
- }
-
-
- void beginLoop(HBasicBlock block) {
- // TODO(ngeoffray): Don't put labels on loops that don't bailout.
- String newLabel = pushLabel();
- if (block.hasGuards()) {
- startBailoutCase(block.guards, const <HTypeGuard>[]);
- }
-
- addIndentation();
- for (SourceString label in block.loopInformation.labels) {
- writeLabel(label);
- buffer.add(":");
- }
- buffer.add('$newLabel: while (true) {\n');
- indent++;
-
- if (block.hasGuards()) {
- startBailoutSwitch();
- }
- }
-
- void endLoop(HBasicBlock block) {
- popLabel();
- HBasicBlock header = block.isLoopHeader() ? block : block.parentLoopHeader;
- if (header.hasGuards()) {
- endBailoutSwitch();
- }
- indent--;
- addIndentation();
- buffer.add('}\n'); // Close 'while'.
- }
-
- void handleLoopCondition(HLoopBranch node) {
- buffer.add('if (!');
- use(node.inputs[0], JSPrecedence.PREFIX_PRECEDENCE);
- buffer.add(') break ${currentLabel()};\n');
- }
-
- void startIf(HIf node) {
- bool hasGuards = node.thenBlock.hasGuards()
- || (node.hasElse && node.elseBlock.hasGuards());
- if (hasGuards) {
- startBailoutCase(node.thenBlock.guards,
- node.hasElse ? node.elseBlock.guards : const <HTypeGuard>[]);
- }
- }
-
- void endIf(HIf node) {
- indent--;
- addIndentation();
- buffer.add('}\n');
- }
-
- void startThen(HIf node) {
- addIndentation();
- bool hasGuards = node.thenBlock.hasGuards()
- || (node.hasElse && node.elseBlock.hasGuards());
- buffer.add('if (');
- int precedence = JSPrecedence.EXPRESSION_PRECEDENCE;
- if (hasGuards) {
- // TODO(ngeoffray): Put the condition initialization in the
- // [setup] buffer.
- List<HTypeGuard> guards = node.thenBlock.guards;
- for (int i = 0, len = guards.length; i < len; i++) {
- buffer.add('state == ${guards[i].state} || ');
- }
- buffer.add('(state == 0 && ');
- precedence = JSPrecedence.BITWISE_OR_PRECEDENCE;
- }
- use(node.inputs[0], precedence);
- if (hasGuards) {
- buffer.add(')');
- }
- buffer.add(') {\n');
- indent++;
- if (node.thenBlock.hasGuards()) {
- startBailoutSwitch();
- }
- }
-
- void endThen(HIf node) {
- if (node.thenBlock.hasGuards()) {
- endBailoutSwitch();
- }
- }
-
- void startElse(HIf node) {
- indent--;
- addIndentation();
- buffer.add('} else {\n');
- indent++;
- if (node.elseBlock.hasGuards()) {
- startBailoutSwitch();
- }
- }
-
- void endElse(HIf node) {
- if (node.elseBlock.hasGuards()) {
- endBailoutSwitch();
- }
- }
-}
« no previous file with comments | « frog/leg/ssa/closure.dart ('k') | frog/leg/ssa/codegen_helpers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698