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

Side by Side 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, 8 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
« no previous file with comments | « frog/leg/ssa/closure.dart ('k') | frog/leg/ssa/codegen_helpers.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 class SsaCodeGeneratorTask extends CompilerTask {
6 SsaCodeGeneratorTask(Compiler compiler) : super(compiler);
7 String get name() => 'SSA code generator';
8
9
10 String generateMethod(WorkItem work, HGraph graph) {
11 return measure(() {
12 compiler.tracer.traceGraph("codegen", graph);
13 Map<Element, String> parameterNames = getParameterNames(work);
14 String parameters = Strings.join(parameterNames.getValues(), ', ');
15 SsaOptimizedCodeGenerator codegen = new SsaOptimizedCodeGenerator(
16 compiler, work, parameters, parameterNames);
17 codegen.visitGraph(graph);
18 return 'function($parameters) {\n${codegen.buffer}}';
19 });
20 }
21
22 String generateBailoutMethod(WorkItem work, HGraph graph) {
23 return measure(() {
24 compiler.tracer.traceGraph("codegen-bailout", graph);
25 new SsaBailoutPropagator(compiler).visitGraph(graph);
26
27 Map<Element, String> parameterNames = getParameterNames(work);
28 String parameters = Strings.join(parameterNames.getValues(), ', ');
29 SsaUnoptimizedCodeGenerator codegen = new SsaUnoptimizedCodeGenerator(
30 compiler, work, parameters, parameterNames);
31 codegen.visitGraph(graph);
32
33 StringBuffer newParameters = new StringBuffer();
34 if (!parameterNames.isEmpty()) newParameters.add('$parameters, ');
35 newParameters.add('state');
36
37 for (int i = 0; i < codegen.maxBailoutParameters; i++) {
38 newParameters.add(', env$i');
39 }
40
41 return 'function($newParameters) {\n${codegen.setup}${codegen.buffer}}';
42 });
43 }
44
45 Map<Element, String> getParameterNames(WorkItem work) {
46 Map<Element, String> parameterNames = new LinkedHashMap<Element, String>();
47 FunctionElement function = work.element;
48
49 // The dom/html libraries have inline JS code that reference
50 // parameter names directly. Long-term such code will be rejected.
51 // Now, just don't mangle the parameter name.
52 function.computeParameters(compiler).forEachParameter((Element element) {
53 parameterNames[element] = function.isNative()
54 ? element.name.slowToString()
55 : JsNames.getValid('${element.name.slowToString()}');
56 });
57 return parameterNames;
58 }
59 }
60
61 typedef void ElementAction(Element element);
62
63 class SsaCodeGenerator implements HVisitor {
64 final Compiler compiler;
65 final WorkItem work;
66 final StringBuffer buffer;
67 final String parameters;
68
69 final Map<Element, String> parameterNames;
70 final Map<int, String> names;
71 final Map<String, int> prefixes;
72 final Set<HInstruction> generateAtUseSite;
73 final Map<HPhi, String> logicalOperations;
74 final Map<Element, ElementAction> breakAction;
75 final Map<Element, ElementAction> continueAction;
76
77 Element equalsNullElement;
78 int indent = 0;
79 int expectedPrecedence = JSPrecedence.STATEMENT_PRECEDENCE;
80 HGraph currentGraph;
81 HBasicBlock currentBlock;
82
83 // Records a block-information that is being handled specially.
84 // Used to break bad recursion.
85 HLabeledBlockInformation currentBlockInformation;
86 // The subgraph is used to delimit traversal for some constructions, e.g.,
87 // if branches.
88 SubGraph subGraph;
89
90 LibraryElement get currentLibrary() => work.element.getLibrary();
91
92 bool isGenerateAtUseSite(HInstruction instruction) {
93 return generateAtUseSite.contains(instruction);
94 }
95
96 SsaCodeGenerator(this.compiler,
97 this.work,
98 this.parameters,
99 this.parameterNames)
100 : names = new Map<int, String>(),
101 prefixes = new Map<String, int>(),
102 buffer = new StringBuffer(),
103 generateAtUseSite = new Set<HInstruction>(),
104 logicalOperations = new Map<HPhi, String>(),
105 breakAction = new Map<Element, ElementAction>(),
106 continueAction = new Map<Element, ElementAction>() {
107
108 for (final name in parameterNames.getValues()) {
109 prefixes[name] = 0;
110 }
111
112 equalsNullElement =
113 compiler.builder.interceptors.getEqualsNullInterceptor();
114 }
115
116 abstract visitTypeGuard(HTypeGuard node);
117
118 abstract beginGraph(HGraph graph);
119 abstract endGraph(HGraph graph);
120
121 abstract beginLoop(HBasicBlock block);
122 abstract endLoop(HBasicBlock block);
123 abstract handleLoopCondition(HLoopBranch node);
124
125 abstract startIf(HIf node);
126 abstract endIf(HIf node);
127 abstract startThen(HIf node);
128 abstract endThen(HIf node);
129 abstract startElse(HIf node);
130 abstract endElse(HIf node);
131
132 void beginExpression(int precedence) {
133 if (precedence < expectedPrecedence) {
134 buffer.add('(');
135 }
136 }
137
138 void endExpression(int precedence) {
139 if (precedence < expectedPrecedence) {
140 buffer.add(')');
141 }
142 }
143
144 void preGenerateMethod(HGraph graph) {
145 new SsaInstructionMerger(generateAtUseSite).visitGraph(graph);
146 new SsaConditionMerger(generateAtUseSite,
147 logicalOperations).visitGraph(graph);
148 }
149
150 visitGraph(HGraph graph) {
151 preGenerateMethod(graph);
152 currentGraph = graph;
153 indent++; // We are already inside a function.
154 subGraph = new SubGraph(graph.entry, graph.exit);
155 beginGraph(graph);
156 visitBasicBlock(graph.entry);
157 endGraph(graph);
158 }
159
160 void visitSubGraph(SubGraph newSubGraph) {
161 SubGraph oldSubGraph = subGraph;
162 subGraph = newSubGraph;
163 visitBasicBlock(subGraph.start);
164 subGraph = oldSubGraph;
165 }
166
167 String temporary(HInstruction instruction) {
168 int id = instruction.id;
169 String name = names[id];
170 if (name !== null) return name;
171
172 if (instruction is HPhi) {
173 HPhi phi = instruction;
174 Element element = phi.element;
175 if (element != null && element.kind == ElementKind.PARAMETER) {
176 name = parameterNames[element];
177 names[id] = name;
178 return name;
179 }
180
181 String prefix;
182 if (element !== null && !element.name.isEmpty()) {
183 prefix = element.name.slowToString();
184 } else {
185 prefix = 'v';
186 }
187 if (!prefixes.containsKey(prefix)) {
188 prefixes[prefix] = 0;
189 return newName(id, prefix);
190 } else {
191 return newName(id, '${prefix}_${prefixes[prefix]++}');
192 }
193 } else {
194 String prefix = 't';
195 if (!prefixes.containsKey(prefix)) prefixes[prefix] = 0;
196 return newName(id, '${prefix}${prefixes[prefix]++}');
197 }
198 }
199
200 bool temporaryExists(HInstruction instruction) {
201 return names.containsKey(instruction.id);
202 }
203
204 String newName(int id, String name) {
205 String result = JsNames.getValid(name);
206 names[id] = result;
207 return result;
208 }
209
210 /**
211 * Only visits the arguments starting at inputs[HInvoke.ARGUMENTS_OFFSET].
212 */
213 void visitArguments(List<HInstruction> inputs) {
214 assert(inputs.length >= HInvoke.ARGUMENTS_OFFSET);
215 buffer.add('(');
216 for (int i = HInvoke.ARGUMENTS_OFFSET; i < inputs.length; i++) {
217 if (i != HInvoke.ARGUMENTS_OFFSET) buffer.add(', ');
218 use(inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE);
219 }
220 buffer.add(')');
221 }
222
223 void define(HInstruction instruction) {
224 buffer.add('var ${temporary(instruction)} = ');
225 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE);
226 }
227
228 void use(HInstruction argument, int expectedPrecedence) {
229 if (isGenerateAtUseSite(argument)) {
230 visit(argument, expectedPrecedence);
231 } else if (argument is HIntegerCheck) {
232 HIntegerCheck instruction = argument;
233 use(instruction.value, expectedPrecedence);
234 } else if (argument is HBoundsCheck) {
235 HBoundsCheck instruction = argument;
236 use(instruction.index, expectedPrecedence);
237 } else if (argument is HTypeGuard) {
238 HTypeGuard instruction = argument;
239 use(instruction.guarded, expectedPrecedence);
240 } else {
241 buffer.add(temporary(argument));
242 }
243 }
244
245 visit(HInstruction node, int expectedPrecedence) {
246 int oldPrecedence = this.expectedPrecedence;
247 this.expectedPrecedence = expectedPrecedence;
248 node.accept(this);
249 this.expectedPrecedence = oldPrecedence;
250 }
251
252 void continueAsBreak(LabelElement target) {
253 addIndentation();
254 buffer.add("break ");
255 writeContinueLabel(target);
256 buffer.add(";\n");
257 }
258
259 void implicitContinueAsBreak(TargetElement target) {
260 addIndentation();
261 buffer.add("break ");
262 writeImplicitContinueLabel(target);
263 buffer.add(";\n");
264 }
265
266 void implicitBreakWithLabel(TargetElement target) {
267 addIndentation();
268 buffer.add("break ");
269 writeImplicitLabel(target);
270 buffer.add(";\n");
271 }
272
273 void handleLabeledBlock(HLabeledBlockInformation labeledBlockInfo) {
274 addIndentation();
275 Link<Element> continueOverrides = const EmptyLink<Element>();
276 // If [labeledBlockInfo.isContinue], the block is an artificial
277 // block around the body of a loop with an update block, so that
278 // continues of the loop can be written as breaks of the body
279 // block.
280 if (labeledBlockInfo.isContinue) {
281 for (LabelElement label in labeledBlockInfo.labels) {
282 if (label.isContinueTarget) {
283 writeContinueLabel(label);
284 buffer.add(':');
285 continueAction[label] = continueAsBreak;
286 continueOverrides = continueOverrides.prepend(label);
287 }
288 }
289 // For handling unlabeled continues from the body of a loop.
290 // TODO(lrn): Consider recording whether the target is in fact
291 // a target of an unlabeled continue, and not generate this if it isn't.
292 TargetElement target = labeledBlockInfo.target;
293 writeImplicitContinueLabel(target);
294 buffer.add(':');
295 continueAction[target] = implicitContinueAsBreak;
296 continueOverrides = continueOverrides.prepend(target);
297 } else {
298 for (LabelElement label in labeledBlockInfo.labels) {
299 if (label.isBreakTarget) {
300 writeLabel(label);
301 buffer.add(':');
302 }
303 }
304 TargetElement target = labeledBlockInfo.target;
305 if (target.isSwitch) {
306 // This is an extra block around a switch that is generated
307 // as a nested if/else chain. We add an extra break target
308 // so that case code can break.
309 writeImplicitLabel(target);
310 buffer.add(':');
311 breakAction[target] = implicitBreakWithLabel;
312 }
313 }
314 buffer.add('{\n');
315 indent++;
316
317 visitSubGraph(labeledBlockInfo.body);
318
319 indent--;
320 addIndentation();
321 buffer.add('}\n');
322
323 if (labeledBlockInfo.joinBlock !== null) {
324 visitBasicBlock(labeledBlockInfo.joinBlock);
325 }
326 if (labeledBlockInfo.isContinue) {
327 while (!continueOverrides.isEmpty()) {
328 continueAction.remove(continueOverrides.head);
329 continueOverrides = continueOverrides.tail;
330 }
331 } else {
332 breakAction.remove(labeledBlockInfo.target);
333 }
334 }
335
336 void emitLogicalOperation(HPhi node, String operation) {
337 JSBinaryOperatorPrecedence operatorPrecedence =
338 JSPrecedence.binary[operation];
339 beginExpression(operatorPrecedence.precedence);
340 use(node.inputs[0], operatorPrecedence.left);
341 buffer.add(" $operation ");
342 use(node.inputs[1], operatorPrecedence.right);
343 endExpression(operatorPrecedence.precedence);
344 }
345
346 visitBasicBlock(HBasicBlock node) {
347 // Abort traversal if we are leaving the currently active sub-graph.
348 if (!subGraph.contains(node)) return;
349
350 // If this node has special behavior attached, handle it.
351 // If we reach here again while handling the attached information,
352 // e.g., because we call visitSubGraph on a subgraph starting here,
353 // don't handle it again.
354 if (node.hasLabeledBlockInformation() &&
355 node.labeledBlockInformation !== currentBlockInformation) {
356 HLabeledBlockInformation oldBlockInformation = currentBlockInformation;
357 currentBlockInformation = node.labeledBlockInformation;
358 handleLabeledBlock(currentBlockInformation);
359 currentBlockInformation = oldBlockInformation;
360 return;
361 }
362
363 currentBlock = node;
364
365 if (node.isLoopHeader()) {
366 // While loop will be closed by the conditional loop-branch.
367 // TODO(floitsch): HACK HACK HACK.
368 beginLoop(node);
369 }
370
371 HInstruction instruction = node.first;
372 while (instruction != null) {
373 if (instruction === node.last) {
374 for (HBasicBlock successor in node.successors) {
375 int index = successor.predecessors.indexOf(node);
376 successor.forEachPhi((HPhi phi) {
377 bool isLogicalOperation = logicalOperations.containsKey(phi);
378 // In case the phi is being generated by another
379 // instruction.
380 if (isLogicalOperation && isGenerateAtUseSite(phi)) return;
381 addIndentation();
382 if (!temporaryExists(phi)) buffer.add('var ');
383 buffer.add('${temporary(phi)} = ');
384 if (isLogicalOperation) {
385 emitLogicalOperation(phi, logicalOperations[phi]);
386 } else {
387 use(phi.inputs[index], JSPrecedence.ASSIGNMENT_PRECEDENCE);
388 }
389 buffer.add(';\n');
390 });
391 }
392 }
393
394 if (instruction is HGoto || instruction is HExit || instruction is HTry) {
395 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE);
396 return;
397 } else if (!isGenerateAtUseSite(instruction)) {
398 if (instruction is !HIf && instruction is !HTypeGuard) {
399 addIndentation();
400 }
401 if (instruction.usedBy.isEmpty()
402 || instruction is HTypeGuard
403 || instruction is HCheck) {
404 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE);
405 } else {
406 define(instruction);
407 }
408 // Control flow instructions know how to handle ';'.
409 if (instruction is !HControlFlow && instruction is !HTypeGuard) {
410 buffer.add(';\n');
411 }
412 } else if (instruction is HIf) {
413 HIf hif = instruction;
414 // The "if" is implementing part of a logical expression.
415 // Skip directly forward to to its latest successor, since everything
416 // in-between must also be generateAtUseSite.
417 assert(hif.trueBranch.id < hif.falseBranch.id);
418 visitBasicBlock(hif.falseBranch);
419 return;
420 }
421 instruction = instruction.next;
422 }
423 }
424
425 visitInvokeBinary(HInvokeBinary node, String op) {
426 if (node.builtin) {
427 JSBinaryOperatorPrecedence operatorPrecedences = JSPrecedence.binary[op];
428 beginExpression(operatorPrecedences.precedence);
429 use(node.left, operatorPrecedences.left);
430 buffer.add(' $op ');
431 use(node.right, operatorPrecedences.right);
432 endExpression(operatorPrecedences.precedence);
433 } else {
434 visitInvokeStatic(node);
435 }
436 }
437
438 visitInvokeUnary(HInvokeUnary node, String op) {
439 if (node.builtin) {
440 beginExpression(JSPrecedence.PREFIX_PRECEDENCE);
441 buffer.add('$op');
442 use(node.operand, JSPrecedence.PREFIX_PRECEDENCE);
443 endExpression(JSPrecedence.PREFIX_PRECEDENCE);
444 } else {
445 visitInvokeStatic(node);
446 }
447 }
448
449 visitEquals(HEquals node) {
450 if (node.builtin) {
451 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
452 use(node.left, JSPrecedence.EQUALITY_PRECEDENCE);
453 buffer.add(' === ');
454 use(node.right, JSPrecedence.RELATIONAL_PRECEDENCE);
455 endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
456 } else if (node.element === equalsNullElement) {
457 beginExpression(JSPrecedence.CALL_PRECEDENCE);
458 use(node.target, JSPrecedence.CALL_PRECEDENCE);
459 buffer.add('(');
460 use(node.left, JSPrecedence.ASSIGNMENT_PRECEDENCE);
461 buffer.add(')');
462 endExpression(JSPrecedence.CALL_PRECEDENCE);
463 } else {
464 visitInvokeStatic(node);
465 }
466 }
467
468 visitAdd(HAdd node) => visitInvokeBinary(node, '+');
469 visitDivide(HDivide node) => visitInvokeBinary(node, '/');
470 visitMultiply(HMultiply node) => visitInvokeBinary(node, '*');
471 visitSubtract(HSubtract node) => visitInvokeBinary(node, '-');
472 // Truncating divide does not have a JS equivalent.
473 visitTruncatingDivide(HTruncatingDivide node) => visitInvokeStatic(node);
474 // Modulo cannot be mapped to the native operator (different semantics).
475 visitModulo(HModulo node) => visitInvokeStatic(node);
476
477 visitBitAnd(HBitAnd node) => visitInvokeBinary(node, '&');
478 visitBitNot(HBitNot node) => visitInvokeUnary(node, '~');
479 visitBitOr(HBitOr node) => visitInvokeBinary(node, '|');
480 visitBitXor(HBitXor node) => visitInvokeBinary(node, '^');
481
482 // We need to check if the left operand is negative in order to use
483 // the native operator.
484 visitShiftRight(HShiftRight node) => visitInvokeStatic(node);
485
486 // Shift left cannot be mapped to the native operator (different semantics).
487 visitShiftLeft(HShiftLeft node) => visitInvokeStatic(node);
488
489 visitNegate(HNegate node) => visitInvokeUnary(node, '-');
490
491 visitIdentity(HIdentity node) => visitInvokeBinary(node, '===');
492 visitLess(HLess node) => visitInvokeBinary(node, '<');
493 visitLessEqual(HLessEqual node) => visitInvokeBinary(node, '<=');
494 visitGreater(HGreater node) => visitInvokeBinary(node, '>');
495 visitGreaterEqual(HGreaterEqual node) => visitInvokeBinary(node, '>=');
496
497 visitBoolify(HBoolify node) {
498 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
499 assert(node.inputs.length == 1);
500 use(node.inputs[0], JSPrecedence.EQUALITY_PRECEDENCE);
501 buffer.add(' === true');
502 endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
503 }
504
505 visitExit(HExit node) {
506 // Don't do anything.
507 }
508
509 visitGoto(HGoto node) {
510 assert(currentBlock.successors.length == 1);
511 List<HBasicBlock> dominated = currentBlock.dominatedBlocks;
512 // With the exception of the entry-node which dominates its successor
513 // and the exit node, no block finishing with a 'goto' can have more than
514 // one dominated block (since it has only one successor).
515 // If the successor is dominated by another block, then the other block
516 // is responsible for visiting the successor.
517 if (dominated.isEmpty()) return;
518 if (dominated.length > 2) unreachable();
519 if (dominated.length == 2 && currentBlock !== currentGraph.entry) {
520 unreachable();
521 }
522 assert(dominated[0] == currentBlock.successors[0]);
523 visitBasicBlock(dominated[0]);
524 }
525
526 // Used to write the name of labels.
527 void writeLabel(LabelElement label) {
528 buffer.add('\$${label.labelName}\$${label.target.nestingLevel}');
529 }
530
531 void writeImplicitLabel(TargetElement target) {
532 buffer.add('\$${target.nestingLevel}');
533 }
534
535 // We sometimes handle continue targets differently from break targets,
536 // so we have special continue-only labels.
537 void writeContinueLabel(LabelElement label) {
538 buffer.add('c\$${label.labelName}\$${label.target.nestingLevel}');
539 }
540
541 void writeImplicitContinueLabel(TargetElement target) {
542 buffer.add('c\$${target.nestingLevel}');
543 }
544
545 /**
546 * Checks if [map] contains an [ElementAction] for [element], and
547 * if so calls that action and returns true.
548 * Otherwise returns false.
549 */
550 bool tryCallAction(Map<Element, ElementAction> map, Element element) {
551 ElementAction action = map[element];
552 if (action === null) return false;
553 action(element);
554 return true;
555 }
556
557 visitBreak(HBreak node) {
558 assert(currentBlock.successors.length == 1);
559 if (node.label !== null) {
560 LabelElement label = node.label;
561 if (!tryCallAction(breakAction, label)) {
562 addIndentation();
563 buffer.add("break ");
564 writeLabel(label);
565 buffer.add(";\n");
566 }
567 } else {
568 TargetElement target = node.target;
569 if (!tryCallAction(breakAction, target)) {
570 addIndentation();
571 buffer.add("break;\n");
572 }
573 }
574 }
575
576 visitContinue(HContinue node) {
577 assert(currentBlock.successors.length == 1);
578 if (node.label !== null) {
579 LabelElement label = node.label;
580 if (!tryCallAction(continueAction, label)) {
581 addIndentation();
582 buffer.add("continue ");
583 writeLabel(label);
584 buffer.add(";\n");
585 }
586 } else {
587 TargetElement target = node.target;
588 if (!tryCallAction(continueAction, target)) {
589 addIndentation();
590 buffer.add("continue;\n");
591 }
592 }
593 }
594
595 visitTry(HTry node) {
596 addIndentation();
597 buffer.add('try {\n');
598 indent++;
599 List<HBasicBlock> successors = node.block.successors;
600 visitBasicBlock(successors[0]);
601 indent--;
602
603 if (node.finallyBlock != successors[1]) {
604 // Printing the catch part.
605 addIndentation();
606 String name = temporary(node.exception);
607 parameterNames[node.exception.element] = name;
608 buffer.add('} catch ($name) {\n');
609 indent++;
610 visitBasicBlock(successors[1]);
611 parameterNames.remove(node.exception.element);
612 indent--;
613 }
614
615 if (node.finallyBlock != null) {
616 addIndentation();
617 buffer.add('} finally {\n');
618 indent++;
619 visitBasicBlock(node.finallyBlock);
620 indent--;
621 }
622 addIndentation();
623 buffer.add('}\n');
624
625 visitBasicBlock(node.joinBlock);
626 }
627
628 visitIf(HIf node) {
629 List<HBasicBlock> dominated = node.block.dominatedBlocks;
630 HIfBlockInformation info = node.blockInformation;
631 startIf(node);
632 assert(!isGenerateAtUseSite(node));
633 startThen(node);
634 assert(node.thenBlock === dominated[0]);
635 visitSubGraph(info.thenGraph);
636 int preVisitedBlocks = 1;
637 endThen(node);
638 if (node.hasElse) {
639 startElse(node);
640 assert(node.elseBlock === dominated[1]);
641 visitSubGraph(info.elseGraph);
642 preVisitedBlocks = 2;
643 endElse(node);
644 }
645 endIf(node);
646 if (info.joinBlock !== null && info.joinBlock.dominator !== node.block) {
647 // The join block is dominated by a block in one of the branches.
648 // The subgraph traversal never reached it, so we visit it here
649 // instead.
650 visitBasicBlock(info.joinBlock);
651 }
652
653 // Visit all the dominated blocks that are not part of the then or else
654 // branches, and is not the join block.
655 // Depending on how the then/else branches terminate
656 // (e.g., return/throw/break) there can be any number of these.
657 int dominatedCount = dominated.length;
658 for (int i = preVisitedBlocks; i < dominatedCount; i++) {
659 HBasicBlock dominatedBlock = dominated[i];
660 assert(dominatedBlock.dominator === node.block);
661 visitBasicBlock(dominatedBlock);
662 }
663 }
664
665 visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
666 beginExpression(JSPrecedence.CALL_PRECEDENCE);
667 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
668 buffer.add('.');
669 // Avoid adding the generative constructor name to the list of
670 // seen selectors.
671 if (node.inputs[0] is HForeignNew) {
672 HForeignNew foreignNew = node.inputs[0];
673 // Remove 'this' from the number of arguments.
674 int argumentCount = node.inputs.length - 1;
675
676 // TODO(ahe): The constructor name was statically resolved in
677 // SsaBuilder.buildFactory. Is there a cleaner way to do this?
678 node.name.printOn(buffer);
679 visitArguments(node.inputs);
680 } else {
681 buffer.add(compiler.namer.instanceMethodInvocationName(
682 currentLibrary, node.name, node.selector));
683 visitArguments(node.inputs);
684 compiler.registerDynamicInvocation(node.name, node.selector);
685 }
686 endExpression(JSPrecedence.CALL_PRECEDENCE);
687 }
688
689 visitInvokeDynamicSetter(HInvokeDynamicSetter node) {
690 beginExpression(JSPrecedence.CALL_PRECEDENCE);
691 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
692 buffer.add('.');
693 buffer.add(compiler.namer.setterName(currentLibrary, node.name));
694 visitArguments(node.inputs);
695 compiler.registerDynamicSetter(node.name);
696 endExpression(JSPrecedence.CALL_PRECEDENCE);
697 }
698
699 visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
700 beginExpression(JSPrecedence.CALL_PRECEDENCE);
701 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
702 buffer.add('.');
703 buffer.add(compiler.namer.getterName(currentLibrary, node.name));
704 visitArguments(node.inputs);
705 compiler.registerDynamicGetter(node.name);
706 endExpression(JSPrecedence.CALL_PRECEDENCE);
707 }
708
709 visitInvokeClosure(HInvokeClosure node) {
710 beginExpression(JSPrecedence.CALL_PRECEDENCE);
711 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
712 buffer.add('.');
713 buffer.add(compiler.namer.closureInvocationName(node.selector));
714 visitArguments(node.inputs);
715 // TODO(floitsch): we should have a separate list for closure invocations.
716 compiler.registerDynamicInvocation(Namer.CLOSURE_INVOCATION_NAME,
717 node.selector);
718 endExpression(JSPrecedence.CALL_PRECEDENCE);
719 }
720
721 visitInvokeStatic(HInvokeStatic node) {
722 beginExpression(JSPrecedence.CALL_PRECEDENCE);
723 use(node.target, JSPrecedence.CALL_PRECEDENCE);
724 visitArguments(node.inputs);
725 endExpression(JSPrecedence.CALL_PRECEDENCE);
726 }
727
728 visitInvokeSuper(HInvokeSuper node) {
729 beginExpression(JSPrecedence.CALL_PRECEDENCE);
730 Element superMethod = node.element;
731 Element superClass = superMethod.enclosingElement;
732 // Remove the element and 'this'.
733 int argumentCount = node.inputs.length - 2;
734 String className = compiler.namer.isolatePropertyAccess(superClass);
735 String methodName;
736 if (superMethod.kind == ElementKind.FUNCTION ||
737 superMethod.kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
738 methodName = compiler.namer.instanceMethodName(
739 currentLibrary, superMethod.name, argumentCount);
740 } else {
741 methodName = compiler.namer.getterName(currentLibrary, superMethod.name);
742 // We need to register the name to ensure that the emitter
743 // generates the necessary getter.
744 // TODO(ahe): This is not optimal for tree-shaking, but we lack
745 // API to register the precise information. In this case, the
746 // enclosingElement of superMethod needs the getter, no other
747 // class (not even its subclasses).
748 compiler.registerDynamicGetter(superMethod.name);
749 }
750 buffer.add('$className.prototype.$methodName.call');
751 visitArguments(node.inputs);
752 endExpression(JSPrecedence.CALL_PRECEDENCE);
753 compiler.registerStaticUse(superMethod);
754 }
755
756 visitFieldGet(HFieldGet node) {
757 String name = JsNames.getValid(node.element.name.slowToString());
758 if (node.receiver !== null) {
759 beginExpression(JSPrecedence.MEMBER_PRECEDENCE);
760 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
761 buffer.add('.');
762 buffer.add(name);
763 beginExpression(JSPrecedence.MEMBER_PRECEDENCE);
764 } else {
765 buffer.add(name);
766 }
767 }
768
769 visitFieldSet(HFieldSet node) {
770 if (node.receiver !== null) {
771 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
772 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE);
773 buffer.add('.');
774 } else {
775 // TODO(ngeoffray): Remove the 'var' once we don't globally box
776 // variables used in a try/catch.
777 buffer.add('var ');
778 }
779 String name = JsNames.getValid(node.element.name.slowToString());
780 buffer.add(name);
781 buffer.add(' = ');
782 use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE);
783 if (node.receiver !== null) {
784 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
785 }
786 }
787
788 visitForeign(HForeign node) {
789 String code = node.code.slowToString();
790 List<HInstruction> inputs = node.inputs;
791 List<String> parts = code.split('#');
792 if (parts.length != inputs.length + 1) {
793 compiler.internalError(
794 'Wrong number of arguments for JS', instruction: node);
795 }
796 beginExpression(JSPrecedence.EXPRESSION_PRECEDENCE);
797 buffer.add(parts[0]);
798 for (int i = 0; i < inputs.length; i++) {
799 use(inputs[i], JSPrecedence.EXPRESSION_PRECEDENCE);
800 buffer.add(parts[i + 1]);
801 }
802 endExpression(JSPrecedence.EXPRESSION_PRECEDENCE);
803 }
804
805 visitForeignNew(HForeignNew node) {
806 String jsClassReference = compiler.namer.isolateAccess(node.element);
807 beginExpression(JSPrecedence.MEMBER_PRECEDENCE);
808 buffer.add('new $jsClassReference(');
809 // We can't use 'visitArguments', since our arguments start at input[0].
810 List<HInstruction> inputs = node.inputs;
811 for (int i = 0; i < inputs.length; i++) {
812 if (i != 0) buffer.add(', ');
813 use(inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE);
814 }
815 buffer.add(')');
816 endExpression(JSPrecedence.MEMBER_PRECEDENCE);
817 }
818
819 visitConstant(HConstant node) {
820 assert(isGenerateAtUseSite(node));
821 // TODO(floitsch): the compile-time constant handler and the codegen
822 // need to work together to avoid the parenthesis. See r4928 for an
823 // implementation that still dealt with precedence.
824 ConstantHandler handler = compiler.constantHandler;
825 String name = handler.getNameForConstant(node.constant);
826 if (name === null) {
827 assert(!node.constant.isObject());
828 if (node.constant.isNum()
829 && expectedPrecedence == JSPrecedence.MEMBER_PRECEDENCE) {
830 buffer.add('(');
831 node.constant.writeJsCode(buffer, handler);
832 buffer.add(')');
833 } else {
834 node.constant.writeJsCode(buffer, handler);
835 }
836 } else {
837 buffer.add(compiler.namer.CURRENT_ISOLATE);
838 buffer.add(".");
839 buffer.add(name);
840 }
841 }
842
843 visitLoopBranch(HLoopBranch node) {
844 HBasicBlock branchBlock = currentBlock;
845 handleLoopCondition(node);
846 List<HBasicBlock> dominated = currentBlock.dominatedBlocks;
847 // For a do while loop, the body has already been visited.
848 if (!node.isDoWhile()) {
849 visitBasicBlock(dominated[0]);
850 }
851 endLoop(node.block);
852 visitBasicBlock(branchBlock.successors[1]);
853 // With labeled breaks we can have more dominated blocks.
854 if (dominated.length >= 3) {
855 for (int i = 2; i < dominated.length; i++) {
856 visitBasicBlock(dominated[i]);
857 }
858 }
859 }
860
861 visitNot(HNot node) {
862 assert(node.inputs.length == 1);
863 beginExpression(JSPrecedence.PREFIX_PRECEDENCE);
864 buffer.add('!');
865 use(node.inputs[0], JSPrecedence.PREFIX_PRECEDENCE);
866 endExpression(JSPrecedence.PREFIX_PRECEDENCE);
867 }
868
869 visitParameterValue(HParameterValue node) {
870 assert(isGenerateAtUseSite(node));
871 buffer.add(parameterNames[node.element]);
872 }
873
874 visitPhi(HPhi node) {
875 String operation = logicalOperations[node];
876 if (operation !== null) {
877 emitLogicalOperation(node, operation);
878 } else {
879 buffer.add('${temporary(node)}');
880 }
881 }
882
883 visitReturn(HReturn node) {
884 assert(node.inputs.length == 1);
885 HInstruction input = node.inputs[0];
886 if (input.isConstantNull()) {
887 buffer.add('return;\n');
888 } else {
889 buffer.add('return ');
890 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE);
891 buffer.add(';\n');
892 }
893 }
894
895 visitThis(HThis node) {
896 buffer.add('this');
897 }
898
899 visitThrow(HThrow node) {
900 if (node.isRethrow) {
901 buffer.add('throw ');
902 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE);
903 } else {
904 generateThrowWithHelper('captureStackTrace', node.inputs[0]);
905 }
906 buffer.add(';\n');
907 }
908
909 visitBoundsCheck(HBoundsCheck node) {
910 buffer.add('if (');
911 use(node.index, JSPrecedence.RELATIONAL_PRECEDENCE);
912 buffer.add(' < 0 || ');
913 use(node.index, JSPrecedence.RELATIONAL_PRECEDENCE);
914 buffer.add(' >= ');
915 use(node.length, JSPrecedence.SHIFT_PRECEDENCE);
916 buffer.add(") ");
917 generateThrowWithHelper('ioore', node.index);
918 }
919
920 visitIntegerCheck(HIntegerCheck node) {
921 buffer.add('if (');
922 use(node.value, JSPrecedence.EQUALITY_PRECEDENCE);
923 buffer.add(' !== (');
924 use(node.value, JSPrecedence.BITWISE_OR_PRECEDENCE);
925 buffer.add(" | 0)) ");
926 generateThrowWithHelper('iae', node.value);
927 }
928
929 void generateThrowWithHelper(String helperName, HInstruction argument) {
930 Element helper = compiler.findHelper(new SourceString(helperName));
931 compiler.registerStaticUse(helper);
932 buffer.add('throw ');
933 beginExpression(JSPrecedence.EXPRESSION_PRECEDENCE);
934 beginExpression(JSPrecedence.CALL_PRECEDENCE);
935 buffer.add(compiler.namer.isolateAccess(helper));
936 visitArguments([null, argument]);
937 endExpression(JSPrecedence.CALL_PRECEDENCE);
938 endExpression(JSPrecedence.EXPRESSION_PRECEDENCE);
939 }
940
941 void addIndentation() {
942 for (int i = 0; i < indent; i++) {
943 buffer.add(' ');
944 }
945 }
946
947 void visitStatic(HStatic node) {
948 compiler.registerStaticUse(node.element);
949 buffer.add(compiler.namer.isolateAccess(node.element));
950 }
951
952 void visitStaticStore(HStaticStore node) {
953 compiler.registerStaticUse(node.element);
954 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
955 buffer.add(compiler.namer.isolateAccess(node.element));
956 buffer.add(' = ');
957 use(node.inputs[0], JSPrecedence.ASSIGNMENT_PRECEDENCE);
958 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
959 }
960
961 void visitLiteralList(HLiteralList node) {
962 if (node.isConst) {
963 // TODO(floitsch): Remove this when CTC handles arrays.
964 SourceString name = new SourceString('makeLiteralListConst');
965 Element helper = compiler.findHelper(name);
966 compiler.registerStaticUse(helper);
967 beginExpression(JSPrecedence.CALL_PRECEDENCE);
968 buffer.add(compiler.namer.isolateAccess(helper));
969 buffer.add('(');
970 generateArrayLiteral(node);
971 buffer.add(')');
972 endExpression(JSPrecedence.CALL_PRECEDENCE);
973 } else {
974 generateArrayLiteral(node);
975 }
976 }
977
978 void generateArrayLiteral(HLiteralList node) {
979 buffer.add('[');
980 int len = node.inputs.length;
981 for (int i = 0; i < len; i++) {
982 if (i != 0) buffer.add(', ');
983 use(node.inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE);
984 }
985 buffer.add(']');
986 }
987
988 void visitIndex(HIndex node) {
989 if (node.builtin) {
990 beginExpression(JSPrecedence.MEMBER_PRECEDENCE);
991 use(node.inputs[1], JSPrecedence.MEMBER_PRECEDENCE);
992 buffer.add('[');
993 use(node.inputs[2], JSPrecedence.EXPRESSION_PRECEDENCE);
994 buffer.add(']');
995 endExpression(JSPrecedence.MEMBER_PRECEDENCE);
996 } else {
997 visitInvokeStatic(node);
998 }
999 }
1000
1001 void visitIndexAssign(HIndexAssign node) {
1002 if (node.builtin) {
1003 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
1004 use(node.inputs[1], JSPrecedence.MEMBER_PRECEDENCE);
1005 buffer.add('[');
1006 use(node.inputs[2], JSPrecedence.EXPRESSION_PRECEDENCE);
1007 buffer.add('] = ');
1008 use(node.inputs[3], JSPrecedence.ASSIGNMENT_PRECEDENCE);
1009 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE);
1010 } else {
1011 visitInvokeStatic(node);
1012 }
1013 }
1014
1015 void visitInvokeInterceptor(HInvokeInterceptor node) {
1016 if (node.builtinJsName != null) {
1017 beginExpression(JSPrecedence.CALL_PRECEDENCE);
1018 use(node.inputs[1], JSPrecedence.MEMBER_PRECEDENCE);
1019 buffer.add('.');
1020 buffer.add(node.builtinJsName);
1021 if (node.getter) return;
1022 buffer.add('(');
1023 for (int i = 2; i < node.inputs.length; i++) {
1024 if (i != 2) buffer.add(', ');
1025 use(node.inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE);
1026 }
1027 buffer.add(")");
1028 endExpression(JSPrecedence.CALL_PRECEDENCE);
1029 } else {
1030 return visitInvokeStatic(node);
1031 }
1032 }
1033
1034 void checkInt(HInstruction input, String cmp) {
1035 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1036 use(input, JSPrecedence.EQUALITY_PRECEDENCE);
1037 buffer.add(' $cmp (');
1038 use(input, JSPrecedence.BITWISE_OR_PRECEDENCE);
1039 buffer.add(' | 0)');
1040 endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1041 }
1042
1043 void checkNum(HInstruction input, String cmp) {
1044 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1045 buffer.add('typeof ');
1046 use(input, JSPrecedence.PREFIX_PRECEDENCE);
1047 buffer.add(" $cmp 'number'");
1048 endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1049 }
1050
1051 void checkDouble(HInstruction input, String cmp) {
1052 checkNum(input, cmp);
1053 }
1054
1055 void checkString(HInstruction input, String cmp) {
1056 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1057 buffer.add('typeof ');
1058 use(input, JSPrecedence.PREFIX_PRECEDENCE);
1059 buffer.add(" $cmp 'string'");
1060 endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1061 }
1062
1063 void checkBool(HInstruction input, String cmp) {
1064 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1065 buffer.add('typeof ');
1066 use(input, JSPrecedence.PREFIX_PRECEDENCE);
1067 buffer.add(" $cmp 'boolean'");
1068 endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1069 }
1070
1071 void checkObject(HInstruction input, String cmp) {
1072 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1073 buffer.add('typeof ');
1074 use(input, JSPrecedence.PREFIX_PRECEDENCE);
1075 buffer.add(" $cmp 'object'");
1076 endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1077 }
1078
1079 void checkArray(HInstruction input, String cmp) {
1080 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1081 use(input, JSPrecedence.MEMBER_PRECEDENCE);
1082 buffer.add('.constructor $cmp Array');
1083 endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1084 }
1085
1086 void checkNull(HInstruction input) {
1087 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1088 use(input, JSPrecedence.EQUALITY_PRECEDENCE);
1089 buffer.add(" === (void 0)");
1090 endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1091 }
1092
1093 void checkFunction(HInstruction input, Element element) {
1094 beginExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
1095 beginExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1096 buffer.add('typeof ');
1097 use(input, JSPrecedence.PREFIX_PRECEDENCE);
1098 buffer.add(" === 'function'");
1099 endExpression(JSPrecedence.EQUALITY_PRECEDENCE);
1100 buffer.add(" || ");
1101 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
1102 checkObject(input, '===');
1103 buffer.add(" && ");
1104 checkType(input, element);
1105 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
1106 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
1107 }
1108
1109 void checkType(HInstruction input, Element element) {
1110 bool requiresNativeIsCheck =
1111 compiler.emitter.nativeEmitter.requiresNativeIsCheck(element);
1112 if (!requiresNativeIsCheck) buffer.add('!!');
1113 use(input, JSPrecedence.MEMBER_PRECEDENCE);
1114 buffer.add('.');
1115 buffer.add(compiler.namer.operatorIs(element));
1116 if (requiresNativeIsCheck) buffer.add('()');
1117 }
1118
1119 void handleStringSupertypeCheck(HInstruction input, Element element) {
1120 // Make sure List and String don't share supertypes, otherwise we
1121 // would need to check for List too.
1122 assert(element !== compiler.listClass
1123 && !Elements.isListSupertype(element, compiler));
1124 beginExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
1125 checkString(input, '===');
1126 buffer.add(' || ');
1127 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
1128 checkObject(input, '===');
1129 buffer.add(' && ');
1130 checkType(input, element);
1131 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
1132 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
1133 }
1134
1135 void handleListOrSupertypeCheck(HInstruction input, Element element) {
1136 // Make sure List and String don't share supertypes, otherwise we
1137 // would need to check for String too.
1138 assert(element !== compiler.stringClass
1139 && !Elements.isStringSupertype(element, compiler));
1140 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
1141 checkObject(input, '===');
1142 buffer.add(' && (');
1143 beginExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
1144 checkArray(input, '===');
1145 buffer.add(' || ');
1146 checkType(input, element);
1147 buffer.add(')');
1148 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
1149 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
1150 }
1151
1152 void visitIs(HIs node) {
1153 Element element = node.typeExpression;
1154 if (element.kind === ElementKind.TYPE_VARIABLE) {
1155 compiler.unimplemented("visitIs for type variables");
1156 }
1157 compiler.registerIsCheck(element);
1158 LibraryElement coreLibrary = compiler.coreLibrary;
1159 ClassElement objectClass = coreLibrary.find(const SourceString('Object'));
1160 HInstruction input = node.expression;
1161 if (node.nullOk) {
1162 beginExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
1163 checkNull(input);
1164 buffer.add(' || ');
1165 }
1166
1167 if (element === objectClass || element === compiler.dynamicClass) {
1168 // The constant folder also does this optimization, but we make
1169 // it safe by assuming it may have not run.
1170 buffer.add('true');
1171 } else if (element == compiler.stringClass) {
1172 checkString(input, '===');
1173 } else if (element == compiler.doubleClass) {
1174 checkDouble(input, '===');
1175 } else if (element == compiler.numClass) {
1176 checkNum(input, '===');
1177 } else if (element == compiler.boolClass) {
1178 checkBool(input, '===');
1179 } else if (element == compiler.functionClass) {
1180 checkFunction(input, element);
1181 } else if (element == compiler.intClass) {
1182 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
1183 checkNum(input, '===');
1184 buffer.add(' && ');
1185 checkInt(input, '===');
1186 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
1187 } else if (Elements.isStringSupertype(element, compiler)) {
1188 handleStringSupertypeCheck(input, element);
1189 } else if (element === compiler.listClass
1190 || Elements.isListSupertype(element, compiler)) {
1191 handleListOrSupertypeCheck(input, element);
1192 } else {
1193 beginExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
1194 checkObject(input, '===');
1195 buffer.add(' && ');
1196 checkType(input, element);
1197 endExpression(JSPrecedence.LOGICAL_AND_PRECEDENCE);
1198 }
1199
1200 if (node.nullOk) {
1201 endExpression(JSPrecedence.LOGICAL_OR_PRECEDENCE);
1202 }
1203 }
1204 }
1205
1206 class SsaOptimizedCodeGenerator extends SsaCodeGenerator {
1207 SsaOptimizedCodeGenerator(compiler, work, parameters, parameterNames)
1208 : super(compiler, work, parameters, parameterNames);
1209
1210 void beginGraph(HGraph graph) {}
1211 void endGraph(HGraph graph) {}
1212
1213 void bailout(HTypeGuard guard, String reason) {
1214 HInstruction input = guard.guarded;
1215 Namer namer = compiler.namer;
1216 Element element = work.element;
1217 buffer.add('return ');
1218 if (element.isInstanceMember()) {
1219 // TODO(ngeoffray): This does not work in case we come from a
1220 // super call. We must make bailout names unique.
1221 buffer.add('this.${namer.getBailoutName(element)}');
1222 } else {
1223 buffer.add(namer.isolateBailoutAccess(element));
1224 }
1225 int parametersCount = parameterNames.length;
1226 buffer.add('($parameters');
1227 if (parametersCount != 0) buffer.add(', ');
1228 if (guard.guarded is !HParameterValue) {
1229 buffer.add('${guard.state}');
1230 bool first = true;
1231 // TODO(ngeoffray): if the bailout method takes more arguments,
1232 // fill the remaining arguments with undefined.
1233 // TODO(ngeoffray): try to put a variable at a deterministic
1234 // location, so that multiple bailout calls put the variable at
1235 // the same parameter index.
1236 for (int i = 0; i < guard.inputs.length; i++) {
1237 buffer.add(', ');
1238 use(guard.inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE);
1239 }
1240 } else {
1241 assert(guard.guarded is HParameterValue);
1242 buffer.add(' 0');
1243 }
1244 buffer.add(')');
1245 }
1246
1247 void visitTypeGuard(HTypeGuard node) {
1248 addIndentation();
1249 HInstruction input = node.guarded;
1250 assert(!isGenerateAtUseSite(input) || input.isCodeMotionInvariant());
1251 if (node.isInteger()) {
1252 buffer.add('if (');
1253 checkInt(input, '!==');
1254 buffer.add(') ');
1255 bailout(node, 'Not an integer');
1256 } else if (node.isNumber()) {
1257 buffer.add('if (');
1258 checkNum(input, '!==');
1259 buffer.add(') ');
1260 bailout(node, 'Not a number');
1261 } else if (node.isBoolean()) {
1262 buffer.add('if (');
1263 checkBool(input, '!==');
1264 buffer.add(') ');
1265 bailout(node, 'Not a boolean');
1266 } else if (node.isString()) {
1267 buffer.add('if (');
1268 checkString(input, '!==');
1269 buffer.add(') ');
1270 bailout(node, 'Not a string');
1271 } else if (node.isArray()) {
1272 buffer.add('if (');
1273 checkObject(input, '!==');
1274 buffer.add('||');
1275 checkArray(input, '!==');
1276 buffer.add(') ');
1277 bailout(node, 'Not an array');
1278 } else if (node.isStringOrArray()) {
1279 buffer.add('if (');
1280 checkString(input, '!==');
1281 buffer.add(' && (');
1282 checkObject(input, '!==');
1283 buffer.add('||');
1284 checkArray(input, '!==');
1285 buffer.add(')) ');
1286 bailout(node, 'Not a string or array');
1287 } else {
1288 unreachable();
1289 }
1290 buffer.add(';\n');
1291 }
1292
1293 void beginLoop(HBasicBlock block) {
1294 addIndentation();
1295 for (LabelElement label in block.loopInformation.labels) {
1296 writeLabel(label);
1297 buffer.add(":");
1298 }
1299 buffer.add('while (true) {\n');
1300 indent++;
1301 }
1302
1303 void endLoop(HBasicBlock block) {
1304 indent--;
1305 addIndentation();
1306 buffer.add('}\n'); // Close 'while' loop.
1307 }
1308
1309 void handleLoopCondition(HLoopBranch node) {
1310 buffer.add('if (!');
1311 use(node.inputs[0], JSPrecedence.PREFIX_PRECEDENCE);
1312 buffer.add(') break;\n');
1313 }
1314
1315 void startIf(HIf node) {
1316 }
1317
1318 void endIf(HIf node) {
1319 indent--;
1320 addIndentation();
1321 buffer.add('}\n');
1322 }
1323
1324 void startThen(HIf node) {
1325 addIndentation();
1326 buffer.add('if (');
1327 use(node.inputs[0], JSPrecedence.EXPRESSION_PRECEDENCE);
1328 buffer.add(') {\n');
1329 indent++;
1330 }
1331
1332 void endThen(HIf node) {
1333 }
1334
1335 void startElse(HIf node) {
1336 indent--;
1337 addIndentation();
1338 buffer.add('} else {\n');
1339 indent++;
1340 }
1341
1342 void endElse(HIf node) {
1343 }
1344 }
1345
1346 class SsaUnoptimizedCodeGenerator extends SsaCodeGenerator {
1347
1348 final StringBuffer setup;
1349 final List<String> labels;
1350 int labelId = 0;
1351 int maxBailoutParameters = 0;
1352
1353 SsaUnoptimizedCodeGenerator(compiler, work, parameters, parameterNames)
1354 : super(compiler, work, parameters, parameterNames),
1355 setup = new StringBuffer(),
1356 labels = <String>[];
1357
1358 String pushLabel() {
1359 String label = 'L${labelId++}';
1360 labels.addLast(label);
1361 return label;
1362 }
1363
1364 String popLabel() {
1365 return labels.removeLast();
1366 }
1367
1368 String currentLabel() {
1369 return labels.last();
1370 }
1371
1372 void beginGraph(HGraph graph) {
1373 if (!graph.entry.hasGuards()) return;
1374 addIndentation();
1375 buffer.add('switch (state) {\n');
1376 indent++;
1377 addIndentation();
1378 buffer.add('case 0:\n');
1379 indent++;
1380
1381 // The setup phase of a bailout function sets up the environment for
1382 // each bailout target. Each bailout target will populate this
1383 // setup phase. It is put at the beginning of the function.
1384 setup.add(' switch (state) {\n');
1385 }
1386
1387 void endGraph(HGraph graph) {
1388 if (!graph.entry.hasGuards()) return;
1389 indent--; // Close original case.
1390 indent--;
1391 addIndentation();
1392 buffer.add('}\n'); // Close 'switch'.
1393 setup.add(' }\n');
1394 }
1395
1396 // For instructions that reference a guard or a check, we change that
1397 // reference to the instruction they guard against. Therefore, we must
1398 // use that instruction when restoring the environment.
1399 HInstruction unwrap(HInstruction argument) {
1400 if (argument is HIntegerCheck) {
1401 HIntegerCheck instruction = argument;
1402 return unwrap(instruction.value);
1403 } else if (argument is HBoundsCheck) {
1404 HBoundsCheck instruction = argument;
1405 return unwrap(instruction.index);
1406 } else if (argument is HTypeGuard) {
1407 HTypeGuard instruction = argument;
1408 return unwrap(instruction.guarded);
1409 } else {
1410 return argument;
1411 }
1412 }
1413
1414 void visitTypeGuard(HTypeGuard node) {
1415 indent--;
1416 addIndentation();
1417 buffer.add('case ${node.state}:\n');
1418 indent++;
1419 addIndentation();
1420 buffer.add('state = 0;\n');
1421
1422 setup.add(' case ${node.state}:\n');
1423 int i = 0;
1424 for (HInstruction input in node.inputs) {
1425 HInstruction instruction = unwrap(input);
1426 setup.add(' ${temporary(instruction)} = env$i;\n');
1427 i++;
1428 }
1429 if (i > maxBailoutParameters) maxBailoutParameters = i;
1430 setup.add(' break;\n');
1431 }
1432
1433 void startBailoutCase(List<HTypeGuard> bailouts1,
1434 List<HTypeGuard> bailouts2) {
1435 indent--;
1436 handleBailoutCase(bailouts1);
1437 handleBailoutCase(bailouts2);
1438 indent++;
1439 }
1440
1441 void handleBailoutCase(List<HTypeGuard> guards) {
1442 for (int i = 0, len = guards.length; i < len; i++) {
1443 addIndentation();
1444 buffer.add('case ${guards[i].state}:\n');
1445 }
1446 }
1447
1448 void startBailoutSwitch() {
1449 addIndentation();
1450 buffer.add('switch (state) {\n');
1451 indent++;
1452 addIndentation();
1453 buffer.add('case 0:\n');
1454 indent++;
1455 }
1456
1457 void endBailoutSwitch() {
1458 indent--; // Close 'case'.
1459 indent--;
1460 addIndentation();
1461 buffer.add('}\n'); // Close 'switch'.
1462 }
1463
1464
1465 void beginLoop(HBasicBlock block) {
1466 // TODO(ngeoffray): Don't put labels on loops that don't bailout.
1467 String newLabel = pushLabel();
1468 if (block.hasGuards()) {
1469 startBailoutCase(block.guards, const <HTypeGuard>[]);
1470 }
1471
1472 addIndentation();
1473 for (SourceString label in block.loopInformation.labels) {
1474 writeLabel(label);
1475 buffer.add(":");
1476 }
1477 buffer.add('$newLabel: while (true) {\n');
1478 indent++;
1479
1480 if (block.hasGuards()) {
1481 startBailoutSwitch();
1482 }
1483 }
1484
1485 void endLoop(HBasicBlock block) {
1486 popLabel();
1487 HBasicBlock header = block.isLoopHeader() ? block : block.parentLoopHeader;
1488 if (header.hasGuards()) {
1489 endBailoutSwitch();
1490 }
1491 indent--;
1492 addIndentation();
1493 buffer.add('}\n'); // Close 'while'.
1494 }
1495
1496 void handleLoopCondition(HLoopBranch node) {
1497 buffer.add('if (!');
1498 use(node.inputs[0], JSPrecedence.PREFIX_PRECEDENCE);
1499 buffer.add(') break ${currentLabel()};\n');
1500 }
1501
1502 void startIf(HIf node) {
1503 bool hasGuards = node.thenBlock.hasGuards()
1504 || (node.hasElse && node.elseBlock.hasGuards());
1505 if (hasGuards) {
1506 startBailoutCase(node.thenBlock.guards,
1507 node.hasElse ? node.elseBlock.guards : const <HTypeGuard>[]);
1508 }
1509 }
1510
1511 void endIf(HIf node) {
1512 indent--;
1513 addIndentation();
1514 buffer.add('}\n');
1515 }
1516
1517 void startThen(HIf node) {
1518 addIndentation();
1519 bool hasGuards = node.thenBlock.hasGuards()
1520 || (node.hasElse && node.elseBlock.hasGuards());
1521 buffer.add('if (');
1522 int precedence = JSPrecedence.EXPRESSION_PRECEDENCE;
1523 if (hasGuards) {
1524 // TODO(ngeoffray): Put the condition initialization in the
1525 // [setup] buffer.
1526 List<HTypeGuard> guards = node.thenBlock.guards;
1527 for (int i = 0, len = guards.length; i < len; i++) {
1528 buffer.add('state == ${guards[i].state} || ');
1529 }
1530 buffer.add('(state == 0 && ');
1531 precedence = JSPrecedence.BITWISE_OR_PRECEDENCE;
1532 }
1533 use(node.inputs[0], precedence);
1534 if (hasGuards) {
1535 buffer.add(')');
1536 }
1537 buffer.add(') {\n');
1538 indent++;
1539 if (node.thenBlock.hasGuards()) {
1540 startBailoutSwitch();
1541 }
1542 }
1543
1544 void endThen(HIf node) {
1545 if (node.thenBlock.hasGuards()) {
1546 endBailoutSwitch();
1547 }
1548 }
1549
1550 void startElse(HIf node) {
1551 indent--;
1552 addIndentation();
1553 buffer.add('} else {\n');
1554 indent++;
1555 if (node.elseBlock.hasGuards()) {
1556 startBailoutSwitch();
1557 }
1558 }
1559
1560 void endElse(HIf node) {
1561 if (node.elseBlock.hasGuards()) {
1562 endBailoutSwitch();
1563 }
1564 }
1565 }
OLDNEW
« 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