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

Side by Side Diff: frog/leg/ssa/nodes.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/js_names.dart ('k') | frog/leg/ssa/optimize.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) 2011, 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 interface HVisitor<R> {
6 R visitAdd(HAdd node);
7 R visitBitAnd(HBitAnd node);
8 R visitBitNot(HBitNot node);
9 R visitBitOr(HBitOr node);
10 R visitBitXor(HBitXor node);
11 R visitBoolify(HBoolify node);
12 R visitBoundsCheck(HBoundsCheck node);
13 R visitBreak(HBreak node);
14 R visitConstant(HConstant node);
15 R visitContinue(HContinue node);
16 R visitDivide(HDivide node);
17 R visitEquals(HEquals node);
18 R visitExit(HExit node);
19 R visitFieldGet(HFieldGet node);
20 R visitFieldSet(HFieldSet node);
21 R visitForeign(HForeign node);
22 R visitForeignNew(HForeignNew node);
23 R visitGoto(HGoto node);
24 R visitGreater(HGreater node);
25 R visitGreaterEqual(HGreaterEqual node);
26 R visitIdentity(HIdentity node);
27 R visitIf(HIf node);
28 R visitIndex(HIndex node);
29 R visitIndexAssign(HIndexAssign node);
30 R visitIntegerCheck(HIntegerCheck node);
31 R visitInvokeClosure(HInvokeClosure node);
32 R visitInvokeDynamicGetter(HInvokeDynamicGetter node);
33 R visitInvokeDynamicMethod(HInvokeDynamicMethod node);
34 R visitInvokeDynamicSetter(HInvokeDynamicSetter node);
35 R visitInvokeInterceptor(HInvokeInterceptor node);
36 R visitInvokeStatic(HInvokeStatic node);
37 R visitInvokeSuper(HInvokeSuper node);
38 R visitIs(HIs node);
39 R visitLess(HLess node);
40 R visitLessEqual(HLessEqual node);
41 R visitLiteralList(HLiteralList node);
42 R visitLoopBranch(HLoopBranch node);
43 R visitModulo(HModulo node);
44 R visitMultiply(HMultiply node);
45 R visitNegate(HNegate node);
46 R visitNot(HNot node);
47 R visitParameterValue(HParameterValue node);
48 R visitPhi(HPhi node);
49 R visitReturn(HReturn node);
50 R visitShiftLeft(HShiftLeft node);
51 R visitShiftRight(HShiftRight node);
52 R visitStatic(HStatic node);
53 R visitStaticStore(HStaticStore node);
54 R visitSubtract(HSubtract node);
55 R visitThis(HThis node);
56 R visitThrow(HThrow node);
57 R visitTruncatingDivide(HTruncatingDivide node);
58 R visitTry(HTry node);
59 R visitTypeGuard(HTypeGuard node);
60 }
61
62 class HGraphVisitor {
63 visitDominatorTree(HGraph graph) {
64 void visitBasicBlockAndSuccessors(HBasicBlock block) {
65 visitBasicBlock(block);
66 List dominated = block.dominatedBlocks;
67 for (int i = 0; i < dominated.length; i++) {
68 visitBasicBlockAndSuccessors(dominated[i]);
69 }
70 }
71
72 visitBasicBlockAndSuccessors(graph.entry);
73 }
74
75 visitPostDominatorTree(HGraph graph) {
76 void visitBasicBlockAndSuccessors(HBasicBlock block) {
77 List dominated = block.dominatedBlocks;
78 for (int i = dominated.length - 1; i >= 0; i--) {
79 visitBasicBlockAndSuccessors(dominated[i]);
80 }
81 visitBasicBlock(block);
82 }
83
84 visitBasicBlockAndSuccessors(graph.entry);
85 }
86
87 abstract visitBasicBlock(HBasicBlock block);
88 }
89
90 class HInstructionVisitor extends HGraphVisitor {
91 HBasicBlock currentBlock;
92
93 abstract visitInstruction(HInstruction node);
94
95 visitBasicBlock(HBasicBlock node) {
96 void visitInstructionList(HInstructionList list) {
97 HInstruction instruction = list.first;
98 while (instruction !== null) {
99 visitInstruction(instruction);
100 instruction = instruction.next;
101 assert(instruction != list.first);
102 }
103 }
104
105 currentBlock = node;
106 visitInstructionList(node);
107 }
108 }
109
110 class HGraph {
111 HBasicBlock entry;
112 HBasicBlock exit;
113 final List<HBasicBlock> blocks;
114
115 // We canonicalize all constants used within a graph so we do not
116 // have to worry about them for global value numbering.
117 Map<Constant, HConstant> constants;
118
119 HGraph()
120 : blocks = new List<HBasicBlock>(),
121 constants = new Map<Constant, HConstant>() {
122 entry = addNewBlock();
123 // The exit block will be added later, so it has an id that is
124 // after all others in the system.
125 exit = new HBasicBlock();
126 }
127
128 void addBlock(HBasicBlock block) {
129 int id = blocks.length;
130 block.id = id;
131 blocks.add(block);
132 assert(blocks[id] === block);
133 }
134
135 HBasicBlock addNewBlock() {
136 HBasicBlock result = new HBasicBlock();
137 addBlock(result);
138 return result;
139 }
140
141 HBasicBlock addNewLoopHeaderBlock(List<LabelElement> labels) {
142 HBasicBlock result = addNewBlock();
143 result.loopInformation = new HLoopInformation(result, labels);
144 return result;
145 }
146
147 static HType mapConstantTypeToSsaType(Constant constant) {
148 if (constant.isNull()) return HType.UNKNOWN;
149 if (constant.isBool()) return HType.BOOLEAN;
150 if (constant.isInt()) return HType.INTEGER;
151 if (constant.isDouble()) return HType.DOUBLE;
152 if (constant.isString()) return HType.STRING;
153 if (constant.isList()) return HType.ARRAY;
154 return HType.UNKNOWN;
155 }
156
157 HConstant addConstant(Constant constant) {
158 HConstant result = constants[constant];
159 if (result === null) {
160 HType type = mapConstantTypeToSsaType(constant);
161 result = new HConstant.internal(constant, type);
162 entry.addAtExit(result);
163 constants[constant] = result;
164 }
165 return result;
166 }
167
168 HConstant addConstantInt(int i) {
169 return addConstant(new IntConstant(i));
170 }
171
172 HConstant addConstantDouble(double d) {
173 return addConstant(new DoubleConstant(d));
174 }
175
176 HConstant addConstantString(DartString str) {
177 return addConstant(new StringConstant(str));
178 }
179
180 HConstant addConstantBool(bool value) {
181 return addConstant(new BoolConstant(value));
182 }
183
184 HConstant addConstantNull() {
185 return addConstant(new NullConstant());
186 }
187
188 void finalize() {
189 addBlock(exit);
190 exit.open();
191 exit.close(new HExit());
192 assignDominators();
193 }
194
195 void assignDominators() {
196 // Run through the blocks in order of increasing ids so we are
197 // guaranteed that we have computed dominators for all blocks
198 // higher up in the dominator tree.
199 for (int i = 0, length = blocks.length; i < length; i++) {
200 HBasicBlock block = blocks[i];
201 List<HBasicBlock> predecessors = block.predecessors;
202 if (block.isLoopHeader()) {
203 assert(predecessors.length >= 2);
204 block.assignCommonDominator(predecessors[0]);
205 } else {
206 for (int j = predecessors.length - 1; j >= 0; j--) {
207 block.assignCommonDominator(predecessors[j]);
208 }
209 }
210 }
211 }
212
213 bool isValid() {
214 HValidator validator = new HValidator();
215 validator.visitGraph(this);
216 return validator.isValid;
217 }
218 }
219
220 class HBaseVisitor extends HGraphVisitor implements HVisitor {
221 HBasicBlock currentBlock;
222
223 visitBasicBlock(HBasicBlock node) {
224 currentBlock = node;
225
226 HInstruction instruction = node.first;
227 while (instruction !== null) {
228 instruction.accept(this);
229 instruction = instruction.next;
230 }
231 }
232
233 visitInstruction(HInstruction instruction) {}
234
235 visitBinaryArithmetic(HBinaryArithmetic node) => visitInvokeBinary(node);
236 visitBinaryBitOp(HBinaryBitOp node) => visitBinaryArithmetic(node);
237 visitInvoke(HInvoke node) => visitInstruction(node);
238 visitInvokeBinary(HInvokeBinary node) => visitInvokeStatic(node);
239 visitInvokeDynamic(HInvokeDynamic node) => visitInvoke(node);
240 visitInvokeDynamicField(HInvokeDynamicField node) => visitInvokeDynamic(node);
241 visitInvokeUnary(HInvokeUnary node) => visitInvokeStatic(node);
242 visitConditionalBranch(HConditionalBranch node) => visitControlFlow(node);
243 visitControlFlow(HControlFlow node) => visitInstruction(node);
244 visitRelational(HRelational node) => visitInvokeBinary(node);
245
246 visitAdd(HAdd node) => visitBinaryArithmetic(node);
247 visitBitAnd(HBitAnd node) => visitBinaryBitOp(node);
248 visitBitNot(HBitNot node) => visitInvokeUnary(node);
249 visitBitOr(HBitOr node) => visitBinaryBitOp(node);
250 visitBitXor(HBitXor node) => visitBinaryBitOp(node);
251 visitBoolify(HBoolify node) => visitInstruction(node);
252 visitBoundsCheck(HBoundsCheck node) => visitCheck(node);
253 visitBreak(HBreak node) => visitGoto(node);
254 visitContinue(HContinue node) => visitGoto(node);
255 visitCheck(HCheck node) => visitInstruction(node);
256 visitConstant(HConstant node) => visitInstruction(node);
257 visitDivide(HDivide node) => visitBinaryArithmetic(node);
258 visitEquals(HEquals node) => visitRelational(node);
259 visitExit(HExit node) => visitControlFlow(node);
260 visitFieldGet(HFieldGet node) => visitInstruction(node);
261 visitFieldSet(HFieldSet node) => visitInstruction(node);
262 visitForeign(HForeign node) => visitInstruction(node);
263 visitForeignNew(HForeignNew node) => visitForeign(node);
264 visitGoto(HGoto node) => visitControlFlow(node);
265 visitGreater(HGreater node) => visitRelational(node);
266 visitGreaterEqual(HGreaterEqual node) => visitRelational(node);
267 visitIdentity(HIdentity node) => visitRelational(node);
268 visitIf(HIf node) => visitConditionalBranch(node);
269 visitIndex(HIndex node) => visitInvokeStatic(node);
270 visitIndexAssign(HIndexAssign node) => visitInvokeStatic(node);
271 visitIntegerCheck(HIntegerCheck node) => visitCheck(node);
272 visitInvokeClosure(HInvokeClosure node)
273 => visitInvokeDynamic(node);
274 visitInvokeDynamicMethod(HInvokeDynamicMethod node)
275 => visitInvokeDynamic(node);
276 visitInvokeDynamicGetter(HInvokeDynamicGetter node)
277 => visitInvokeDynamicField(node);
278 visitInvokeDynamicSetter(HInvokeDynamicSetter node)
279 => visitInvokeDynamicField(node);
280 visitInvokeInterceptor(HInvokeInterceptor node)
281 => visitInvokeStatic(node);
282 visitInvokeStatic(HInvokeStatic node) => visitInvoke(node);
283 visitInvokeSuper(HInvokeSuper node) => visitInvoke(node);
284 visitLess(HLess node) => visitRelational(node);
285 visitLessEqual(HLessEqual node) => visitRelational(node);
286 visitLiteralList(HLiteralList node) => visitInstruction(node);
287 visitLoopBranch(HLoopBranch node) => visitConditionalBranch(node);
288 visitModulo(HModulo node) => visitBinaryArithmetic(node);
289 visitNegate(HNegate node) => visitInvokeUnary(node);
290 visitNot(HNot node) => visitInstruction(node);
291 visitPhi(HPhi node) => visitInstruction(node);
292 visitMultiply(HMultiply node) => visitBinaryArithmetic(node);
293 visitParameterValue(HParameterValue node) => visitInstruction(node);
294 visitReturn(HReturn node) => visitControlFlow(node);
295 visitShiftRight(HShiftRight node) => visitBinaryBitOp(node);
296 visitShiftLeft(HShiftLeft node) => visitBinaryBitOp(node);
297 visitSubtract(HSubtract node) => visitBinaryArithmetic(node);
298 visitStatic(HStatic node) => visitInstruction(node);
299 visitStaticStore(HStaticStore node) => visitInstruction(node);
300 visitThis(HThis node) => visitParameterValue(node);
301 visitThrow(HThrow node) => visitControlFlow(node);
302 visitTry(HTry node) => visitControlFlow(node);
303 visitTruncatingDivide(HTruncatingDivide node) => visitBinaryArithmetic(node);
304 visitTypeGuard(HTypeGuard node) => visitInstruction(node);
305 visitIs(HIs node) => visitInstruction(node);
306 }
307
308 class SubGraph {
309 // The first and last block of the sub-graph.
310 final HBasicBlock start;
311 final HBasicBlock end;
312
313 const SubGraph(this.start, this.end);
314
315 bool contains(HBasicBlock block) {
316 assert(start !== null);
317 assert(end !== null);
318 assert(block !== null);
319 return start.id <= block.id && block.id <= end.id;
320 }
321 }
322
323 class HInstructionList {
324 HInstruction first = null;
325 HInstruction last = null;
326
327 bool isEmpty() {
328 return first === null;
329 }
330
331 void addAfter(HInstruction cursor, HInstruction instruction) {
332 if (cursor === null) {
333 assert(isEmpty());
334 first = last = instruction;
335 } else if (cursor === last) {
336 last.next = instruction;
337 instruction.previous = last;
338 last = instruction;
339 } else {
340 instruction.previous = cursor;
341 instruction.next = cursor.next;
342 cursor.next.previous = instruction;
343 cursor.next = instruction;
344 }
345 }
346
347 void addBefore(HInstruction cursor, HInstruction instruction) {
348 if (cursor === null) {
349 assert(isEmpty());
350 first = last = instruction;
351 } else if (cursor === first) {
352 first.previous = instruction;
353 instruction.next = first;
354 first = instruction;
355 } else {
356 instruction.next = cursor;
357 instruction.previous = cursor.previous;
358 cursor.previous.next = instruction;
359 cursor.previous = instruction;
360 }
361 }
362
363 void detach(HInstruction instruction) {
364 assert(contains(instruction));
365 assert(instruction.isInBasicBlock());
366 if (instruction.previous === null) {
367 first = instruction.next;
368 } else {
369 instruction.previous.next = instruction.next;
370 }
371 if (instruction.next === null) {
372 last = instruction.previous;
373 } else {
374 instruction.next.previous = instruction.previous;
375 }
376 instruction.previous = null;
377 instruction.next = null;
378 }
379
380 void remove(HInstruction instruction) {
381 assert(instruction.usedBy.isEmpty());
382 detach(instruction);
383 }
384
385 /** Linear search for [instruction]. */
386 bool contains(HInstruction instruction) {
387 HInstruction cursor = first;
388 while (cursor != null) {
389 if (cursor === instruction) return true;
390 cursor = cursor.next;
391 }
392 return false;
393 }
394 }
395
396 class HBasicBlock extends HInstructionList implements Hashable {
397 // The [id] must be such that any successor's id is greater than
398 // this [id]. The exception are back-edges.
399 int id;
400
401 static final int STATUS_NEW = 0;
402 static final int STATUS_OPEN = 1;
403 static final int STATUS_CLOSED = 2;
404 int status = STATUS_NEW;
405
406 HInstructionList phis;
407
408 HLoopInformation loopInformation = null;
409 HLabeledBlockInformation labeledBlockInformation = null;
410 HBasicBlock parentLoopHeader = null;
411 List<HTypeGuard> guards;
412
413 final List<HBasicBlock> predecessors;
414 List<HBasicBlock> successors;
415
416 HBasicBlock dominator = null;
417 final List<HBasicBlock> dominatedBlocks;
418
419 HBasicBlock() : this.withId(null);
420 HBasicBlock.withId(this.id)
421 : phis = new HInstructionList(),
422 predecessors = <HBasicBlock>[],
423 successors = const <HBasicBlock>[],
424 dominatedBlocks = <HBasicBlock>[],
425 guards = <HTypeGuard>[];
426
427 int hashCode() => id;
428
429 bool isNew() => status == STATUS_NEW;
430 bool isOpen() => status == STATUS_OPEN;
431 bool isClosed() => status == STATUS_CLOSED;
432
433 bool isLoopHeader() => loopInformation !== null;
434 bool hasLabeledBlockInformation() => labeledBlockInformation !== null;
435
436 bool hasGuards() => !guards.isEmpty();
437
438 void open() {
439 assert(isNew());
440 status = STATUS_OPEN;
441 }
442
443 void close(HControlFlow end) {
444 assert(isOpen());
445 addAfter(last, end);
446 status = STATUS_CLOSED;
447 }
448
449 // TODO(kasperl): I really don't want to pass the compiler into this
450 // method. Maybe we need a better logging framework.
451 void printToCompiler(Compiler compiler) {
452 HInstruction instruction = first;
453 while (instruction != null) {
454 int instructionId = instruction.id;
455 String inputsAsString = instruction.inputsToString();
456 compiler.log('$instructionId: $instruction $inputsAsString');
457 instruction = instruction.next;
458 }
459 }
460
461 void addAtEntry(HInstruction instruction) {
462 assert(isClosed());
463 assert(instruction is !HPhi);
464 super.addBefore(first, instruction);
465 instruction.notifyAddedToBlock(this);
466 }
467
468 void addAtExit(HInstruction instruction) {
469 assert(isClosed());
470 assert(last is HControlFlow);
471 assert(instruction is !HPhi);
472 super.addBefore(last, instruction);
473 instruction.notifyAddedToBlock(this);
474 }
475
476 void moveAtExit(HInstruction instruction) {
477 assert(instruction is !HPhi);
478 assert(instruction.isInBasicBlock());
479 assert(isClosed());
480 assert(last is HControlFlow);
481 super.addBefore(last, instruction);
482 instruction.block = this;
483 assert(isValid());
484 }
485
486 void add(HInstruction instruction) {
487 assert(instruction is !HControlFlow);
488 assert(instruction is !HPhi);
489 super.addAfter(last, instruction);
490 instruction.notifyAddedToBlock(this);
491 }
492
493 void addPhi(HPhi phi) {
494 phis.addAfter(phis.last, phi);
495 phi.notifyAddedToBlock(this);
496 }
497
498 void removePhi(HPhi phi) {
499 phis.remove(phi);
500 phi.notifyRemovedFromBlock(this);
501 }
502
503 void addAfter(HInstruction cursor, HInstruction instruction) {
504 assert(cursor is !HPhi);
505 assert(instruction is !HPhi);
506 assert(isOpen() || isClosed());
507 super.addAfter(cursor, instruction);
508 instruction.notifyAddedToBlock(this);
509 }
510
511 void addBefore(HInstruction cursor, HInstruction instruction) {
512 assert(cursor is !HPhi);
513 assert(instruction is !HPhi);
514 assert(isOpen() || isClosed());
515 super.addBefore(cursor, instruction);
516 instruction.notifyAddedToBlock(this);
517 }
518
519 void remove(HInstruction instruction) {
520 assert(isOpen() || isClosed());
521 assert(instruction is !HPhi);
522 super.remove(instruction);
523 instruction.notifyRemovedFromBlock(this);
524 }
525
526 void addSuccessor(HBasicBlock block) {
527 // Forward branches are only allowed to new blocks.
528 assert(isClosed() && (block.isNew() || block.id < id));
529 if (successors.isEmpty()) {
530 successors = [block];
531 } else {
532 successors.add(block);
533 }
534 block.predecessors.add(this);
535 }
536
537 void postProcessLoopHeader() {
538 assert(isLoopHeader());
539 // Only the first entry into the loop is from outside the
540 // loop. All other entries must be back edges.
541 for (int i = 1, length = predecessors.length; i < length; i++) {
542 loopInformation.addBackEdge(predecessors[i]);
543 }
544 }
545
546 /**
547 * Rewrites all uses of the [from] instruction to using the [to]
548 * instruction instead.
549 */
550 void rewrite(HInstruction from, HInstruction to) {
551 for (HInstruction use in from.usedBy) {
552 rewriteInput(use, from, to);
553 }
554 to.usedBy.addAll(from.usedBy);
555 from.usedBy.clear();
556 }
557
558 static void rewriteInput(HInstruction instruction,
559 HInstruction from,
560 HInstruction to) {
561 List inputs = instruction.inputs;
562 for (int i = 0; i < inputs.length; i++) {
563 if (inputs[i] === from) inputs[i] = to;
564 }
565 }
566
567 bool isExitBlock() {
568 return first === last && first is HExit;
569 }
570
571 void addDominatedBlock(HBasicBlock block) {
572 assert(isClosed());
573 assert(id !== null && block.id !== null);
574 assert(dominatedBlocks.indexOf(block) < 0);
575 // Keep the list of dominated blocks sorted such that if there are two
576 // succeeding blocks in the list, the predecessor is before the successor.
577 // Assume that we add the dominated blocks in the right order.
578 int index = dominatedBlocks.length;
579 while (index > 0 && dominatedBlocks[index - 1].id > block.id) {
580 index--;
581 }
582 if (index == dominatedBlocks.length) {
583 dominatedBlocks.add(block);
584 } else {
585 dominatedBlocks.insertRange(index, 1, block);
586 }
587 assert(block.dominator === null);
588 block.dominator = this;
589 }
590
591 void removeDominatedBlock(HBasicBlock block) {
592 assert(isClosed());
593 assert(id !== null && block.id !== null);
594 int index = dominatedBlocks.indexOf(block);
595 assert(index >= 0);
596 if (index == dominatedBlocks.length - 1) {
597 dominatedBlocks.removeLast();
598 } else {
599 dominatedBlocks.removeRange(index, 1);
600 }
601 assert(block.dominator === this);
602 block.dominator = null;
603 }
604
605 void assignCommonDominator(HBasicBlock predecessor) {
606 assert(isClosed());
607 if (dominator === null) {
608 // If this basic block doesn't have a dominator yet we use the
609 // given predecessor as the dominator.
610 predecessor.addDominatedBlock(this);
611 } else if (predecessor.dominator !== null) {
612 // If the predecessor has a dominator and this basic block has a
613 // dominator, we find a common parent in the dominator tree and
614 // use that as the dominator.
615 HBasicBlock first = dominator;
616 HBasicBlock second = predecessor;
617 while (first !== second) {
618 if (first.id > second.id) {
619 first = first.dominator;
620 } else {
621 second = second.dominator;
622 }
623 assert(first !== null && second !== null);
624 }
625 if (dominator !== first) {
626 dominator.removeDominatedBlock(this);
627 first.addDominatedBlock(this);
628 }
629 }
630 }
631
632 void forEachPhi(void f(HPhi phi)) {
633 HPhi current = phis.first;
634 while (current !== null) {
635 f(current);
636 current = current.next;
637 }
638 }
639
640 bool isValid() {
641 assert(isClosed());
642 HValidator validator = new HValidator();
643 validator.visitBasicBlock(this);
644 return validator.isValid;
645 }
646 }
647
648 class HLabeledBlockInformation {
649 final SubGraph body;
650 final HBasicBlock joinBlock;
651 final List<LabelElement> labels;
652 final TargetElement target;
653 final bool isContinue;
654
655 HLabeledBlockInformation(this.body, this.joinBlock,
656 List<LabelElement> labels,
657 [this.isContinue = false]) :
658 this.labels = labels, this.target = labels[0].target;
659
660 HLabeledBlockInformation.implicit(this.body,
661 this.joinBlock,
662 this.target,
663 [this.isContinue = false])
664 : this.labels = const<LabelElement>[];
665 }
666
667 class HLoopInformation {
668 final HBasicBlock header;
669 final List<HBasicBlock> blocks;
670 final List<HBasicBlock> backEdges;
671 final List<LabelElement> labels;
672
673 HLoopInformation(this.header, this.labels)
674 : blocks = new List<HBasicBlock>(),
675 backEdges = new List<HBasicBlock>();
676
677 void addBackEdge(HBasicBlock predecessor) {
678 backEdges.add(predecessor);
679 addBlock(predecessor);
680 }
681
682 // Adds a block and transitively all its predecessors in the loop as
683 // loop blocks.
684 void addBlock(HBasicBlock block) {
685 if (block === header) return;
686 HBasicBlock parentHeader = block.parentLoopHeader;
687 if (parentHeader === header) {
688 // Nothing to do in this case.
689 } else if (parentHeader !== null) {
690 addBlock(parentHeader);
691 } else {
692 block.parentLoopHeader = header;
693 blocks.add(block);
694 for (int i = 0, length = block.predecessors.length; i < length; i++) {
695 addBlock(block.predecessors[i]);
696 }
697 }
698 }
699
700 HBasicBlock getLastBackEdge() {
701 int maxId = -1;
702 HBasicBlock result = null;
703 for (int i = 0, length = backEdges.length; i < length; i++) {
704 HBasicBlock current = backEdges[i];
705 if (current.id > maxId) {
706 maxId = current.id;
707 result = current;
708 }
709 }
710 return result;
711 }
712 }
713
714 class HType {
715 final int flag;
716 const HType(int this.flag);
717
718 static final int FLAG_CONFLICTING = 0;
719 static final int FLAG_UNKNOWN = 1;
720 static final int FLAG_BOOLEAN = FLAG_UNKNOWN << 1;
721 static final int FLAG_INTEGER = FLAG_BOOLEAN << 1;
722 static final int FLAG_STRING = FLAG_INTEGER << 1;
723 static final int FLAG_ARRAY = FLAG_STRING << 1;
724 static final int FLAG_DOUBLE = FLAG_ARRAY << 1;
725
726 static final HType CONFLICTING = const HType(FLAG_CONFLICTING);
727 static final HType UNKNOWN = const HType(FLAG_UNKNOWN);
728 static final HType BOOLEAN = const HType(FLAG_BOOLEAN);
729 static final HType STRING = const HType(FLAG_STRING);
730 static final HType ARRAY = const HType(FLAG_ARRAY);
731 static final HType INTEGER = const HType(FLAG_INTEGER);
732 static final HType DOUBLE = const HType(FLAG_DOUBLE);
733 static final HType STRING_OR_ARRAY = const HType(FLAG_STRING | FLAG_ARRAY);
734 static final HType NUMBER = const HType(FLAG_DOUBLE | FLAG_INTEGER);
735
736 bool isConflicting() => this === CONFLICTING;
737 bool isUnknown() => this === UNKNOWN;
738 bool isBoolean() => this === BOOLEAN;
739 bool isInteger() => this === INTEGER;
740 bool isDouble() => this === DOUBLE;
741 bool isString() => this === STRING;
742 bool isArray() => this === ARRAY;
743 bool isNumber() => (this.flag & (FLAG_INTEGER | FLAG_DOUBLE)) != 0;
744 bool isStringOrArray() => (this.flag & (FLAG_STRING | FLAG_ARRAY)) != 0;
745 bool isKnown() => this !== UNKNOWN && this !== CONFLICTING;
746
747 static HType getTypeFromFlag(int flag) {
748 if (flag === CONFLICTING.flag) return CONFLICTING;
749 if (flag === UNKNOWN.flag) return UNKNOWN;
750 if (flag === BOOLEAN.flag) return BOOLEAN;
751 if (flag === INTEGER.flag) return INTEGER;
752 if (flag === DOUBLE.flag) return DOUBLE;
753 if (flag === STRING.flag) return STRING;
754 if (flag === ARRAY.flag) return ARRAY;
755 if (flag === NUMBER.flag) return NUMBER;
756 if (flag === STRING_OR_ARRAY.flag) return STRING_OR_ARRAY;
757 assert(false);
758 }
759
760 HType combine(HType other) {
761 if (isUnknown()) return other;
762 if (other.isUnknown()) return this;
763 return getTypeFromFlag(this.flag & other.flag);
764 }
765 }
766
767 class HInstruction implements Hashable {
768 final int id;
769 static int idCounter;
770
771 final List<HInstruction> inputs;
772 final List<HInstruction> usedBy;
773
774 HBasicBlock block;
775 HInstruction previous = null;
776 HInstruction next = null;
777 int flags = 0;
778 HType type = HType.UNKNOWN;
779
780 // Changes flags.
781 static final int FLAG_CHANGES_SOMETHING = 0;
782 static final int FLAG_CHANGES_COUNT = FLAG_CHANGES_SOMETHING + 1;
783
784 // Depends flags (one for each changes flag).
785 static final int FLAG_DEPENDS_ON_SOMETHING = FLAG_CHANGES_COUNT;
786
787 // Other flags.
788 static final int FLAG_USE_GVN = FLAG_DEPENDS_ON_SOMETHING + 1;
789
790 HInstruction(this.inputs) : id = idCounter++, usedBy = <HInstruction>[];
791
792 int hashCode() => id;
793
794 bool getFlag(int position) => (flags & (1 << position)) != 0;
795 void setFlag(int position) { flags |= (1 << position); }
796 void clearFlag(int position) { flags &= ~(1 << position); }
797
798 static int computeDependsOnFlags(int flags) => flags << FLAG_CHANGES_COUNT;
799
800 int getChangesFlags() => flags & ((1 << FLAG_CHANGES_COUNT) - 1);
801 bool hasSideEffects() => getChangesFlags() != 0;
802 void prepareGvn() { setAllSideEffects(); }
803
804 void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); }
805 void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); }
806
807 bool useGvn() => getFlag(FLAG_USE_GVN);
808 void setUseGvn() { setFlag(FLAG_USE_GVN); }
809
810 bool isArray() => type.isArray();
811 bool isBoolean() => type.isBoolean();
812 bool isInteger() => type.isInteger();
813 bool isNumber() => type.isNumber();
814 bool isString() => type.isString();
815 bool isTypeUnknown() => type.isUnknown();
816 bool isStringOrArray() => type.isStringOrArray();
817
818 // Compute the type of the instruction.
819 HType computeType() => HType.UNKNOWN;
820
821 HType computeDesiredType() {
822 HType candidateType = HType.UNKNOWN;
823 for (final user in usedBy) {
824 HType desiredType = user.computeDesiredInputType(this);
825 if (candidateType.isUnknown()) {
826 candidateType = desiredType;
827 } else if (!type.isUnknown() && candidateType != desiredType) {
828 candidateType = candidateType.combine(desiredType);
829 if (!candidateType.isKnown()) {
830 candidateType = HType.UNKNOWN;
831 break;
832 }
833 }
834 }
835 return candidateType;
836 }
837
838 HType computeDesiredInputType(HInstruction input) => HType.UNKNOWN;
839
840 // Returns whether the instruction does produce the type it claims.
841 // For most instructions, this returns false. A type guard will be
842 // inserted to make sure the users get the right type in.
843 bool hasExpectedType() => false;
844
845 // Re-compute and update the type of the instruction. Returns
846 // whether or not the type was changed.
847 bool updateType() {
848 if (type.isConflicting()) return false;
849 HType newType = computeType();
850 HType desiredType = computeDesiredType();
851 HType combined = newType.combine(desiredType);
852 if (combined.isKnown()) newType = combined;
853
854 bool changed = (type != newType);
855 if (type.isUnknown()) {
856 type = newType;
857 return changed;
858 } else if (changed) {
859 type = type.combine(newType);
860 return changed;
861 }
862 return false;
863 }
864
865 bool isInBasicBlock() => block !== null;
866
867 String inputsToString() {
868 void addAsCommaSeparated(StringBuffer buffer, List<HInstruction> list) {
869 for (int i = 0; i < list.length; i++) {
870 if (i != 0) buffer.add(', ');
871 buffer.add("@${list[i].id}");
872 }
873 }
874
875 StringBuffer buffer = new StringBuffer();
876 buffer.add('(');
877 addAsCommaSeparated(buffer, inputs);
878 buffer.add(') - used at [');
879 addAsCommaSeparated(buffer, usedBy);
880 buffer.add(']');
881 return buffer.toString();
882 }
883
884 bool gvnEquals(HInstruction other) {
885 assert(useGvn() && other.useGvn());
886 // Check that the type and the flags match.
887 bool hasSameType = typeEquals(other);
888 assert(hasSameType == (typeCode() == other.typeCode()));
889 if (!hasSameType) return false;
890 if (flags != other.flags) return false;
891 // Check that the inputs match.
892 final int inputsLength = inputs.length;
893 final List<HInstruction> otherInputs = other.inputs;
894 if (inputsLength != otherInputs.length) return false;
895 for (int i = 0; i < inputsLength; i++) {
896 if (inputs[i] !== otherInputs[i]) return false;
897 }
898 // Check that the data in the instruction matches.
899 return dataEquals(other);
900 }
901
902 int gvnHashCode() {
903 int result = typeCode();
904 int length = inputs.length;
905 for (int i = 0; i < length; i++) {
906 result = (result * 19) + (inputs[i].id) + (result >> 7);
907 }
908 return result;
909 }
910
911 // These methods should be overwritten by instructions that
912 // participate in global value numbering.
913 int typeCode() => -1;
914 bool typeEquals(HInstruction other) => false;
915 bool dataEquals(HInstruction other) => false;
916
917 abstract accept(HVisitor visitor);
918
919 void notifyAddedToBlock(HBasicBlock block) {
920 assert(!isInBasicBlock());
921 assert(this.block === null);
922 // Add [this] to the inputs' uses.
923 for (int i = 0; i < inputs.length; i++) {
924 assert(inputs[i].isInBasicBlock());
925 inputs[i].usedBy.add(this);
926 }
927 this.block = block;
928 assert(isValid());
929 }
930
931 void notifyRemovedFromBlock(HBasicBlock block) {
932 assert(isInBasicBlock());
933 assert(usedBy.isEmpty());
934 assert(this.block === block);
935
936 // Remove [this] from the inputs' uses.
937 for (int i = 0; i < inputs.length; i++) {
938 List inputUsedBy = inputs[i].usedBy;
939 for (int j = 0; j < inputUsedBy.length; j++) {
940 if (inputUsedBy[j] === this) {
941 inputUsedBy[j] = inputUsedBy[inputUsedBy.length - 1];
942 inputUsedBy.removeLast();
943 break;
944 }
945 }
946 }
947 this.block = null;
948 assert(isValid());
949 }
950
951 bool isConstant() => false;
952 bool isConstantNull() => false;
953 bool isConstantNumber() => false;
954 bool isConstantString() => false;
955
956 bool isValid() {
957 HValidator validator = new HValidator();
958 validator.currentBlock = block;
959 validator.visitInstruction(this);
960 return validator.isValid;
961 }
962
963 /**
964 * The code for computing a bailout environment, and the code
965 * generation must agree on what does not need to be captured,
966 * so should always be generated at use site.
967 */
968 bool isCodeMotionInvariant() => false;
969 }
970
971 class HBoolify extends HInstruction {
972 HBoolify(HInstruction value) : super(<HInstruction>[value]);
973 void prepareGvn() {
974 assert(!hasSideEffects());
975 setUseGvn();
976 }
977
978 HType computeType() => HType.BOOLEAN;
979 bool hasExpectedType() => true;
980
981 accept(HVisitor visitor) => visitor.visitBoolify(this);
982 int typeCode() => 0;
983 bool typeEquals(other) => other is HBoolify;
984 bool dataEquals(HInstruction other) => true;
985 }
986
987 class HCheck extends HInstruction {
988 HCheck(inputs) : super(inputs);
989
990 // TODO(floitsch): make class abstract instead of adding an abstract method.
991 abstract accept(HVisitor visitor);
992 }
993
994 class HTypeGuard extends HInstruction {
995 int state;
996 HTypeGuard(int this.state, List<HInstruction> env) : super(env);
997
998 void prepareGvn() {
999 assert(!hasSideEffects());
1000 setUseGvn();
1001 }
1002
1003 HInstruction get guarded() => inputs.last();
1004
1005 HType computeType() => type;
1006 bool hasExpectedType() => true;
1007
1008 accept(HVisitor visitor) => visitor.visitTypeGuard(this);
1009 int typeCode() => 1;
1010 bool typeEquals(other) => other is HTypeGuard;
1011 bool dataEquals(HTypeGuard other) => type == other.type;
1012 }
1013
1014 class HBoundsCheck extends HCheck {
1015 HBoundsCheck(length, index) : super(<HInstruction>[length, index]) {
1016 type = HType.INTEGER;
1017 }
1018
1019 HInstruction get length() => inputs[0];
1020 HInstruction get index() => inputs[1];
1021
1022 void prepareGvn() {
1023 assert(!hasSideEffects());
1024 setUseGvn();
1025 }
1026
1027 HType computeType() => HType.INTEGER;
1028 bool hasExpectedType() => true;
1029
1030 accept(HVisitor visitor) => visitor.visitBoundsCheck(this);
1031 int typeCode() => 2;
1032 bool typeEquals(other) => other is HBoundsCheck;
1033 bool dataEquals(HInstruction other) => true;
1034 }
1035
1036 class HIntegerCheck extends HCheck {
1037 HIntegerCheck(value) : super(<HInstruction>[value]);
1038
1039 HInstruction get value() => inputs[0];
1040
1041 void prepareGvn() {
1042 assert(!hasSideEffects());
1043 setUseGvn();
1044 }
1045
1046 HType computeType() => HType.INTEGER;
1047 bool hasExpectedType() => true;
1048
1049 accept(HVisitor visitor) => visitor.visitIntegerCheck(this);
1050 int typeCode() => 3;
1051 bool typeEquals(other) => other is HIntegerCheck;
1052 bool dataEquals(HInstruction other) => true;
1053 }
1054
1055 class HConditionalBranch extends HControlFlow {
1056 HConditionalBranch(inputs) : super(inputs);
1057 HInstruction get condition() => inputs[0];
1058 HBasicBlock get trueBranch() => block.successors[0];
1059 HBasicBlock get falseBranch() => block.successors[1];
1060 abstract toString();
1061 }
1062
1063 class HControlFlow extends HInstruction {
1064 HControlFlow(inputs) : super(inputs);
1065 abstract toString();
1066 }
1067
1068 class HInvoke extends HInstruction {
1069 /**
1070 * The first argument must be the target: either an [HStatic] node, or
1071 * the receiver of a method-call. The remaining inputs are the arguments
1072 * to the invocation.
1073 */
1074 final Selector selector;
1075 HInvoke(Selector this.selector, List<HInstruction> inputs) : super(inputs);
1076 static final int ARGUMENTS_OFFSET = 1;
1077
1078 // TODO(floitsch): make class abstract instead of adding an abstract method.
1079 abstract accept(HVisitor visitor);
1080 }
1081
1082 class HInvokeDynamic extends HInvoke {
1083 SourceString name;
1084 HInvokeDynamic(Selector selector, this.name, List<HInstruction> inputs)
1085 : super(selector, inputs);
1086 toString() => 'invoke dynamic: $name';
1087 HInstruction get receiver() => inputs[0];
1088
1089 // TODO(floitsch): make class abstract instead of adding an abstract method.
1090 abstract accept(HVisitor visitor);
1091 }
1092
1093 class HInvokeClosure extends HInvokeDynamic {
1094 Element element;
1095 HInvokeClosure(Selector selector, List<HInstruction> inputs)
1096 : super(selector, const SourceString('call'), inputs);
1097 accept(HVisitor visitor) => visitor.visitInvokeClosure(this);
1098 }
1099
1100 class HInvokeDynamicMethod extends HInvokeDynamic {
1101 HInvokeDynamicMethod(Selector selector,
1102 SourceString methodName,
1103 List<HInstruction> inputs)
1104 : super(selector, methodName, inputs);
1105 toString() => 'invoke dynamic method: $name';
1106 accept(HVisitor visitor) => visitor.visitInvokeDynamicMethod(this);
1107 }
1108
1109 class HInvokeDynamicField extends HInvokeDynamic {
1110 Element element;
1111 HInvokeDynamicField(Selector selector,
1112 Element this.element,
1113 SourceString name,
1114 List<HInstruction>inputs)
1115 : super(selector, name, inputs);
1116 toString() => 'invoke dynamic field: $name';
1117
1118 // TODO(floitsch): make class abstract instead of adding an abstract method.
1119 abstract accept(HVisitor visitor);
1120 }
1121
1122 class HInvokeDynamicGetter extends HInvokeDynamicField {
1123 HInvokeDynamicGetter(selector, element, name, receiver)
1124 : super(selector, element, name, [receiver]);
1125 toString() => 'invoke dynamic getter: $name';
1126 accept(HVisitor visitor) => visitor.visitInvokeDynamicGetter(this);
1127 }
1128
1129 class HInvokeDynamicSetter extends HInvokeDynamicField {
1130 HInvokeDynamicSetter(selector, element, name, receiver, value)
1131 : super(selector, element, name, [receiver, value]);
1132 toString() => 'invoke dynamic setter: $name';
1133 accept(HVisitor visitor) => visitor.visitInvokeDynamicSetter(this);
1134 }
1135
1136 class HInvokeStatic extends HInvoke {
1137 /** The first input must be the target. */
1138 HInvokeStatic(selector, inputs) : super(selector, inputs);
1139 toString() => 'invoke static: ${element.name}';
1140 accept(HVisitor visitor) => visitor.visitInvokeStatic(this);
1141 Element get element() => target.element;
1142 HStatic get target() => inputs[0];
1143
1144 bool isArrayConstructor() {
1145 // TODO(ngeoffray): This is not the right way to do the check,
1146 // nor the right place. We need to move it to a phase.
1147 return (element.isFactoryConstructor()
1148 && element.enclosingElement.name.slowToString() == 'List');
1149 }
1150
1151 HType computeType() {
1152 if (isArrayConstructor()) {
1153 return HType.ARRAY;
1154 }
1155 return HType.UNKNOWN;
1156 }
1157
1158 bool get builtin() => isArrayConstructor();
1159 bool hasExpectedType() => isArrayConstructor();
1160 }
1161
1162 class HInvokeSuper extends HInvokeStatic {
1163 HInvokeSuper(selector, inputs) : super(selector, inputs);
1164 toString() => 'invoke super: ${element.name}';
1165 accept(HVisitor visitor) => visitor.visitInvokeSuper(this);
1166 }
1167
1168 class HInvokeInterceptor extends HInvokeStatic {
1169 final SourceString name;
1170 final bool getter;
1171
1172 HInvokeInterceptor(Selector selector,
1173 SourceString this.name,
1174 bool this.getter,
1175 List<HInstruction> inputs)
1176 : super(selector, inputs);
1177 toString() => 'invoke interceptor: ${element.name}';
1178 accept(HVisitor visitor) => visitor.visitInvokeInterceptor(this);
1179
1180
1181 String get builtinJsName() {
1182 if (getter
1183 && name == const SourceString('length')
1184 && inputs[1].isStringOrArray()) {
1185 return 'length';
1186 } else if (name == const SourceString('add') && inputs[1].isArray()) {
1187 return 'push';
1188 } else if (name == const SourceString('removeLast')
1189 && inputs[1].isArray()) {
1190 return 'pop';
1191 }
1192 return null;
1193 }
1194
1195 HType computeType() {
1196 if (getter
1197 && name == const SourceString('length')
1198 && inputs[1].isStringOrArray()) {
1199 return HType.INTEGER;
1200 }
1201 return HType.UNKNOWN;
1202 }
1203
1204 HType computeDesiredInputType(HInstruction input) {
1205 if (input == inputs[0]) return HType.UNKNOWN;
1206 if (input == inputs[1] && input.isStringOrArray()) {
1207 if (name == const SourceString('add')
1208 || name == const SourceString('removeLast')) {
1209 return HType.ARRAY;
1210 }
1211 }
1212 return HType.UNKNOWN;
1213 }
1214
1215 bool hasExpectedType() => builtinJsName != null;
1216
1217 void prepareGvn() {
1218 if (builtinJsName == 'length') {
1219 clearAllSideEffects();
1220 } else {
1221 setAllSideEffects();
1222 }
1223 }
1224
1225 int typeCode() => 4;
1226 bool typeEquals(other) => other is HInvokeInterceptor;
1227 bool dataEquals(HInvokeInterceptor other) {
1228 return builtinJsName == other.builtinJsName && name == other.name;
1229 }
1230 }
1231
1232 class HFieldGet extends HInstruction {
1233 final Element element;
1234 HFieldGet(Element this.element, HInstruction receiver)
1235 : super(<HInstruction>[receiver]);
1236 HFieldGet.fromActivation(Element this.element) : super(<HInstruction>[]);
1237
1238 HInstruction get receiver() => inputs.length == 1 ? inputs[0] : null;
1239 accept(HVisitor visitor) => visitor.visitFieldGet(this);
1240 }
1241
1242 class HFieldSet extends HInstruction {
1243 final Element element;
1244 HFieldSet(Element this.element, HInstruction receiver, HInstruction value)
1245 : super(<HInstruction>[receiver, value]);
1246 HFieldSet.fromActivation(Element this.element, HInstruction value)
1247 : super(<HInstruction>[value]);
1248
1249 HInstruction get receiver() => inputs.length == 2 ? inputs[0] : null;
1250 HInstruction get value() => inputs.length == 2 ? inputs[1] : inputs[0];
1251 accept(HVisitor visitor) => visitor.visitFieldSet(this);
1252
1253 void prepareGvn() {
1254 // TODO(ngeoffray): implement more fine grain side effects.
1255 setAllSideEffects();
1256 }
1257 }
1258
1259 class HForeign extends HInstruction {
1260 final DartString code;
1261 final DartString declaredType;
1262 HForeign(this.code, this.declaredType, List<HInstruction> inputs)
1263 : super(inputs);
1264 accept(HVisitor visitor) => visitor.visitForeign(this);
1265
1266 HType computeType() {
1267 if (declaredType.slowToString() == 'bool') return HType.BOOLEAN;
1268 if (declaredType.slowToString() == 'int') return HType.INTEGER;
1269 if (declaredType.slowToString() == 'num') return HType.NUMBER;
1270 if (declaredType.slowToString() == 'String') return HType.STRING;
1271 return HType.UNKNOWN;
1272 }
1273
1274 bool hasExpectedType() => true;
1275 }
1276
1277 class HForeignNew extends HForeign {
1278 ClassElement element;
1279 HForeignNew(this.element, List<HInstruction> inputs)
1280 : super(const LiteralDartString("new"),
1281 const LiteralDartString("Object"), inputs);
1282 accept(HVisitor visitor) => visitor.visitForeignNew(this);
1283 }
1284
1285 class HInvokeBinary extends HInvokeStatic {
1286 HInvokeBinary(HStatic target, HInstruction left, HInstruction right)
1287 : super(Selector.BINARY_OPERATOR, <HInstruction>[target, left, right]);
1288
1289 HInstruction get left() => inputs[1];
1290 HInstruction get right() => inputs[2];
1291
1292 HType computeInputsType() {
1293 HType leftType = left.type;
1294 HType rightType = right.type;
1295 if (leftType.isUnknown() || rightType.isUnknown()) {
1296 return HType.UNKNOWN;
1297 }
1298 return leftType.combine(rightType);
1299 }
1300
1301 abstract BinaryOperation get operation();
1302 }
1303
1304 class HBinaryArithmetic extends HInvokeBinary {
1305 HBinaryArithmetic(HStatic target, HInstruction left, HInstruction right)
1306 : super(target, left, right);
1307
1308 void prepareGvn() {
1309 // An arithmetic expression can take part in global value
1310 // numbering and do not have any side-effects if we know that all
1311 // inputs are numbers.
1312 if (builtin) {
1313 clearAllSideEffects();
1314 setUseGvn();
1315 } else {
1316 setAllSideEffects();
1317 }
1318 }
1319
1320 bool get builtin() => left.isNumber() && right.isNumber();
1321
1322 HType computeType() {
1323 HType inputsType = computeInputsType();
1324 if (!inputsType.isUnknown()) return inputsType;
1325 if (left.isNumber()) return HType.NUMBER;
1326 return HType.UNKNOWN;
1327 }
1328
1329 HType computeDesiredInputType(HInstruction input) {
1330 // TODO(floitsch): we want the target to be a function.
1331 if (input == target) return HType.UNKNOWN;
1332 if (isNumber() || left.isNumber() || right.isNumber()) return HType.NUMBER;
1333 if (type.isUnknown()) return HType.NUMBER;
1334 return HType.UNKNOWN;
1335 }
1336
1337 bool hasExpectedType() => left.isNumber() && right.isNumber();
1338 // TODO(1603): The class should be marked as abstract.
1339 abstract BinaryOperation get operation();
1340 }
1341
1342 class HAdd extends HBinaryArithmetic {
1343 HAdd(HStatic target, HInstruction left, HInstruction right)
1344 : super(target, left, right);
1345 accept(HVisitor visitor) => visitor.visitAdd(this);
1346
1347 bool get builtin() {
1348 return (left.isNumber() && right.isNumber())
1349 || (left.isString() && right.isString())
1350 || (left.isString() && right is HConstant);
1351 }
1352
1353 HType computeType() {
1354 HType computedType = computeInputsType();
1355 if (computedType.isConflicting() && left.isString()) return HType.STRING;
1356 if (!computedType.isUnknown()) return computedType;
1357 if (left.isNumber()) return HType.NUMBER;
1358 return HType.UNKNOWN;
1359 }
1360
1361 bool hasExpectedType() => builtin || type.isUnknown() || left.isString();
1362
1363 HType computeDesiredInputType(HInstruction input) {
1364 // TODO(floitsch): we want the target to be a function.
1365 if (input == target) return HType.UNKNOWN;
1366 if (isString() || left.isString()) {
1367 return (input == left) ? HType.STRING : HType.UNKNOWN;
1368 }
1369 if (right.isString()) return HType.STRING;
1370 if (isNumber() || left.isNumber() || right.isNumber()) return HType.NUMBER;
1371 return HType.UNKNOWN;
1372 }
1373
1374 AddOperation get operation() => const AddOperation();
1375
1376 int typeCode() => 5;
1377 bool typeEquals(other) => other is HAdd;
1378 bool dataEquals(HInstruction other) => true;
1379 }
1380
1381 class HDivide extends HBinaryArithmetic {
1382 HDivide(HStatic target, HInstruction left, HInstruction right)
1383 : super(target, left, right);
1384 accept(HVisitor visitor) => visitor.visitDivide(this);
1385
1386 bool get builtin() => left.isNumber() && right.isNumber();
1387
1388 HType computeType() {
1389 HType inputsType = computeInputsType();
1390 if (left.isNumber()) return HType.DOUBLE;
1391 return HType.UNKNOWN;
1392 }
1393
1394 DivideOperation get operation() => const DivideOperation();
1395 int typeCode() => 6;
1396 bool typeEquals(other) => other is HDivide;
1397 bool dataEquals(HInstruction other) => true;
1398 }
1399
1400 class HModulo extends HBinaryArithmetic {
1401 HModulo(HStatic target, HInstruction left, HInstruction right)
1402 : super(target, left, right);
1403 accept(HVisitor visitor) => visitor.visitModulo(this);
1404
1405 ModuloOperation get operation() => const ModuloOperation();
1406 int typeCode() => 7;
1407 bool typeEquals(other) => other is HModulo;
1408 bool dataEquals(HInstruction other) => true;
1409 }
1410
1411 class HMultiply extends HBinaryArithmetic {
1412 HMultiply(HStatic target, HInstruction left, HInstruction right)
1413 : super(target, left, right);
1414 accept(HVisitor visitor) => visitor.visitMultiply(this);
1415
1416 MultiplyOperation get operation() => const MultiplyOperation();
1417 int typeCode() => 8;
1418 bool typeEquals(other) => other is HMultiply;
1419 bool dataEquals(HInstruction other) => true;
1420 }
1421
1422 class HSubtract extends HBinaryArithmetic {
1423 HSubtract(HStatic target, HInstruction left, HInstruction right)
1424 : super(target, left, right);
1425 accept(HVisitor visitor) => visitor.visitSubtract(this);
1426
1427 SubtractOperation get operation() => const SubtractOperation();
1428 int typeCode() => 9;
1429 bool typeEquals(other) => other is HSubtract;
1430 bool dataEquals(HInstruction other) => true;
1431 }
1432
1433 class HTruncatingDivide extends HBinaryArithmetic {
1434 HTruncatingDivide(HStatic target, HInstruction left, HInstruction right)
1435 : super(target, left, right);
1436 accept(HVisitor visitor) => visitor.visitTruncatingDivide(this);
1437
1438 TruncatingDivideOperation get operation()
1439 => const TruncatingDivideOperation();
1440 int typeCode() => 10;
1441 bool typeEquals(other) => other is HTruncatingDivide;
1442 bool dataEquals(HInstruction other) => true;
1443 }
1444
1445
1446 // TODO(floitsch): Should HBinaryArithmetic really be the super class of
1447 // HBinaryBitOp?
1448 class HBinaryBitOp extends HBinaryArithmetic {
1449 HBinaryBitOp(HStatic target, HInstruction left, HInstruction right)
1450 : super(target, left, right);
1451
1452 bool get builtin() => left.isInteger() && right.isInteger();
1453
1454 HType computeType() {
1455 HType inputsType = computeInputsType();
1456 if (!inputsType.isUnknown()) return inputsType;
1457 if (left.isInteger()) return HType.INTEGER;
1458 return HType.UNKNOWN;
1459 }
1460
1461 HType computeDesiredInputType(HInstruction input) {
1462 // TODO(floitsch): we want the target to be a function.
1463 if (input == target) return HType.UNKNOWN;
1464 return HType.INTEGER;
1465 }
1466
1467 // TODO(floitsch): make class abstract instead of adding an abstract method.
1468 abstract accept(HVisitor visitor);
1469 }
1470
1471 class HShiftLeft extends HBinaryBitOp {
1472 HShiftLeft(HStatic target, HInstruction left, HInstruction right)
1473 : super(target, left, right);
1474 accept(HVisitor visitor) => visitor.visitShiftLeft(this);
1475
1476 ShiftLeftOperation get operation() => const ShiftLeftOperation();
1477 int typeCode() => 11;
1478 bool typeEquals(other) => other is HShiftLeft;
1479 bool dataEquals(HInstruction other) => true;
1480 }
1481
1482 class HShiftRight extends HBinaryBitOp {
1483 HShiftRight(HStatic target, HInstruction left, HInstruction right)
1484 : super(target, left, right);
1485 accept(HVisitor visitor) => visitor.visitShiftRight(this);
1486
1487 ShiftRightOperation get operation() => const ShiftRightOperation();
1488 int typeCode() => 12;
1489 bool typeEquals(other) => other is HShiftRight;
1490 bool dataEquals(HInstruction other) => true;
1491 }
1492
1493 class HBitOr extends HBinaryBitOp {
1494 HBitOr(HStatic target, HInstruction left, HInstruction right)
1495 : super(target, left, right);
1496 accept(HVisitor visitor) => visitor.visitBitOr(this);
1497
1498 BitOrOperation get operation() => const BitOrOperation();
1499 int typeCode() => 13;
1500 bool typeEquals(other) => other is HBitOr;
1501 bool dataEquals(HInstruction other) => true;
1502 }
1503
1504 class HBitAnd extends HBinaryBitOp {
1505 HBitAnd(HStatic target, HInstruction left, HInstruction right)
1506 : super(target, left, right);
1507 accept(HVisitor visitor) => visitor.visitBitAnd(this);
1508
1509 BitAndOperation get operation() => const BitAndOperation();
1510 int typeCode() => 14;
1511 bool typeEquals(other) => other is HBitAnd;
1512 bool dataEquals(HInstruction other) => true;
1513 }
1514
1515 class HBitXor extends HBinaryBitOp {
1516 HBitXor(HStatic target, HInstruction left, HInstruction right)
1517 : super(target, left, right);
1518 accept(HVisitor visitor) => visitor.visitBitXor(this);
1519
1520 BitXorOperation get operation() => const BitXorOperation();
1521 int typeCode() => 15;
1522 bool typeEquals(other) => other is HBitXor;
1523 bool dataEquals(HInstruction other) => true;
1524 }
1525
1526 class HInvokeUnary extends HInvokeStatic {
1527 HInvokeUnary(HStatic target, HInstruction input)
1528 : super(Selector.UNARY_OPERATOR, <HInstruction>[target, input]);
1529
1530 HInstruction get operand() => inputs[1];
1531
1532 void prepareGvn() {
1533 // A unary arithmetic expression can take part in global value
1534 // numbering and does not have any side-effects if its input is a
1535 // number.
1536 if (builtin) {
1537 clearAllSideEffects();
1538 setUseGvn();
1539 } else {
1540 setAllSideEffects();
1541 }
1542 }
1543
1544 bool get builtin() => operand.isNumber();
1545
1546 HType computeType() {
1547 HType operandType = operand.type;
1548 if (!operandType.isUnknown()) return operandType;
1549 return HType.UNKNOWN;
1550 }
1551
1552 HType computeDesiredInputType(HInstruction input) {
1553 // TODO(floitsch): we want the target to be a function.
1554 if (input == target) return HType.UNKNOWN;
1555 if (type.isUnknown() || type.isNumber()) return HType.NUMBER;
1556 return HType.UNKNOWN;
1557 }
1558
1559 bool hasExpectedType() => builtin || type.isUnknown();
1560
1561 abstract UnaryOperation get operation();
1562 }
1563
1564 class HNegate extends HInvokeUnary {
1565 HNegate(HStatic target, HInstruction input) : super(target, input);
1566 accept(HVisitor visitor) => visitor.visitNegate(this);
1567
1568 NegateOperation get operation() => const NegateOperation();
1569 int typeCode() => 16;
1570 bool typeEquals(other) => other is HNegate;
1571 bool dataEquals(HInstruction other) => true;
1572 }
1573
1574 class HBitNot extends HInvokeUnary {
1575 HBitNot(HStatic target, HInstruction input) : super(target, input);
1576 accept(HVisitor visitor) => visitor.visitBitNot(this);
1577
1578 bool get builtin() => operand.isInteger();
1579
1580 HType computeType() {
1581 HType operandType = operand.type;
1582 if (!operandType.isUnknown()) return operandType;
1583 return HType.UNKNOWN;
1584 }
1585
1586 HType computeDesiredInputType(HInstruction input) {
1587 // TODO(floitsch): we want the target to be a function.
1588 if (input == target) return HType.UNKNOWN;
1589 return HType.INTEGER;
1590 }
1591
1592 BitNotOperation get operation() => const BitNotOperation();
1593 int typeCode() => 17;
1594 bool typeEquals(other) => other is HBitNot;
1595 bool dataEquals(HInstruction other) => true;
1596 }
1597
1598 class HExit extends HControlFlow {
1599 HExit() : super(const <HInstruction>[]);
1600 toString() => 'exit';
1601 accept(HVisitor visitor) => visitor.visitExit(this);
1602 }
1603
1604 class HGoto extends HControlFlow {
1605 HGoto() : super(const <HInstruction>[]);
1606 toString() => 'goto';
1607 accept(HVisitor visitor) => visitor.visitGoto(this);
1608 }
1609
1610 class HBreak extends HGoto {
1611 final TargetElement target;
1612 final LabelElement label;
1613 HBreak(this.target) : label = null;
1614 HBreak.toLabel(LabelElement label) : label = label, target = label.target;
1615 toString() => (label !== null) ? 'break ${label.labelName}' : 'break';
1616 accept(HVisitor visitor) => visitor.visitBreak(this);
1617 }
1618
1619 class HContinue extends HGoto {
1620 final TargetElement target;
1621 final LabelElement label;
1622 HContinue(this.target) : label = null;
1623 HContinue.toLabel(LabelElement label) : label = label, target = label.target;
1624 toString() => (label !== null) ? 'continue ${label.labelName}' : 'continue';
1625 accept(HVisitor visitor) => visitor.visitContinue(this);
1626 }
1627
1628 class HTry extends HControlFlow {
1629 HParameterValue exception;
1630 HBasicBlock finallyBlock;
1631 HTry() : super(const <HInstruction>[]);
1632 toString() => 'try';
1633 accept(HVisitor visitor) => visitor.visitTry(this);
1634 HBasicBlock get joinBlock() => this.block.successors.last();
1635 }
1636
1637 class HIf extends HConditionalBranch {
1638 bool hasElse;
1639 HIfBlockInformation blockInformation = null;
1640 HIf(HInstruction condition, this.hasElse) : super(<HInstruction>[condition]);
1641 toString() => 'if';
1642 accept(HVisitor visitor) => visitor.visitIf(this);
1643
1644 HBasicBlock get thenBlock() {
1645 assert(block.dominatedBlocks[0] === block.successors[0]);
1646 return block.successors[0];
1647 }
1648
1649 HBasicBlock get elseBlock() {
1650 if (hasElse) {
1651 assert(block.dominatedBlocks[1] === block.successors[1]);
1652 return block.successors[1];
1653 } else {
1654 return null;
1655 }
1656 }
1657
1658 HBasicBlock get joinBlock() => blockInformation.joinBlock;
1659 }
1660
1661 class HLoopBranch extends HConditionalBranch {
1662 static final int CONDITION_FIRST_LOOP = 0;
1663 static final int DO_WHILE_LOOP = 1;
1664
1665 final int kind;
1666 HLoopBranch(HInstruction condition, [this.kind = CONDITION_FIRST_LOOP])
1667 : super(<HInstruction>[condition]);
1668 toString() => 'loop-branch';
1669 accept(HVisitor visitor) => visitor.visitLoopBranch(this);
1670
1671 bool isDoWhile() {
1672 return kind === DO_WHILE_LOOP;
1673 }
1674 }
1675
1676 class HConstant extends HInstruction {
1677 final Constant constant;
1678 HConstant.internal(this.constant, HType type) : super(<HInstruction>[]) {
1679 this.type = type;
1680 }
1681
1682 void prepareGvn() {
1683 assert(!hasSideEffects());
1684 }
1685
1686 toString() => 'literal: $constant';
1687 accept(HVisitor visitor) => visitor.visitConstant(this);
1688 HType computeType() => type;
1689
1690 // Literals have the type they have. It can't be changed.
1691 bool updateType() => false;
1692
1693 bool hasExpectedType() => true;
1694
1695 bool isConstant() => true;
1696 bool isConstantBoolean() => constant.isBool();
1697 bool isConstantNull() => constant.isNull();
1698 bool isConstantNumber() => constant.isNum();
1699 bool isConstantString() => constant.isString();
1700
1701 // Maybe avoid this if the literal is big?
1702 bool isCodeMotionInvariant() => true;
1703 }
1704
1705 class HNot extends HInstruction {
1706 HNot(HInstruction value) : super(<HInstruction>[value]);
1707 void prepareGvn() {
1708 assert(!hasSideEffects());
1709 setUseGvn();
1710 }
1711
1712 HType computeType() => HType.BOOLEAN;
1713 bool hasExpectedType() => true;
1714 HType computeDesiredInputType(HInstruction input) {
1715 return HType.BOOLEAN;
1716 }
1717
1718 accept(HVisitor visitor) => visitor.visitNot(this);
1719 int typeCode() => 18;
1720 bool typeEquals(other) => other is HNot;
1721 bool dataEquals(HInstruction other) => true;
1722 }
1723
1724 class HParameterValue extends HInstruction {
1725 final Element element;
1726
1727 HParameterValue(this.element) : super(<HInstruction>[]);
1728
1729 void prepareGvn() {
1730 assert(!hasSideEffects());
1731 }
1732 toString() => 'parameter ${element.name}';
1733 accept(HVisitor visitor) => visitor.visitParameterValue(this);
1734 bool isCodeMotionInvariant() => true;
1735 }
1736
1737 class HThis extends HParameterValue {
1738 HThis() : super(null);
1739 toString() => 'this';
1740 accept(HVisitor visitor) => visitor.visitThis(this);
1741 }
1742
1743 class HPhi extends HInstruction {
1744 final Element element;
1745
1746 static final IS_NOT_LOGICAL_OPERATOR = 0;
1747 static final IS_AND = 1;
1748 static final IS_OR = 2;
1749
1750 int logicalOperatorType = IS_NOT_LOGICAL_OPERATOR;
1751
1752 // The order of the [inputs] must correspond to the order of the
1753 // predecessor-edges. That is if an input comes from the first predecessor
1754 // of the surrounding block, then the input must be the first in the [HPhi].
1755 HPhi(this.element, List<HInstruction> inputs) : super(inputs);
1756 HPhi.noInputs(Element element) : this(element, <HInstruction>[]);
1757 HPhi.singleInput(Element element, HInstruction input)
1758 : this(element, <HInstruction>[input]);
1759 HPhi.manyInputs(Element element, List<HInstruction> inputs)
1760 : this(element, inputs);
1761
1762 void addInput(HInstruction input) {
1763 assert(isInBasicBlock());
1764 inputs.add(input);
1765 input.usedBy.add(this);
1766 }
1767
1768 // Compute the (shared) type of the inputs if any. If all inputs
1769 // have the same known type return it. If any two inputs have
1770 // different known types, we'll return a conflict -- otherwise we'll
1771 // simply return an unknown type.
1772 HType computeInputsType() {
1773 bool seenUnknown = false;
1774 HType candidateType = inputs[0].type;
1775 for (int i = 1, length = inputs.length; i < length; i++) {
1776 HType inputType = inputs[i].type;
1777 if (inputType.isUnknown()) return HType.UNKNOWN;
1778 candidateType = candidateType.combine(inputType);
1779 if (candidateType.isConflicting()) return HType.CONFLICTING;
1780 }
1781 return candidateType;
1782 }
1783
1784 HType computeType() {
1785 HType inputsType = computeInputsType();
1786 if (!inputsType.isUnknown()) return inputsType;
1787 return super.computeType();
1788 }
1789
1790 HType computeDesiredInputType(HInstruction input) {
1791 if (type.isNumber()) return HType.NUMBER;
1792 if (type.isStringOrArray()) return HType.STRING_OR_ARRAY;
1793 return type;
1794 }
1795
1796 bool hasExpectedType() {
1797 for (int i = 0; i < inputs.length; i++) {
1798 if (type.combine(inputs[i].type).isConflicting()) return false;
1799 }
1800 return true;
1801 }
1802
1803 void setInitialTypeForLoopPhi() {
1804 assert(block.isLoopHeader());
1805 assert(type.isUnknown());
1806 type = inputs[0].type;
1807 }
1808
1809 bool isLogicalOperator() => logicalOperatorType != IS_NOT_LOGICAL_OPERATOR;
1810
1811 String logicalOperator() {
1812 assert(isLogicalOperator());
1813 if (logicalOperatorType == IS_AND) return "&&";
1814 assert(logicalOperatorType == IS_OR);
1815 return "||";
1816 }
1817
1818 toString() => 'phi';
1819 accept(HVisitor visitor) => visitor.visitPhi(this);
1820 }
1821
1822 class HRelational extends HInvokeBinary {
1823 HRelational(HStatic target, HInstruction left, HInstruction right)
1824 : super(target, left, right) {
1825 type = HType.BOOLEAN;
1826 }
1827
1828 void prepareGvn() {
1829 // Relational expressions can take part in global value numbering
1830 // and do not have any side-effects if we know all the inputs are
1831 // numbers. This can be improved for at least equality.
1832 if (builtin) {
1833 clearAllSideEffects();
1834 setUseGvn();
1835 } else {
1836 setAllSideEffects();
1837 }
1838 }
1839
1840 HType computeDesiredInputType(HInstruction input) {
1841 // TODO(floitsch): we want the target to be a function.
1842 if (input == target) return HType.UNKNOWN;
1843 // For all relational operations exept HEquals, we expect to only
1844 // get numbers.
1845 return HType.NUMBER;
1846 }
1847
1848 bool get builtin() => left.isNumber() && right.isNumber();
1849 HType computeType() => HType.BOOLEAN;
1850 // A HRelational goes through the builtin operator or the top level
1851 // element. Therefore, it always has the expected type.
1852 bool hasExpectedType() => true;
1853 // TODO(1603): the class should be marked as abstract.
1854 abstract BinaryOperation get operation();
1855 }
1856
1857 class HEquals extends HRelational {
1858 HEquals(HStatic target, HInstruction left, HInstruction right)
1859 : super(target, left, right);
1860 accept(HVisitor visitor) => visitor.visitEquals(this);
1861
1862 bool get builtin() {
1863 return (left.isNumber() && right.isNumber()) || left is HConstant;
1864 }
1865
1866 HType computeType() => HType.BOOLEAN;
1867
1868 HType computeDesiredInputType(HInstruction input) {
1869 // TODO(floitsch): we want the target to be a function.
1870 if (input == target) return HType.UNKNOWN;
1871 if (left.isNumber() || right.isNumber()) return HType.NUMBER;
1872 return HType.UNKNOWN;
1873 }
1874
1875 EqualsOperation get operation() => const EqualsOperation();
1876 int typeCode() => 19;
1877 bool typeEquals(other) => other is HEquals;
1878 bool dataEquals(HInstruction other) => true;
1879 }
1880
1881 class HIdentity extends HRelational {
1882 HIdentity(HStatic target, HInstruction left, HInstruction right)
1883 : super(target, left, right);
1884 accept(HVisitor visitor) => visitor.visitIdentity(this);
1885
1886 bool get builtin() => true;
1887 HType computeType() => HType.BOOLEAN;
1888 bool hasExpectedType() => true;
1889
1890 HType computeDesiredInputType(HInstruction input) => HType.UNKNOWN;
1891
1892 IdentityOperation get operation() => const IdentityOperation();
1893 int typeCode() => 20;
1894 bool typeEquals(other) => other is HIdentity;
1895 bool dataEquals(HInstruction other) => true;
1896 }
1897
1898 class HGreater extends HRelational {
1899 HGreater(HStatic target, HInstruction left, HInstruction right)
1900 : super(target, left, right);
1901 accept(HVisitor visitor) => visitor.visitGreater(this);
1902
1903 GreaterOperation get operation() => const GreaterOperation();
1904 int typeCode() => 21;
1905 bool typeEquals(other) => other is HGreater;
1906 bool dataEquals(HInstruction other) => true;
1907 }
1908
1909 class HGreaterEqual extends HRelational {
1910 HGreaterEqual(HStatic target, HInstruction left, HInstruction right)
1911 : super(target, left, right);
1912 accept(HVisitor visitor) => visitor.visitGreaterEqual(this);
1913
1914 GreaterEqualOperation get operation() => const GreaterEqualOperation();
1915 int typeCode() => 22;
1916 bool typeEquals(other) => other is HGreaterEqual;
1917 bool dataEquals(HInstruction other) => true;
1918 }
1919
1920 class HLess extends HRelational {
1921 HLess(HStatic target, HInstruction left, HInstruction right)
1922 : super(target, left, right);
1923 accept(HVisitor visitor) => visitor.visitLess(this);
1924
1925 LessOperation get operation() => const LessOperation();
1926 int typeCode() => 23;
1927 bool typeEquals(other) => other is HLess;
1928 bool dataEquals(HInstruction other) => true;
1929 }
1930
1931 class HLessEqual extends HRelational {
1932 HLessEqual(HStatic target, HInstruction left, HInstruction right)
1933 : super(target, left, right);
1934 accept(HVisitor visitor) => visitor.visitLessEqual(this);
1935
1936 LessEqualOperation get operation() => const LessEqualOperation();
1937 int typeCode() => 24;
1938 bool typeEquals(other) => other is HLessEqual;
1939 bool dataEquals(HInstruction other) => true;
1940 }
1941
1942 class HReturn extends HControlFlow {
1943 HReturn(value) : super(<HInstruction>[value]);
1944 toString() => 'return';
1945 accept(HVisitor visitor) => visitor.visitReturn(this);
1946 }
1947
1948 class HThrow extends HControlFlow {
1949 final bool isRethrow;
1950 HThrow(value, [this.isRethrow = false]) : super(<HInstruction>[value]);
1951 toString() => 'throw';
1952 accept(HVisitor visitor) => visitor.visitThrow(this);
1953 }
1954
1955 class HStatic extends HInstruction {
1956 Element element;
1957 HStatic(this.element) : super(<HInstruction>[]);
1958
1959 void prepareGvn() {
1960 if (!element.isAssignable()) {
1961 clearAllSideEffects();
1962 setUseGvn();
1963 }
1964 }
1965 toString() => 'static ${element.name}';
1966 accept(HVisitor visitor) => visitor.visitStatic(this);
1967
1968 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode();
1969 int typeCode() => 25;
1970 bool typeEquals(other) => other is HStatic;
1971 bool dataEquals(HStatic other) => element == other.element;
1972 bool isCodeMotionInvariant() => !element.isAssignable();
1973 }
1974
1975 class HStaticStore extends HInstruction {
1976 Element element;
1977 HStaticStore(this.element, HInstruction value) : super(<HInstruction>[value]);
1978 toString() => 'static store ${element.name}';
1979 accept(HVisitor visitor) => visitor.visitStaticStore(this);
1980
1981 int typeCode() => 26;
1982 bool typeEquals(other) => other is HStaticStore;
1983 bool dataEquals(HStaticStore other) => element == other.element;
1984 }
1985
1986 class HLiteralList extends HInstruction {
1987 HLiteralList(inputs, this.isConst) : super(inputs);
1988 toString() => 'literal list';
1989 accept(HVisitor visitor) => visitor.visitLiteralList(this);
1990 HType computeType() => HType.ARRAY;
1991 bool hasExpectedType() => true;
1992 final bool isConst; // TODO(floitsch): Remove when CTC handles arrays.
1993
1994 void prepareGvn() {
1995 assert(!hasSideEffects());
1996 }
1997 }
1998
1999 class HIndex extends HInvokeStatic {
2000 HIndex(HStatic target, HInstruction receiver, HInstruction index)
2001 : super(Selector.INDEX, <HInstruction>[target, receiver, index]);
2002 toString() => 'index operator';
2003 accept(HVisitor visitor) => visitor.visitIndex(this);
2004
2005 void prepareGvn() {
2006 if (builtin) {
2007 clearAllSideEffects();
2008 } else {
2009 setAllSideEffects();
2010 }
2011 }
2012
2013 HInstruction get receiver() => inputs[1];
2014 HInstruction get index() => inputs[2];
2015
2016 HType computeDesiredInputType(HInstruction input) {
2017 // TODO(floitsch): we want the target to be a function.
2018 if (input == target) return HType.UNKNOWN;
2019 if (input == receiver) return HType.STRING_OR_ARRAY;
2020 return HType.UNKNOWN;
2021 }
2022
2023 bool get builtin() => receiver.isStringOrArray();
2024 HType computeType() => HType.UNKNOWN;
2025 bool hasExpectedType() => false;
2026 }
2027
2028 class HIndexAssign extends HInvokeStatic {
2029 HIndexAssign(HStatic target,
2030 HInstruction receiver,
2031 HInstruction index,
2032 HInstruction value)
2033 : super(Selector.INDEX_SET,
2034 <HInstruction>[target, receiver, index, value]);
2035 toString() => 'index assign operator';
2036 accept(HVisitor visitor) => visitor.visitIndexAssign(this);
2037
2038 HInstruction get receiver() => inputs[1];
2039 HInstruction get index() => inputs[2];
2040 HInstruction get value() => inputs[3];
2041
2042 HType computeDesiredInputType(HInstruction input) {
2043 // TODO(floitsch): we want the target to be a function.
2044 if (input == target) return HType.UNKNOWN;
2045 if (input == receiver) return HType.ARRAY;
2046 return HType.UNKNOWN;
2047 }
2048
2049 bool get builtin() => receiver.isArray();
2050 HType computeType() => value.type;
2051 // This instruction does not yield a new value, so it always
2052 // has the expected type (void).
2053 bool hasExpectedType() => true;
2054 }
2055
2056 class HIs extends HInstruction {
2057 // TODO(ahe): This should be a Type, not Element.
2058 final Element typeExpression;
2059 final bool nullOk;
2060
2061 HIs(this.typeExpression, HInstruction expression, [nullOk = false])
2062 : this.nullOk = nullOk, super(<HInstruction>[expression]);
2063
2064 HInstruction get expression() => inputs[0];
2065
2066 HType computeType() => HType.BOOLEAN;
2067 bool hasExpectedType() => true;
2068
2069 accept(HVisitor visitor) => visitor.visitIs(this);
2070
2071 toString() => "$expression is $typeExpression";
2072 }
2073
2074 class HIfBlockInformation {
2075 final HIf branch;
2076 final SubGraph thenGraph;
2077 final SubGraph elseGraph;
2078 final HBasicBlock joinBlock;
2079 HIfBlockInformation(this.branch,
2080 this.thenGraph,
2081 this.elseGraph,
2082 this.joinBlock);
2083 }
OLDNEW
« no previous file with comments | « frog/leg/ssa/js_names.dart ('k') | frog/leg/ssa/optimize.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698