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

Unified Diff: sdk/lib/_internal/compiler/implementation/ssa/nodes.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
deleted file mode 100644
index 29731459e1e1ac9d8858995a16f21a719da7b72d..0000000000000000000000000000000000000000
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ /dev/null
@@ -1,3100 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of ssa;
-
-abstract class HVisitor<R> {
- R visitAdd(HAdd node);
- R visitBitAnd(HBitAnd node);
- R visitBitNot(HBitNot node);
- R visitBitOr(HBitOr node);
- R visitBitXor(HBitXor node);
- R visitBoolify(HBoolify node);
- R visitBoundsCheck(HBoundsCheck node);
- R visitBreak(HBreak node);
- R visitConstant(HConstant node);
- R visitContinue(HContinue node);
- R visitDivide(HDivide node);
- R visitExit(HExit node);
- R visitExitTry(HExitTry node);
- R visitFieldGet(HFieldGet node);
- R visitFieldSet(HFieldSet node);
- R visitForeign(HForeign node);
- R visitForeignNew(HForeignNew node);
- R visitGoto(HGoto node);
- R visitGreater(HGreater node);
- R visitGreaterEqual(HGreaterEqual node);
- R visitIdentity(HIdentity node);
- R visitIf(HIf node);
- R visitIndex(HIndex node);
- R visitIndexAssign(HIndexAssign node);
- R visitInterceptor(HInterceptor node);
- R visitInvokeClosure(HInvokeClosure node);
- R visitInvokeDynamicGetter(HInvokeDynamicGetter node);
- R visitInvokeDynamicMethod(HInvokeDynamicMethod node);
- R visitInvokeDynamicSetter(HInvokeDynamicSetter node);
- R visitInvokeStatic(HInvokeStatic node);
- R visitInvokeSuper(HInvokeSuper node);
- R visitInvokeConstructorBody(HInvokeConstructorBody node);
- R visitIs(HIs node);
- R visitIsViaInterceptor(HIsViaInterceptor node);
- R visitLazyStatic(HLazyStatic node);
- R visitLess(HLess node);
- R visitLessEqual(HLessEqual node);
- R visitLiteralList(HLiteralList node);
- R visitLocalGet(HLocalGet node);
- R visitLocalSet(HLocalSet node);
- R visitLocalValue(HLocalValue node);
- R visitLoopBranch(HLoopBranch node);
- R visitMultiply(HMultiply node);
- R visitNegate(HNegate node);
- R visitNot(HNot node);
- R visitOneShotInterceptor(HOneShotInterceptor node);
- R visitParameterValue(HParameterValue node);
- R visitPhi(HPhi node);
- R visitRangeConversion(HRangeConversion node);
- R visitReadModifyWrite(HReadModifyWrite node);
- R visitReturn(HReturn node);
- R visitShiftLeft(HShiftLeft node);
- R visitShiftRight(HShiftRight node);
- R visitStatic(HStatic node);
- R visitStaticStore(HStaticStore node);
- R visitStringConcat(HStringConcat node);
- R visitStringify(HStringify node);
- R visitSubtract(HSubtract node);
- R visitSwitch(HSwitch node);
- R visitThis(HThis node);
- R visitThrow(HThrow node);
- R visitThrowExpression(HThrowExpression node);
- R visitTruncatingDivide(HTruncatingDivide node);
- R visitTry(HTry node);
- R visitTypeConversion(HTypeConversion node);
- R visitTypeKnown(HTypeKnown node);
- R visitReadTypeVariable(HReadTypeVariable node);
- R visitFunctionType(HFunctionType node);
- R visitVoidType(HVoidType node);
- R visitInterfaceType(HInterfaceType node);
- R visitDynamicType(HDynamicType node);
-}
-
-abstract class HGraphVisitor {
- visitDominatorTree(HGraph graph) {
- void visitBasicBlockAndSuccessors(HBasicBlock block) {
- visitBasicBlock(block);
- List dominated = block.dominatedBlocks;
- for (int i = 0; i < dominated.length; i++) {
- visitBasicBlockAndSuccessors(dominated[i]);
- }
- }
-
- visitBasicBlockAndSuccessors(graph.entry);
- }
-
- visitPostDominatorTree(HGraph graph) {
- void visitBasicBlockAndSuccessors(HBasicBlock block) {
- List dominated = block.dominatedBlocks;
- for (int i = dominated.length - 1; i >= 0; i--) {
- visitBasicBlockAndSuccessors(dominated[i]);
- }
- visitBasicBlock(block);
- }
-
- visitBasicBlockAndSuccessors(graph.entry);
- }
-
- visitBasicBlock(HBasicBlock block);
-}
-
-abstract class HInstructionVisitor extends HGraphVisitor {
- HBasicBlock currentBlock;
-
- visitInstruction(HInstruction node);
-
- visitBasicBlock(HBasicBlock node) {
- void visitInstructionList(HInstructionList list) {
- HInstruction instruction = list.first;
- while (instruction != null) {
- visitInstruction(instruction);
- instruction = instruction.next;
- assert(instruction != list.first);
- }
- }
-
- currentBlock = node;
- visitInstructionList(node);
- }
-}
-
-class HGraph {
- HBasicBlock entry;
- HBasicBlock exit;
- HThis thisInstruction;
- /// Receiver parameter, set for methods using interceptor calling convention.
- HParameterValue explicitReceiverParameter;
- bool isRecursiveMethod = false;
- bool calledInLoop = false;
- final List<HBasicBlock> blocks;
-
- // We canonicalize all constants used within a graph so we do not
- // have to worry about them for global value numbering.
- Map<ConstantValue, HConstant> constants;
-
- HGraph()
- : blocks = new List<HBasicBlock>(),
- constants = new Map<ConstantValue, HConstant>() {
- entry = addNewBlock();
- // The exit block will be added later, so it has an id that is
- // after all others in the system.
- exit = new HBasicBlock();
- }
-
- void addBlock(HBasicBlock block) {
- int id = blocks.length;
- block.id = id;
- blocks.add(block);
- assert(identical(blocks[id], block));
- }
-
- HBasicBlock addNewBlock() {
- HBasicBlock result = new HBasicBlock();
- addBlock(result);
- return result;
- }
-
- HBasicBlock addNewLoopHeaderBlock(JumpTarget target,
- List<LabelDefinition> labels) {
- HBasicBlock result = addNewBlock();
- result.loopInformation =
- new HLoopInformation(result, target, labels);
- return result;
- }
-
- HConstant addConstant(ConstantValue constant, Compiler compiler) {
- HConstant result = constants[constant];
- if (result == null) {
- TypeMask type = constant.computeMask(compiler);
- result = new HConstant.internal(constant, type);
- entry.addAtExit(result);
- constants[constant] = result;
- } else if (result.block == null) {
- // The constant was not used anymore.
- entry.addAtExit(result);
- }
- return result;
- }
-
- HConstant addDeferredConstant(ConstantValue constant, PrefixElement prefix,
- Compiler compiler) {
- ConstantValue wrapper = new DeferredConstantValue(constant, prefix);
- compiler.deferredLoadTask.registerConstantDeferredUse(wrapper, prefix);
- return addConstant(wrapper, compiler);
- }
-
- HConstant addConstantInt(int i, Compiler compiler) {
- return addConstant(compiler.backend.constantSystem.createInt(i), compiler);
- }
-
- HConstant addConstantDouble(double d, Compiler compiler) {
- return addConstant(
- compiler.backend.constantSystem.createDouble(d), compiler);
- }
-
- HConstant addConstantString(ast.DartString str,
- Compiler compiler) {
- return addConstant(
- compiler.backend.constantSystem.createString(str),
- compiler);
- }
-
- HConstant addConstantBool(bool value, Compiler compiler) {
- return addConstant(
- compiler.backend.constantSystem.createBool(value), compiler);
- }
-
- HConstant addConstantNull(Compiler compiler) {
- return addConstant(compiler.backend.constantSystem.createNull(), compiler);
- }
-
- void finalize() {
- addBlock(exit);
- exit.open();
- exit.close(new HExit());
- assignDominators();
- }
-
- void assignDominators() {
- // Run through the blocks in order of increasing ids so we are
- // guaranteed that we have computed dominators for all blocks
- // higher up in the dominator tree.
- for (int i = 0, length = blocks.length; i < length; i++) {
- HBasicBlock block = blocks[i];
- List<HBasicBlock> predecessors = block.predecessors;
- if (block.isLoopHeader()) {
- block.assignCommonDominator(predecessors[0]);
- } else {
- for (int j = predecessors.length - 1; j >= 0; j--) {
- block.assignCommonDominator(predecessors[j]);
- }
- }
- }
- }
-
- bool isValid() {
- HValidator validator = new HValidator();
- validator.visitGraph(this);
- return validator.isValid;
- }
-}
-
-class HBaseVisitor extends HGraphVisitor implements HVisitor {
- HBasicBlock currentBlock;
-
- visitBasicBlock(HBasicBlock node) {
- currentBlock = node;
-
- HInstruction instruction = node.first;
- while (instruction != null) {
- instruction.accept(this);
- instruction = instruction.next;
- }
- }
-
- visitInstruction(HInstruction instruction) {}
-
- visitBinaryArithmetic(HBinaryArithmetic node) => visitInvokeBinary(node);
- visitBinaryBitOp(HBinaryBitOp node) => visitInvokeBinary(node);
- visitInvoke(HInvoke node) => visitInstruction(node);
- visitInvokeBinary(HInvokeBinary node) => visitInstruction(node);
- visitInvokeDynamic(HInvokeDynamic node) => visitInvoke(node);
- visitInvokeDynamicField(HInvokeDynamicField node) => visitInvokeDynamic(node);
- visitInvokeUnary(HInvokeUnary node) => visitInstruction(node);
- visitConditionalBranch(HConditionalBranch node) => visitControlFlow(node);
- visitControlFlow(HControlFlow node) => visitInstruction(node);
- visitFieldAccess(HFieldAccess node) => visitInstruction(node);
- visitRelational(HRelational node) => visitInvokeBinary(node);
-
- visitAdd(HAdd node) => visitBinaryArithmetic(node);
- visitBitAnd(HBitAnd node) => visitBinaryBitOp(node);
- visitBitNot(HBitNot node) => visitInvokeUnary(node);
- visitBitOr(HBitOr node) => visitBinaryBitOp(node);
- visitBitXor(HBitXor node) => visitBinaryBitOp(node);
- visitBoolify(HBoolify node) => visitInstruction(node);
- visitBoundsCheck(HBoundsCheck node) => visitCheck(node);
- visitBreak(HBreak node) => visitJump(node);
- visitContinue(HContinue node) => visitJump(node);
- visitCheck(HCheck node) => visitInstruction(node);
- visitConstant(HConstant node) => visitInstruction(node);
- visitDivide(HDivide node) => visitBinaryArithmetic(node);
- visitExit(HExit node) => visitControlFlow(node);
- visitExitTry(HExitTry node) => visitControlFlow(node);
- visitFieldGet(HFieldGet node) => visitFieldAccess(node);
- visitFieldSet(HFieldSet node) => visitFieldAccess(node);
- visitForeign(HForeign node) => visitInstruction(node);
- visitForeignNew(HForeignNew node) => visitForeign(node);
- visitGoto(HGoto node) => visitControlFlow(node);
- visitGreater(HGreater node) => visitRelational(node);
- visitGreaterEqual(HGreaterEqual node) => visitRelational(node);
- visitIdentity(HIdentity node) => visitRelational(node);
- visitIf(HIf node) => visitConditionalBranch(node);
- visitIndex(HIndex node) => visitInstruction(node);
- visitIndexAssign(HIndexAssign node) => visitInstruction(node);
- visitInterceptor(HInterceptor node) => visitInstruction(node);
- visitInvokeClosure(HInvokeClosure node)
- => visitInvokeDynamic(node);
- visitInvokeConstructorBody(HInvokeConstructorBody node)
- => visitInvokeStatic(node);
- visitInvokeDynamicMethod(HInvokeDynamicMethod node)
- => visitInvokeDynamic(node);
- visitInvokeDynamicGetter(HInvokeDynamicGetter node)
- => visitInvokeDynamicField(node);
- visitInvokeDynamicSetter(HInvokeDynamicSetter node)
- => visitInvokeDynamicField(node);
- visitInvokeStatic(HInvokeStatic node) => visitInvoke(node);
- visitInvokeSuper(HInvokeSuper node) => visitInvokeStatic(node);
- visitJump(HJump node) => visitControlFlow(node);
- visitLazyStatic(HLazyStatic node) => visitInstruction(node);
- visitLess(HLess node) => visitRelational(node);
- visitLessEqual(HLessEqual node) => visitRelational(node);
- visitLiteralList(HLiteralList node) => visitInstruction(node);
- visitLocalAccess(HLocalAccess node) => visitInstruction(node);
- visitLocalGet(HLocalGet node) => visitLocalAccess(node);
- visitLocalSet(HLocalSet node) => visitLocalAccess(node);
- visitLocalValue(HLocalValue node) => visitInstruction(node);
- visitLoopBranch(HLoopBranch node) => visitConditionalBranch(node);
- visitNegate(HNegate node) => visitInvokeUnary(node);
- visitNot(HNot node) => visitInstruction(node);
- visitOneShotInterceptor(HOneShotInterceptor node)
- => visitInvokeDynamic(node);
- visitPhi(HPhi node) => visitInstruction(node);
- visitMultiply(HMultiply node) => visitBinaryArithmetic(node);
- visitParameterValue(HParameterValue node) => visitLocalValue(node);
- visitRangeConversion(HRangeConversion node) => visitCheck(node);
- visitReadModifyWrite(HReadModifyWrite node) => visitInstruction(node);
- visitReturn(HReturn node) => visitControlFlow(node);
- visitShiftLeft(HShiftLeft node) => visitBinaryBitOp(node);
- visitShiftRight(HShiftRight node) => visitBinaryBitOp(node);
- visitSubtract(HSubtract node) => visitBinaryArithmetic(node);
- visitSwitch(HSwitch node) => visitControlFlow(node);
- visitStatic(HStatic node) => visitInstruction(node);
- visitStaticStore(HStaticStore node) => visitInstruction(node);
- visitStringConcat(HStringConcat node) => visitInstruction(node);
- visitStringify(HStringify node) => visitInstruction(node);
- visitThis(HThis node) => visitParameterValue(node);
- visitThrow(HThrow node) => visitControlFlow(node);
- visitThrowExpression(HThrowExpression node) => visitInstruction(node);
- visitTruncatingDivide(HTruncatingDivide node) => visitBinaryArithmetic(node);
- visitTry(HTry node) => visitControlFlow(node);
- visitIs(HIs node) => visitInstruction(node);
- visitIsViaInterceptor(HIsViaInterceptor node) => visitInstruction(node);
- visitTypeConversion(HTypeConversion node) => visitCheck(node);
- visitTypeKnown(HTypeKnown node) => visitCheck(node);
- visitReadTypeVariable(HReadTypeVariable node) => visitInstruction(node);
- visitFunctionType(HFunctionType node) => visitInstruction(node);
- visitVoidType(HVoidType node) => visitInstruction(node);
- visitInterfaceType(HInterfaceType node) => visitInstruction(node);
- visitDynamicType(HDynamicType node) => visitInstruction(node);
-}
-
-class SubGraph {
- // The first and last block of the sub-graph.
- final HBasicBlock start;
- final HBasicBlock end;
-
- const SubGraph(this.start, this.end);
-
- bool contains(HBasicBlock block) {
- assert(start != null);
- assert(end != null);
- assert(block != null);
- return start.id <= block.id && block.id <= end.id;
- }
-}
-
-class SubExpression extends SubGraph {
- const SubExpression(HBasicBlock start, HBasicBlock end)
- : super(start, end);
-
- /** Find the condition expression if this sub-expression is a condition. */
- HInstruction get conditionExpression {
- HInstruction last = end.last;
- if (last is HConditionalBranch || last is HSwitch) return last.inputs[0];
- return null;
- }
-}
-
-class HInstructionList {
- HInstruction first = null;
- HInstruction last = null;
-
- bool get isEmpty {
- return first == null;
- }
-
- void internalAddAfter(HInstruction cursor, HInstruction instruction) {
- if (cursor == null) {
- assert(isEmpty);
- first = last = instruction;
- } else if (identical(cursor, last)) {
- last.next = instruction;
- instruction.previous = last;
- last = instruction;
- } else {
- instruction.previous = cursor;
- instruction.next = cursor.next;
- cursor.next.previous = instruction;
- cursor.next = instruction;
- }
- }
-
- void internalAddBefore(HInstruction cursor, HInstruction instruction) {
- if (cursor == null) {
- assert(isEmpty);
- first = last = instruction;
- } else if (identical(cursor, first)) {
- first.previous = instruction;
- instruction.next = first;
- first = instruction;
- } else {
- instruction.next = cursor;
- instruction.previous = cursor.previous;
- cursor.previous.next = instruction;
- cursor.previous = instruction;
- }
- }
-
- void detach(HInstruction instruction) {
- assert(contains(instruction));
- assert(instruction.isInBasicBlock());
- if (instruction.previous == null) {
- first = instruction.next;
- } else {
- instruction.previous.next = instruction.next;
- }
- if (instruction.next == null) {
- last = instruction.previous;
- } else {
- instruction.next.previous = instruction.previous;
- }
- instruction.previous = null;
- instruction.next = null;
- }
-
- void remove(HInstruction instruction) {
- assert(instruction.usedBy.isEmpty);
- detach(instruction);
- }
-
- /** Linear search for [instruction]. */
- bool contains(HInstruction instruction) {
- HInstruction cursor = first;
- while (cursor != null) {
- if (identical(cursor, instruction)) return true;
- cursor = cursor.next;
- }
- return false;
- }
-}
-
-class HBasicBlock extends HInstructionList {
- // The [id] must be such that any successor's id is greater than
- // this [id]. The exception are back-edges.
- int id;
-
- static const int STATUS_NEW = 0;
- static const int STATUS_OPEN = 1;
- static const int STATUS_CLOSED = 2;
- int status = STATUS_NEW;
-
- HInstructionList phis;
-
- HLoopInformation loopInformation = null;
- HBlockFlow blockFlow = null;
- HBasicBlock parentLoopHeader = null;
- bool isLive = true;
-
- final List<HBasicBlock> predecessors;
- List<HBasicBlock> successors;
-
- HBasicBlock dominator = null;
- final List<HBasicBlock> dominatedBlocks;
-
- HBasicBlock() : this.withId(null);
- HBasicBlock.withId(this.id)
- : phis = new HInstructionList(),
- predecessors = <HBasicBlock>[],
- successors = const <HBasicBlock>[],
- dominatedBlocks = <HBasicBlock>[];
-
- int get hashCode => id;
-
- bool isNew() => status == STATUS_NEW;
- bool isOpen() => status == STATUS_OPEN;
- bool isClosed() => status == STATUS_CLOSED;
-
- bool isLoopHeader() {
- return loopInformation != null;
- }
-
- void setBlockFlow(HBlockInformation blockInfo, HBasicBlock continuation) {
- blockFlow = new HBlockFlow(blockInfo, continuation);
- }
-
- bool isLabeledBlock() =>
- blockFlow != null &&
- blockFlow.body is HLabeledBlockInformation;
-
- HBasicBlock get enclosingLoopHeader {
- if (isLoopHeader()) return this;
- return parentLoopHeader;
- }
-
- void open() {
- assert(isNew());
- status = STATUS_OPEN;
- }
-
- void close(HControlFlow end) {
- assert(isOpen());
- addAfter(last, end);
- status = STATUS_CLOSED;
- }
-
- void addAtEntry(HInstruction instruction) {
- assert(instruction is !HPhi);
- internalAddBefore(first, instruction);
- instruction.notifyAddedToBlock(this);
- }
-
- void addAtExit(HInstruction instruction) {
- assert(isClosed());
- assert(last is HControlFlow);
- assert(instruction is !HPhi);
- internalAddBefore(last, instruction);
- instruction.notifyAddedToBlock(this);
- }
-
- void moveAtExit(HInstruction instruction) {
- assert(instruction is !HPhi);
- assert(instruction.isInBasicBlock());
- assert(isClosed());
- assert(last is HControlFlow);
- internalAddBefore(last, instruction);
- instruction.block = this;
- assert(isValid());
- }
-
- void add(HInstruction instruction) {
- assert(instruction is !HControlFlow);
- assert(instruction is !HPhi);
- internalAddAfter(last, instruction);
- instruction.notifyAddedToBlock(this);
- }
-
- void addPhi(HPhi phi) {
- assert(phi.inputs.length == 0 || phi.inputs.length == predecessors.length);
- assert(phi.block == null);
- phis.internalAddAfter(phis.last, phi);
- phi.notifyAddedToBlock(this);
- }
-
- void removePhi(HPhi phi) {
- phis.remove(phi);
- assert(phi.block == this);
- phi.notifyRemovedFromBlock();
- }
-
- void addAfter(HInstruction cursor, HInstruction instruction) {
- assert(cursor is !HPhi);
- assert(instruction is !HPhi);
- assert(isOpen() || isClosed());
- internalAddAfter(cursor, instruction);
- instruction.notifyAddedToBlock(this);
- }
-
- void addBefore(HInstruction cursor, HInstruction instruction) {
- assert(cursor is !HPhi);
- assert(instruction is !HPhi);
- assert(isOpen() || isClosed());
- internalAddBefore(cursor, instruction);
- instruction.notifyAddedToBlock(this);
- }
-
- void remove(HInstruction instruction) {
- assert(isOpen() || isClosed());
- assert(instruction is !HPhi);
- super.remove(instruction);
- assert(instruction.block == this);
- instruction.notifyRemovedFromBlock();
- }
-
- void addSuccessor(HBasicBlock block) {
- if (successors.isEmpty) {
- successors = [block];
- } else {
- successors.add(block);
- }
- block.predecessors.add(this);
- }
-
- void postProcessLoopHeader() {
- assert(isLoopHeader());
- // Only the first entry into the loop is from outside the
- // loop. All other entries must be back edges.
- for (int i = 1, length = predecessors.length; i < length; i++) {
- loopInformation.addBackEdge(predecessors[i]);
- }
- }
-
- /**
- * Rewrites all uses of the [from] instruction to using the [to]
- * instruction instead.
- */
- void rewrite(HInstruction from, HInstruction to) {
- for (HInstruction use in from.usedBy) {
- use.rewriteInput(from, to);
- }
- to.usedBy.addAll(from.usedBy);
- from.usedBy.clear();
- }
-
- /**
- * Rewrites all uses of the [from] instruction to using either the
- * [to] instruction, or a [HCheck] instruction that has better type
- * information on [to], and that dominates the user.
- */
- void rewriteWithBetterUser(HInstruction from, HInstruction to) {
- // BUG(11841): Turn this method into a phase to be run after GVN phases.
- Link<HCheck> better = const Link<HCheck>();
- for (HInstruction user in to.usedBy) {
- if (user == from || user is! HCheck) continue;
- HCheck check = user;
- if (check.checkedInput == to) {
- better = better.prepend(user);
- }
- }
-
- if (better.isEmpty) return rewrite(from, to);
-
- L1: for (HInstruction user in from.usedBy) {
- for (HCheck check in better) {
- if (check.dominates(user)) {
- user.rewriteInput(from, check);
- check.usedBy.add(user);
- continue L1;
- }
- }
- user.rewriteInput(from, to);
- to.usedBy.add(user);
- }
- from.usedBy.clear();
- }
-
- bool isExitBlock() {
- return identical(first, last) && first is HExit;
- }
-
- void addDominatedBlock(HBasicBlock block) {
- assert(isClosed());
- assert(id != null && block.id != null);
- assert(dominatedBlocks.indexOf(block) < 0);
- // Keep the list of dominated blocks sorted such that if there are two
- // succeeding blocks in the list, the predecessor is before the successor.
- // Assume that we add the dominated blocks in the right order.
- int index = dominatedBlocks.length;
- while (index > 0 && dominatedBlocks[index - 1].id > block.id) {
- index--;
- }
- if (index == dominatedBlocks.length) {
- dominatedBlocks.add(block);
- } else {
- dominatedBlocks.insert(index, block);
- }
- assert(block.dominator == null);
- block.dominator = this;
- }
-
- void removeDominatedBlock(HBasicBlock block) {
- assert(isClosed());
- assert(id != null && block.id != null);
- int index = dominatedBlocks.indexOf(block);
- assert(index >= 0);
- if (index == dominatedBlocks.length - 1) {
- dominatedBlocks.removeLast();
- } else {
- dominatedBlocks.removeRange(index, index + 1);
- }
- assert(identical(block.dominator, this));
- block.dominator = null;
- }
-
- void assignCommonDominator(HBasicBlock predecessor) {
- assert(isClosed());
- if (dominator == null) {
- // If this basic block doesn't have a dominator yet we use the
- // given predecessor as the dominator.
- predecessor.addDominatedBlock(this);
- } else if (predecessor.dominator != null) {
- // If the predecessor has a dominator and this basic block has a
- // dominator, we find a common parent in the dominator tree and
- // use that as the dominator.
- HBasicBlock block0 = dominator;
- HBasicBlock block1 = predecessor;
- while (!identical(block0, block1)) {
- if (block0.id > block1.id) {
- block0 = block0.dominator;
- } else {
- block1 = block1.dominator;
- }
- assert(block0 != null && block1 != null);
- }
- if (!identical(dominator, block0)) {
- dominator.removeDominatedBlock(this);
- block0.addDominatedBlock(this);
- }
- }
- }
-
- void forEachPhi(void f(HPhi phi)) {
- HPhi current = phis.first;
- while (current != null) {
- HInstruction saved = current.next;
- f(current);
- current = saved;
- }
- }
-
- void forEachInstruction(void f(HInstruction instruction)) {
- HInstruction current = first;
- while (current != null) {
- HInstruction saved = current.next;
- f(current);
- current = saved;
- }
- }
-
- bool isValid() {
- assert(isClosed());
- HValidator validator = new HValidator();
- validator.visitBasicBlock(this);
- return validator.isValid;
- }
-
- Map<HBasicBlock, bool> dominatesCache;
-
- bool dominates(HBasicBlock other) {
- if (dominatesCache == null) {
- dominatesCache = new Map<HBasicBlock, bool>();
- } else {
- bool res = dominatesCache[other];
- if (res != null) return res;
- }
- do {
- if (identical(this, other)) return dominatesCache[other] = true;
- other = other.dominator;
- } while (other != null && other.id >= id);
- return dominatesCache[other] = false;
- }
-}
-
-abstract class HInstruction implements Spannable {
- Entity sourceElement;
- SourceFileLocation sourcePosition;
-
- final int id;
- static int idCounter;
-
- final List<HInstruction> inputs;
- final List<HInstruction> usedBy;
-
- HBasicBlock block;
- HInstruction previous = null;
- HInstruction next = null;
-
- SideEffects sideEffects = new SideEffects.empty();
- bool _useGvn = false;
-
- // Type codes.
- static const int UNDEFINED_TYPECODE = -1;
- static const int BOOLIFY_TYPECODE = 0;
- static const int TYPE_GUARD_TYPECODE = 1;
- static const int BOUNDS_CHECK_TYPECODE = 2;
- static const int INTEGER_CHECK_TYPECODE = 3;
- static const int INTERCEPTOR_TYPECODE = 4;
- static const int ADD_TYPECODE = 5;
- static const int DIVIDE_TYPECODE = 6;
- static const int MULTIPLY_TYPECODE = 7;
- static const int SUBTRACT_TYPECODE = 8;
- static const int SHIFT_LEFT_TYPECODE = 9;
- static const int BIT_OR_TYPECODE = 10;
- static const int BIT_AND_TYPECODE = 11;
- static const int BIT_XOR_TYPECODE = 12;
- static const int NEGATE_TYPECODE = 13;
- static const int BIT_NOT_TYPECODE = 14;
- static const int NOT_TYPECODE = 15;
- static const int IDENTITY_TYPECODE = 16;
- static const int GREATER_TYPECODE = 17;
- static const int GREATER_EQUAL_TYPECODE = 18;
- static const int LESS_TYPECODE = 19;
- static const int LESS_EQUAL_TYPECODE = 20;
- static const int STATIC_TYPECODE = 21;
- static const int STATIC_STORE_TYPECODE = 22;
- static const int FIELD_GET_TYPECODE = 23;
- static const int TYPE_CONVERSION_TYPECODE = 24;
- static const int TYPE_KNOWN_TYPECODE = 25;
- static const int INVOKE_STATIC_TYPECODE = 26;
- static const int INDEX_TYPECODE = 27;
- static const int IS_TYPECODE = 28;
- static const int INVOKE_DYNAMIC_TYPECODE = 29;
- static const int SHIFT_RIGHT_TYPECODE = 30;
- static const int READ_TYPE_VARIABLE_TYPECODE = 31;
- static const int FUNCTION_TYPE_TYPECODE = 32;
- static const int VOID_TYPE_TYPECODE = 33;
- static const int INTERFACE_TYPE_TYPECODE = 34;
- static const int DYNAMIC_TYPE_TYPECODE = 35;
- static const int TRUNCATING_DIVIDE_TYPECODE = 36;
- static const int IS_VIA_INTERCEPTOR_TYPECODE = 37;
-
- HInstruction(this.inputs, this.instructionType)
- : id = idCounter++, usedBy = <HInstruction>[] {
- assert(inputs.every((e) => e != null));
- }
-
- int get hashCode => id;
-
- bool useGvn() => _useGvn;
- void setUseGvn() { _useGvn = true; }
-
- bool get isMovable => useGvn();
-
- /**
- * A pure instruction is an instruction that does not have any side
- * effect, nor any dependency. They can be moved anywhere in the
- * graph.
- */
- bool isPure() {
- return !sideEffects.hasSideEffects()
- && !sideEffects.dependsOnSomething()
- && !canThrow();
- }
-
- /// Overridden by [HCheck] to return the actual non-[HCheck]
- /// instruction it checks against.
- HInstruction nonCheck() => this;
-
- /// Can this node throw an exception?
- bool canThrow() => false;
-
- /// Does this node potentially affect control flow.
- bool isControlFlow() => false;
-
- bool isExact() => instructionType.isExact || isNull();
-
- bool canBeNull() => instructionType.isNullable;
-
- bool isNull() => instructionType.isEmpty && instructionType.isNullable;
- bool isConflicting() {
- return instructionType.isEmpty && !instructionType.isNullable;
- }
-
- bool canBePrimitive(Compiler compiler) {
- return canBePrimitiveNumber(compiler)
- || canBePrimitiveArray(compiler)
- || canBePrimitiveBoolean(compiler)
- || canBePrimitiveString(compiler)
- || isNull();
- }
-
- bool canBePrimitiveNumber(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- JavaScriptBackend backend = compiler.backend;
- // TODO(sra): It should be possible to test only jsDoubleClass and
- // jsUInt31Class, since all others are superclasses of these two.
- return instructionType.contains(backend.jsNumberClass, classWorld)
- || instructionType.contains(backend.jsIntClass, classWorld)
- || instructionType.contains(backend.jsPositiveIntClass, classWorld)
- || instructionType.contains(backend.jsUInt32Class, classWorld)
- || instructionType.contains(backend.jsUInt31Class, classWorld)
- || instructionType.contains(backend.jsDoubleClass, classWorld);
- }
-
- bool canBePrimitiveBoolean(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- JavaScriptBackend backend = compiler.backend;
- return instructionType.contains(backend.jsBoolClass, classWorld);
- }
-
- bool canBePrimitiveArray(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- JavaScriptBackend backend = compiler.backend;
- return instructionType.contains(backend.jsArrayClass, classWorld)
- || instructionType.contains(backend.jsFixedArrayClass, classWorld)
- || instructionType.contains(backend.jsExtendableArrayClass, classWorld);
- }
-
- bool isIndexablePrimitive(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- JavaScriptBackend backend = compiler.backend;
- return instructionType.containsOnlyString(classWorld)
- || instructionType.satisfies(backend.jsIndexableClass, classWorld);
- }
-
- bool isFixedArray(Compiler compiler) {
- JavaScriptBackend backend = compiler.backend;
- return instructionType.containsOnly(backend.jsFixedArrayClass);
- }
-
- bool isExtendableArray(Compiler compiler) {
- JavaScriptBackend backend = compiler.backend;
- return instructionType.containsOnly(backend.jsExtendableArrayClass);
- }
-
- bool isMutableArray(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- JavaScriptBackend backend = compiler.backend;
- return instructionType.satisfies(backend.jsMutableArrayClass, classWorld);
- }
-
- bool isReadableArray(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- JavaScriptBackend backend = compiler.backend;
- return instructionType.satisfies(backend.jsArrayClass, classWorld);
- }
-
- bool isMutableIndexable(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- JavaScriptBackend backend = compiler.backend;
- return instructionType.satisfies(
- backend.jsMutableIndexableClass, classWorld);
- }
-
- bool isArray(Compiler compiler) => isReadableArray(compiler);
-
- bool canBePrimitiveString(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- JavaScriptBackend backend = compiler.backend;
- return instructionType.contains(backend.jsStringClass, classWorld);
- }
-
- bool isInteger(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- return instructionType.containsOnlyInt(classWorld)
- && !instructionType.isNullable;
- }
-
- bool isUInt32(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- JavaScriptBackend backend = compiler.backend;
- return !instructionType.isNullable
- && instructionType.satisfies(backend.jsUInt32Class, classWorld);
- }
-
- bool isUInt31(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- JavaScriptBackend backend = compiler.backend;
- return !instructionType.isNullable
- && instructionType.satisfies(backend.jsUInt31Class, classWorld);
- }
-
- bool isPositiveInteger(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- JavaScriptBackend backend = compiler.backend;
- return !instructionType.isNullable
- && instructionType.satisfies(backend.jsPositiveIntClass, classWorld);
- }
-
- bool isPositiveIntegerOrNull(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- JavaScriptBackend backend = compiler.backend;
- return instructionType.satisfies(backend.jsPositiveIntClass, classWorld);
- }
-
- bool isIntegerOrNull(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- return instructionType.containsOnlyInt(classWorld);
- }
-
- bool isNumber(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- return instructionType.containsOnlyNum(classWorld)
- && !instructionType.isNullable;
- }
-
- bool isNumberOrNull(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- return instructionType.containsOnlyNum(classWorld);
- }
-
- bool isDouble(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- return instructionType.containsOnlyDouble(classWorld)
- && !instructionType.isNullable;
- }
-
- bool isDoubleOrNull(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- return instructionType.containsOnlyDouble(classWorld);
- }
-
- bool isBoolean(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- return instructionType.containsOnlyBool(classWorld)
- && !instructionType.isNullable;
- }
-
- bool isBooleanOrNull(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- return instructionType.containsOnlyBool(classWorld);
- }
-
- bool isString(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- return instructionType.containsOnlyString(classWorld)
- && !instructionType.isNullable;
- }
-
- bool isStringOrNull(Compiler compiler) {
- ClassWorld classWorld = compiler.world;
- return instructionType.containsOnlyString(classWorld);
- }
-
- bool isPrimitive(Compiler compiler) {
- return (isPrimitiveOrNull(compiler) && !instructionType.isNullable)
- || isNull();
- }
-
- bool isPrimitiveOrNull(Compiler compiler) {
- return isIndexablePrimitive(compiler)
- || isNumberOrNull(compiler)
- || isBooleanOrNull(compiler)
- || isNull();
- }
-
- /**
- * Type of the instruction.
- */
- TypeMask instructionType;
-
- Selector get selector => null;
- HInstruction getDartReceiver(Compiler compiler) => null;
- bool onlyThrowsNSM() => false;
-
- bool isInBasicBlock() => block != null;
-
- bool gvnEquals(HInstruction other) {
- assert(useGvn() && other.useGvn());
- // Check that the type and the sideEffects match.
- bool hasSameType = typeEquals(other);
- assert(hasSameType == (typeCode() == other.typeCode()));
- if (!hasSameType) return false;
- if (sideEffects != other.sideEffects) return false;
- // Check that the inputs match.
- final int inputsLength = inputs.length;
- final List<HInstruction> otherInputs = other.inputs;
- if (inputsLength != otherInputs.length) return false;
- for (int i = 0; i < inputsLength; i++) {
- if (!identical(inputs[i].nonCheck(), otherInputs[i].nonCheck())) {
- return false;
- }
- }
- // Check that the data in the instruction matches.
- return dataEquals(other);
- }
-
- int gvnHashCode() {
- int result = typeCode();
- int length = inputs.length;
- for (int i = 0; i < length; i++) {
- result = (result * 19) + (inputs[i].nonCheck().id) + (result >> 7);
- }
- return result;
- }
-
- // These methods should be overwritten by instructions that
- // participate in global value numbering.
- int typeCode() => HInstruction.UNDEFINED_TYPECODE;
- bool typeEquals(HInstruction other) => false;
- bool dataEquals(HInstruction other) => false;
-
- accept(HVisitor visitor);
-
- void notifyAddedToBlock(HBasicBlock targetBlock) {
- assert(!isInBasicBlock());
- assert(block == null);
- // Add [this] to the inputs' uses.
- for (int i = 0; i < inputs.length; i++) {
- assert(inputs[i].isInBasicBlock());
- inputs[i].usedBy.add(this);
- }
- block = targetBlock;
- assert(isValid());
- }
-
- void notifyRemovedFromBlock() {
- assert(isInBasicBlock());
- assert(usedBy.isEmpty);
-
- // Remove [this] from the inputs' uses.
- for (int i = 0; i < inputs.length; i++) {
- inputs[i].removeUser(this);
- }
- this.block = null;
- assert(isValid());
- }
-
- /// Do a in-place change of [from] to [to]. Warning: this function
- /// does not update [inputs] and [usedBy]. Use [changeUse] instead.
- void rewriteInput(HInstruction from, HInstruction to) {
- for (int i = 0; i < inputs.length; i++) {
- if (identical(inputs[i], from)) inputs[i] = to;
- }
- }
-
- /** Removes all occurrences of [instruction] from [list]. */
- void removeFromList(List<HInstruction> list, HInstruction instruction) {
- int length = list.length;
- int i = 0;
- while (i < length) {
- if (instruction == list[i]) {
- list[i] = list[length - 1];
- length--;
- } else {
- i++;
- }
- }
- list.length = length;
- }
-
- /** Removes all occurrences of [user] from [usedBy]. */
- void removeUser(HInstruction user) {
- removeFromList(usedBy, user);
- }
-
- // Change all uses of [oldInput] by [this] to [newInput]. Also
- // updates the [usedBy] of [oldInput] and [newInput].
- void changeUse(HInstruction oldInput, HInstruction newInput) {
- assert(newInput != null && !identical(oldInput, newInput));
- for (int i = 0; i < inputs.length; i++) {
- if (identical(inputs[i], oldInput)) {
- inputs[i] = newInput;
- newInput.usedBy.add(this);
- }
- }
- removeFromList(oldInput.usedBy, this);
- }
-
- // Compute the set of users of this instruction that is dominated by
- // [other]. If [other] is a user of [this], it is included in the
- // returned set.
- Setlet<HInstruction> dominatedUsers(HInstruction other) {
- // Keep track of all instructions that we have to deal with later
- // and count the number of them that are in the current block.
- Setlet<HInstruction> users = new Setlet<HInstruction>();
- int usersInCurrentBlock = 0;
-
- // Run through all the users and see if they are dominated or
- // potentially dominated by [other].
- HBasicBlock otherBlock = other.block;
- for (int i = 0, length = usedBy.length; i < length; i++) {
- HInstruction current = usedBy[i];
- if (otherBlock.dominates(current.block)) {
- if (identical(current.block, otherBlock)) usersInCurrentBlock++;
- users.add(current);
- }
- }
-
- // Run through all the phis in the same block as [other] and remove them
- // from the users set.
- if (usersInCurrentBlock > 0) {
- for (HPhi phi = otherBlock.phis.first; phi != null; phi = phi.next) {
- if (users.contains(phi)) {
- users.remove(phi);
- if (--usersInCurrentBlock == 0) break;
- }
- }
- }
-
- // Run through all the instructions before [other] and remove them
- // from the users set.
- if (usersInCurrentBlock > 0) {
- HInstruction current = otherBlock.first;
- while (!identical(current, other)) {
- if (users.contains(current)) {
- users.remove(current);
- if (--usersInCurrentBlock == 0) break;
- }
- current = current.next;
- }
- }
-
- return users;
- }
-
- void replaceAllUsersDominatedBy(HInstruction cursor,
- HInstruction newInstruction) {
- Setlet<HInstruction> users = dominatedUsers(cursor);
- for (HInstruction user in users) {
- user.changeUse(this, newInstruction);
- }
- }
-
- void moveBefore(HInstruction other) {
- assert(this is !HControlFlow);
- assert(this is !HPhi);
- assert(other is !HPhi);
- block.detach(this);
- other.block.internalAddBefore(other, this);
- block = other.block;
- }
-
- bool isConstant() => false;
- bool isConstantBoolean() => false;
- bool isConstantNull() => false;
- bool isConstantNumber() => false;
- bool isConstantInteger() => false;
- bool isConstantString() => false;
- bool isConstantList() => false;
- bool isConstantMap() => false;
- bool isConstantFalse() => false;
- bool isConstantTrue() => false;
-
- bool isInterceptor(Compiler compiler) => false;
-
- bool isValid() {
- HValidator validator = new HValidator();
- validator.currentBlock = block;
- validator.visitInstruction(this);
- return validator.isValid;
- }
-
- bool isCodeMotionInvariant() => false;
-
- bool isJsStatement() => false;
-
- bool dominates(HInstruction other) {
- // An instruction does not dominates itself.
- if (this == other) return false;
- if (block != other.block) return block.dominates(other.block);
-
- HInstruction current = this.next;
- while (current != null) {
- if (current == other) return true;
- current = current.next;
- }
- return false;
- }
-
- HInstruction convertType(Compiler compiler, DartType type, int kind) {
- if (type == null) return this;
- type = type.unalias(compiler);
- // Only the builder knows how to create [HTypeConversion]
- // instructions with generics. It has the generic type context
- // available.
- assert(type.kind != TypeKind.TYPE_VARIABLE);
- assert(type.treatAsRaw || type.isFunctionType);
- if (type.isDynamic) return this;
- // The type element is either a class or the void element.
- Element element = type.element;
- if (identical(element, compiler.objectClass)) return this;
- JavaScriptBackend backend = compiler.backend;
- if (type.kind != TypeKind.INTERFACE) {
- return new HTypeConversion(type, kind, backend.dynamicType, this);
- } else if (kind == HTypeConversion.BOOLEAN_CONVERSION_CHECK) {
- // Boolean conversion checks work on non-nullable booleans.
- return new HTypeConversion(type, kind, backend.boolType, this);
- } else if (kind == HTypeConversion.CHECKED_MODE_CHECK && !type.treatAsRaw) {
- throw 'creating compound check to $type (this = ${this})';
- } else {
- TypeMask subtype = new TypeMask.subtype(element.declaration,
- compiler.world);
- return new HTypeConversion(type, kind, subtype, this);
- }
- }
-
- /**
- * Return whether the instructions do not belong to a loop or
- * belong to the same loop.
- */
- bool hasSameLoopHeaderAs(HInstruction other) {
- return block.enclosingLoopHeader == other.block.enclosingLoopHeader;
- }
-}
-
-/**
- * Late instructions are used after the main optimization phases. They capture
- * codegen decisions just prior to generating JavaScript.
- */
-abstract class HLateInstruction extends HInstruction {
- HLateInstruction(List<HInstruction> inputs, TypeMask type)
- : super(inputs, type);
-}
-
-class HBoolify extends HInstruction {
- HBoolify(HInstruction value, TypeMask type)
- : super(<HInstruction>[value], type) {
- setUseGvn();
- }
-
- accept(HVisitor visitor) => visitor.visitBoolify(this);
- int typeCode() => HInstruction.BOOLIFY_TYPECODE;
- bool typeEquals(other) => other is HBoolify;
- bool dataEquals(HInstruction other) => true;
-}
-
-/**
- * A [HCheck] instruction is an instruction that might do a dynamic
- * check at runtime on another instruction. To have proper instruction
- * dependencies in the graph, instructions that depend on the check
- * being done reference the [HCheck] instruction instead of the
- * instruction itself.
- */
-abstract class HCheck extends HInstruction {
- HCheck(inputs, type) : super(inputs, type) {
- setUseGvn();
- }
- HInstruction get checkedInput => inputs[0];
- bool isJsStatement() => true;
- bool canThrow() => true;
-
- HInstruction nonCheck() => checkedInput.nonCheck();
-}
-
-class HBoundsCheck extends HCheck {
- static const int ALWAYS_FALSE = 0;
- static const int FULL_CHECK = 1;
- static const int ALWAYS_ABOVE_ZERO = 2;
- static const int ALWAYS_BELOW_LENGTH = 3;
- static const int ALWAYS_TRUE = 4;
- /**
- * Details which tests have been done statically during compilation.
- * Default is that all checks must be performed dynamically.
- */
- int staticChecks = FULL_CHECK;
-
- HBoundsCheck(length, index, array, type)
- : super(<HInstruction>[length, index, array], type);
-
- HInstruction get length => inputs[1];
- HInstruction get index => inputs[0];
- HInstruction get array => inputs[2];
- bool isControlFlow() => true;
-
- accept(HVisitor visitor) => visitor.visitBoundsCheck(this);
- int typeCode() => HInstruction.BOUNDS_CHECK_TYPECODE;
- bool typeEquals(other) => other is HBoundsCheck;
- bool dataEquals(HInstruction other) => true;
-}
-
-abstract class HConditionalBranch extends HControlFlow {
- HConditionalBranch(inputs) : super(inputs);
- HInstruction get condition => inputs[0];
- HBasicBlock get trueBranch => block.successors[0];
- HBasicBlock get falseBranch => block.successors[1];
-}
-
-abstract class HControlFlow extends HInstruction {
- HControlFlow(inputs) : super(inputs, const TypeMask.nonNullEmpty());
- bool isControlFlow() => true;
- bool isJsStatement() => true;
-}
-
-abstract class HInvoke extends HInstruction {
- /**
- * The first argument must be the target: either an [HStatic] node, or
- * the receiver of a method-call. The remaining inputs are the arguments
- * to the invocation.
- */
- HInvoke(List<HInstruction> inputs, type) : super(inputs, type) {
- sideEffects.setAllSideEffects();
- sideEffects.setDependsOnSomething();
- }
- static const int ARGUMENTS_OFFSET = 1;
- bool canThrow() => true;
-
- /**
- * Returns whether this call is on an intercepted method.
- */
- bool get isInterceptedCall {
- // We know it's a selector call if it follows the interceptor
- // calling convention, which adds the actual receiver as a
- // parameter to the call.
- return (selector != null) && (inputs.length - 2 == selector.argumentCount);
- }
-}
-
-abstract class HInvokeDynamic extends HInvoke {
- final InvokeDynamicSpecializer specializer;
- Selector selector;
- Element element;
-
- HInvokeDynamic(Selector selector,
- this.element,
- List<HInstruction> inputs,
- TypeMask type,
- [bool isIntercepted = false])
- : super(inputs, type),
- this.selector = selector,
- specializer = isIntercepted
- ? InvokeDynamicSpecializer.lookupSpecializer(selector)
- : const InvokeDynamicSpecializer();
- toString() => 'invoke dynamic: $selector';
- HInstruction get receiver => inputs[0];
- HInstruction getDartReceiver(Compiler compiler) {
- return isCallOnInterceptor(compiler) ? inputs[1] : inputs[0];
- }
-
- /**
- * Returns whether this call is on an interceptor object.
- */
- bool isCallOnInterceptor(Compiler compiler) {
- return isInterceptedCall && receiver.isInterceptor(compiler);
- }
-
- int typeCode() => HInstruction.INVOKE_DYNAMIC_TYPECODE;
- bool typeEquals(other) => other is HInvokeDynamic;
- bool dataEquals(HInvokeDynamic other) {
- // Use the name and the kind instead of [Selector.operator==]
- // because we don't need to check the arity (already checked in
- // [gvnEquals]), and the receiver types may not be in sync.
- return selector.name == other.selector.name
- && selector.kind == other.selector.kind;
- }
-}
-
-class HInvokeClosure extends HInvokeDynamic {
- HInvokeClosure(Selector selector, List<HInstruction> inputs, TypeMask type)
- : super(selector, null, inputs, type) {
- assert(selector.isClosureCall);
- }
- accept(HVisitor visitor) => visitor.visitInvokeClosure(this);
-}
-
-class HInvokeDynamicMethod extends HInvokeDynamic {
- HInvokeDynamicMethod(Selector selector,
- List<HInstruction> inputs,
- TypeMask type,
- [bool isIntercepted = false])
- : super(selector, null, inputs, type, isIntercepted);
-
- String toString() => 'invoke dynamic method: $selector';
- accept(HVisitor visitor) => visitor.visitInvokeDynamicMethod(this);
-}
-
-abstract class HInvokeDynamicField extends HInvokeDynamic {
- HInvokeDynamicField(
- Selector selector, Element element, List<HInstruction> inputs,
- TypeMask type)
- : super(selector, element, inputs, type);
- toString() => 'invoke dynamic field: $selector';
-}
-
-class HInvokeDynamicGetter extends HInvokeDynamicField {
- HInvokeDynamicGetter(selector, element, inputs, type)
- : super(selector, element, inputs, type);
- toString() => 'invoke dynamic getter: $selector';
- accept(HVisitor visitor) => visitor.visitInvokeDynamicGetter(this);
-}
-
-class HInvokeDynamicSetter extends HInvokeDynamicField {
- HInvokeDynamicSetter(selector, element, inputs, type)
- : super(selector, element, inputs, type);
- toString() => 'invoke dynamic setter: $selector';
- accept(HVisitor visitor) => visitor.visitInvokeDynamicSetter(this);
-}
-
-class HInvokeStatic extends HInvoke {
- final Element element;
-
- final bool targetCanThrow;
-
- bool canThrow() => targetCanThrow;
-
- /// If this instruction is a call to a constructor, [instantiatedTypes]
- /// contains the type(s) used in the (Dart) `New` expression(s). The
- /// [instructionType] of this node is not enough, because we also need the
- /// type arguments. See also [SsaFromAstMixin.currentInlinedInstantiations].
- List<DartType> instantiatedTypes;
-
- /** The first input must be the target. */
- HInvokeStatic(this.element, inputs, TypeMask type,
- {this.targetCanThrow: true})
- : super(inputs, type);
-
- toString() => 'invoke static: $element';
- accept(HVisitor visitor) => visitor.visitInvokeStatic(this);
- int typeCode() => HInstruction.INVOKE_STATIC_TYPECODE;
-}
-
-class HInvokeSuper extends HInvokeStatic {
- /** The class where the call to super is being done. */
- final ClassElement caller;
- final bool isSetter;
- final Selector selector;
-
- HInvokeSuper(Element element,
- this.caller,
- this.selector,
- inputs,
- type,
- {this.isSetter})
- : super(element, inputs, type);
-
- HInstruction get receiver => inputs[0];
- HInstruction getDartReceiver(Compiler compiler) {
- return isCallOnInterceptor(compiler) ? inputs[1] : inputs[0];
- }
-
- /**
- * Returns whether this call is on an interceptor object.
- */
- bool isCallOnInterceptor(Compiler compiler) {
- return isInterceptedCall && receiver.isInterceptor(compiler);
- }
-
- toString() => 'invoke super: $element';
- accept(HVisitor visitor) => visitor.visitInvokeSuper(this);
-
- HInstruction get value {
- assert(isSetter);
- // The 'inputs' are [receiver, value] or [interceptor, receiver, value].
- return inputs.last;
- }
-}
-
-class HInvokeConstructorBody extends HInvokeStatic {
- // The 'inputs' are
- // [receiver, arg1, ..., argN] or
- // [interceptor, receiver, arg1, ... argN].
- HInvokeConstructorBody(element, inputs, type)
- : super(element, inputs, type);
-
- String toString() => 'invoke constructor body: ${element.name}';
- accept(HVisitor visitor) => visitor.visitInvokeConstructorBody(this);
-}
-
-abstract class HFieldAccess extends HInstruction {
- final Element element;
-
- HFieldAccess(Element element, List<HInstruction> inputs, TypeMask type)
- : this.element = element, super(inputs, type);
-
- HInstruction get receiver => inputs[0];
-}
-
-class HFieldGet extends HFieldAccess {
- final bool isAssignable;
-
- HFieldGet(Element element,
- HInstruction receiver,
- TypeMask type,
- {bool isAssignable})
- : this.isAssignable = (isAssignable != null)
- ? isAssignable
- : element.isAssignable,
- super(element, <HInstruction>[receiver], type) {
- sideEffects.clearAllSideEffects();
- sideEffects.clearAllDependencies();
- setUseGvn();
- if (this.isAssignable) {
- sideEffects.setDependsOnInstancePropertyStore();
- }
- }
-
- bool isInterceptor(Compiler compiler) {
- if (sourceElement == null) return false;
- // In case of a closure inside an interceptor class, [:this:] is
- // stored in the generated closure class, and accessed through a
- // [HFieldGet].
- JavaScriptBackend backend = compiler.backend;
- if (sourceElement is ThisLocal) {
- ThisLocal thisLocal = sourceElement;
- return backend.isInterceptorClass(thisLocal.enclosingClass);
- }
- return false;
- }
-
- bool canThrow() => receiver.canBeNull();
-
- HInstruction getDartReceiver(Compiler compiler) => receiver;
- bool onlyThrowsNSM() => true;
- bool get isNullCheck => element == null;
-
- accept(HVisitor visitor) => visitor.visitFieldGet(this);
-
- int typeCode() => HInstruction.FIELD_GET_TYPECODE;
- bool typeEquals(other) => other is HFieldGet;
- bool dataEquals(HFieldGet other) => element == other.element;
- String toString() => "FieldGet $element";
-}
-
-class HFieldSet extends HFieldAccess {
- HFieldSet(Element element,
- HInstruction receiver,
- HInstruction value)
- : super(element, <HInstruction>[receiver, value],
- const TypeMask.nonNullEmpty()) {
- sideEffects.clearAllSideEffects();
- sideEffects.clearAllDependencies();
- sideEffects.setChangesInstanceProperty();
- }
-
- bool canThrow() => receiver.canBeNull();
-
- HInstruction getDartReceiver(Compiler compiler) => receiver;
- bool onlyThrowsNSM() => true;
-
- HInstruction get value => inputs[1];
- accept(HVisitor visitor) => visitor.visitFieldSet(this);
-
- bool isJsStatement() => true;
- String toString() => "FieldSet $element";
-}
-
-/**
- * HReadModifyWrite is a late stage instruction for a field (property) update
- * via an assignment operation or pre- or post-increment.
- */
-class HReadModifyWrite extends HLateInstruction {
- static const ASSIGN_OP = 0;
- static const PRE_OP = 1;
- static const POST_OP = 2;
- final Element element;
- final String jsOp;
- final int opKind;
-
- HReadModifyWrite._(Element this.element, this.jsOp, this.opKind,
- List<HInstruction> inputs, TypeMask type)
- : super(inputs, type) {
- sideEffects.clearAllSideEffects();
- sideEffects.clearAllDependencies();
- sideEffects.setChangesInstanceProperty();
- sideEffects.setDependsOnInstancePropertyStore();
- }
-
- HReadModifyWrite.assignOp(Element element, String jsOp,
- HInstruction receiver, HInstruction operand, TypeMask type)
- : this._(element, jsOp, ASSIGN_OP,
- <HInstruction>[receiver, operand], type);
-
- HReadModifyWrite.preOp(Element element, String jsOp,
- HInstruction receiver, TypeMask type)
- : this._(element, jsOp, PRE_OP, <HInstruction>[receiver], type);
-
- HReadModifyWrite.postOp(Element element, String jsOp,
- HInstruction receiver, TypeMask type)
- : this._(element, jsOp, POST_OP, <HInstruction>[receiver], type);
-
- HInstruction get receiver => inputs[0];
-
- bool get isPreOp => opKind == PRE_OP;
- bool get isPostOp => opKind == POST_OP;
- bool get isAssignOp => opKind == ASSIGN_OP;
-
- bool canThrow() => receiver.canBeNull();
-
- HInstruction getDartReceiver(Compiler compiler) => receiver;
- bool onlyThrowsNSM() => true;
-
- HInstruction get value => inputs[1];
- accept(HVisitor visitor) => visitor.visitReadModifyWrite(this);
-
- bool isJsStatement() => isAssignOp;
- String toString() => "ReadModifyWrite $jsOp $opKind $element";
-}
-
-abstract class HLocalAccess extends HInstruction {
- final Local variable;
-
- HLocalAccess(this.variable, List<HInstruction> inputs, TypeMask type)
- : super(inputs, type);
-
- HInstruction get receiver => inputs[0];
-}
-
-class HLocalGet extends HLocalAccess {
- // No need to use GVN for a [HLocalGet], it is just a local
- // access.
- HLocalGet(Local variable, HLocalValue local, TypeMask type)
- : super(variable, <HInstruction>[local], type);
-
- accept(HVisitor visitor) => visitor.visitLocalGet(this);
-
- HLocalValue get local => inputs[0];
-}
-
-class HLocalSet extends HLocalAccess {
- HLocalSet(Local variable, HLocalValue local, HInstruction value)
- : super(variable, <HInstruction>[local, value],
- const TypeMask.nonNullEmpty());
-
- accept(HVisitor visitor) => visitor.visitLocalSet(this);
-
- HLocalValue get local => inputs[0];
- HInstruction get value => inputs[1];
- bool isJsStatement() => true;
-}
-
-class HForeign extends HInstruction {
- final js.Template codeTemplate;
- final bool isStatement;
- final bool _canThrow;
- final native.NativeBehavior nativeBehavior;
-
- HForeign(this.codeTemplate,
- TypeMask type,
- List<HInstruction> inputs,
- {this.isStatement: false,
- SideEffects effects,
- native.NativeBehavior nativeBehavior,
- canThrow: false})
- : this.nativeBehavior = nativeBehavior,
- this._canThrow = canThrow,
- super(inputs, type) {
- if (effects == null && nativeBehavior != null) {
- effects = nativeBehavior.sideEffects;
- }
- if (effects != null) sideEffects.add(effects);
- }
-
- HForeign.statement(codeTemplate, List<HInstruction> inputs,
- SideEffects effects,
- native.NativeBehavior nativeBehavior,
- TypeMask type)
- : this(codeTemplate, type, inputs, isStatement: true,
- effects: effects, nativeBehavior: nativeBehavior);
-
- accept(HVisitor visitor) => visitor.visitForeign(this);
-
- bool isJsStatement() => isStatement;
- bool canThrow() {
- return _canThrow
- || sideEffects.hasSideEffects()
- || sideEffects.dependsOnSomething();
- }
-}
-
-class HForeignNew extends HForeign {
- ClassElement element;
-
- /// If this field is not `null`, this call is from an inlined constructor and
- /// we have to register the instantiated type in the code generator. The
- /// [instructionType] of this node is not enough, because we also need the
- /// type arguments. See also [SsaFromAstMixin.currentInlinedInstantiations].
- List<DartType> instantiatedTypes;
-
- HForeignNew(this.element, TypeMask type, List<HInstruction> inputs,
- [this.instantiatedTypes])
- : super(null, type, inputs);
-
- accept(HVisitor visitor) => visitor.visitForeignNew(this);
-}
-
-abstract class HInvokeBinary extends HInstruction {
- final Selector selector;
- HInvokeBinary(HInstruction left, HInstruction right, this.selector, type)
- : super(<HInstruction>[left, right], type) {
- sideEffects.clearAllSideEffects();
- sideEffects.clearAllDependencies();
- setUseGvn();
- }
-
- HInstruction get left => inputs[0];
- HInstruction get right => inputs[1];
-
- BinaryOperation operation(ConstantSystem constantSystem);
-}
-
-abstract class HBinaryArithmetic extends HInvokeBinary {
- HBinaryArithmetic(left, right, selector, type)
- : super(left, right, selector, type);
- BinaryOperation operation(ConstantSystem constantSystem);
-}
-
-class HAdd extends HBinaryArithmetic {
- HAdd(left, right, selector, type) : super(left, right, selector, type);
- accept(HVisitor visitor) => visitor.visitAdd(this);
-
- BinaryOperation operation(ConstantSystem constantSystem)
- => constantSystem.add;
- int typeCode() => HInstruction.ADD_TYPECODE;
- bool typeEquals(other) => other is HAdd;
- bool dataEquals(HInstruction other) => true;
-}
-
-class HDivide extends HBinaryArithmetic {
- HDivide(left, right, selector, type) : super(left, right, selector, type);
- accept(HVisitor visitor) => visitor.visitDivide(this);
-
- BinaryOperation operation(ConstantSystem constantSystem)
- => constantSystem.divide;
- int typeCode() => HInstruction.DIVIDE_TYPECODE;
- bool typeEquals(other) => other is HDivide;
- bool dataEquals(HInstruction other) => true;
-}
-
-class HMultiply extends HBinaryArithmetic {
- HMultiply(left, right, selector, type) : super(left, right, selector, type);
- accept(HVisitor visitor) => visitor.visitMultiply(this);
-
- BinaryOperation operation(ConstantSystem operations)
- => operations.multiply;
- int typeCode() => HInstruction.MULTIPLY_TYPECODE;
- bool typeEquals(other) => other is HMultiply;
- bool dataEquals(HInstruction other) => true;
-}
-
-class HSubtract extends HBinaryArithmetic {
- HSubtract(left, right, selector, type) : super(left, right, selector, type);
- accept(HVisitor visitor) => visitor.visitSubtract(this);
-
- BinaryOperation operation(ConstantSystem constantSystem)
- => constantSystem.subtract;
- int typeCode() => HInstruction.SUBTRACT_TYPECODE;
- bool typeEquals(other) => other is HSubtract;
- bool dataEquals(HInstruction other) => true;
-}
-
-class HTruncatingDivide extends HBinaryArithmetic {
- HTruncatingDivide(left, right, selector, type)
- : super(left, right, selector, type);
- accept(HVisitor visitor) => visitor.visitTruncatingDivide(this);
-
- BinaryOperation operation(ConstantSystem constantSystem)
- => constantSystem.truncatingDivide;
- int typeCode() => HInstruction.TRUNCATING_DIVIDE_TYPECODE;
- bool typeEquals(other) => other is HTruncatingDivide;
- bool dataEquals(HInstruction other) => true;
-}
-
-/**
- * An [HSwitch] instruction has one input for the incoming
- * value, and one input per constant that it can switch on.
- * Its block has one successor per constant, and one for the default.
- */
-class HSwitch extends HControlFlow {
- HSwitch(List<HInstruction> inputs) : super(inputs);
-
- HConstant constant(int index) => inputs[index + 1];
- HInstruction get expression => inputs[0];
-
- /**
- * Provides the target to jump to if none of the constants match
- * the expression. If the switch had no default case, this is the
- * following join-block.
- */
- HBasicBlock get defaultTarget => block.successors.last;
-
- accept(HVisitor visitor) => visitor.visitSwitch(this);
-
- String toString() => "HSwitch cases = $inputs";
-}
-
-abstract class HBinaryBitOp extends HInvokeBinary {
- HBinaryBitOp(left, right, selector, type)
- : super(left, right, selector, type);
-}
-
-class HShiftLeft extends HBinaryBitOp {
- HShiftLeft(left, right, selector, type) : super(left, right, selector, type);
- accept(HVisitor visitor) => visitor.visitShiftLeft(this);
-
- BinaryOperation operation(ConstantSystem constantSystem)
- => constantSystem.shiftLeft;
- int typeCode() => HInstruction.SHIFT_LEFT_TYPECODE;
- bool typeEquals(other) => other is HShiftLeft;
- bool dataEquals(HInstruction other) => true;
-}
-
-class HShiftRight extends HBinaryBitOp {
- HShiftRight(left, right, selector, type) : super(left, right, selector, type);
- accept(HVisitor visitor) => visitor.visitShiftRight(this);
-
- BinaryOperation operation(ConstantSystem constantSystem)
- => constantSystem.shiftRight;
- int typeCode() => HInstruction.SHIFT_RIGHT_TYPECODE;
- bool typeEquals(other) => other is HShiftRight;
- bool dataEquals(HInstruction other) => true;
-}
-
-class HBitOr extends HBinaryBitOp {
- HBitOr(left, right, selector, type) : super(left, right, selector, type);
- accept(HVisitor visitor) => visitor.visitBitOr(this);
-
- BinaryOperation operation(ConstantSystem constantSystem)
- => constantSystem.bitOr;
- int typeCode() => HInstruction.BIT_OR_TYPECODE;
- bool typeEquals(other) => other is HBitOr;
- bool dataEquals(HInstruction other) => true;
-}
-
-class HBitAnd extends HBinaryBitOp {
- HBitAnd(left, right, selector, type) : super(left, right, selector, type);
- accept(HVisitor visitor) => visitor.visitBitAnd(this);
-
- BinaryOperation operation(ConstantSystem constantSystem)
- => constantSystem.bitAnd;
- int typeCode() => HInstruction.BIT_AND_TYPECODE;
- bool typeEquals(other) => other is HBitAnd;
- bool dataEquals(HInstruction other) => true;
-}
-
-class HBitXor extends HBinaryBitOp {
- HBitXor(left, right, selector, type) : super(left, right, selector, type);
- accept(HVisitor visitor) => visitor.visitBitXor(this);
-
- BinaryOperation operation(ConstantSystem constantSystem)
- => constantSystem.bitXor;
- int typeCode() => HInstruction.BIT_XOR_TYPECODE;
- bool typeEquals(other) => other is HBitXor;
- bool dataEquals(HInstruction other) => true;
-}
-
-abstract class HInvokeUnary extends HInstruction {
- final Selector selector;
- HInvokeUnary(HInstruction input, this.selector, type)
- : super(<HInstruction>[input], type) {
- sideEffects.clearAllSideEffects();
- sideEffects.clearAllDependencies();
- setUseGvn();
- }
-
- HInstruction get operand => inputs[0];
-
- UnaryOperation operation(ConstantSystem constantSystem);
-}
-
-class HNegate extends HInvokeUnary {
- HNegate(input, selector, type) : super(input, selector, type);
- accept(HVisitor visitor) => visitor.visitNegate(this);
-
- UnaryOperation operation(ConstantSystem constantSystem)
- => constantSystem.negate;
- int typeCode() => HInstruction.NEGATE_TYPECODE;
- bool typeEquals(other) => other is HNegate;
- bool dataEquals(HInstruction other) => true;
-}
-
-class HBitNot extends HInvokeUnary {
- HBitNot(input, selector, type) : super(input, selector, type);
- accept(HVisitor visitor) => visitor.visitBitNot(this);
-
- UnaryOperation operation(ConstantSystem constantSystem)
- => constantSystem.bitNot;
- int typeCode() => HInstruction.BIT_NOT_TYPECODE;
- bool typeEquals(other) => other is HBitNot;
- bool dataEquals(HInstruction other) => true;
-}
-
-class HExit extends HControlFlow {
- HExit() : super(const <HInstruction>[]);
- toString() => 'exit';
- accept(HVisitor visitor) => visitor.visitExit(this);
-}
-
-class HGoto extends HControlFlow {
- HGoto() : super(const <HInstruction>[]);
- toString() => 'goto';
- accept(HVisitor visitor) => visitor.visitGoto(this);
-}
-
-abstract class HJump extends HControlFlow {
- final JumpTarget target;
- final LabelDefinition label;
- HJump(this.target) : label = null, super(const <HInstruction>[]);
- HJump.toLabel(LabelDefinition label)
- : label = label, target = label.target, super(const <HInstruction>[]);
-}
-
-class HBreak extends HJump {
- /**
- * Signals that this is a special break instruction for the synthetic loop
- * generatedfor a switch statement with continue statements. See
- * [SsaFromAstMixin.buildComplexSwitchStatement] for detail.
- */
- final bool breakSwitchContinueLoop;
- HBreak(JumpTarget target, {bool this.breakSwitchContinueLoop: false})
- : super(target);
- HBreak.toLabel(LabelDefinition label)
- : breakSwitchContinueLoop = false, super.toLabel(label);
- toString() => (label != null) ? 'break ${label.labelName}' : 'break';
- accept(HVisitor visitor) => visitor.visitBreak(this);
-}
-
-class HContinue extends HJump {
- HContinue(JumpTarget target) : super(target);
- HContinue.toLabel(LabelDefinition label) : super.toLabel(label);
- toString() => (label != null) ? 'continue ${label.labelName}' : 'continue';
- accept(HVisitor visitor) => visitor.visitContinue(this);
-}
-
-class HTry extends HControlFlow {
- HLocalValue exception;
- HBasicBlock catchBlock;
- HBasicBlock finallyBlock;
- HTry() : super(const <HInstruction>[]);
- toString() => 'try';
- accept(HVisitor visitor) => visitor.visitTry(this);
- HBasicBlock get joinBlock => this.block.successors.last;
-}
-
-// An [HExitTry] control flow node is used when the body of a try or
-// the body of a catch contains a return, break or continue. To build
-// the control flow graph, we explicitly mark the body that
-// leads to one of this instruction a predecessor of catch and
-// finally.
-class HExitTry extends HControlFlow {
- HExitTry() : super(const <HInstruction>[]);
- toString() => 'exit try';
- accept(HVisitor visitor) => visitor.visitExitTry(this);
- HBasicBlock get bodyTrySuccessor => block.successors[0];
-}
-
-class HIf extends HConditionalBranch {
- HBlockFlow blockInformation = null;
- HIf(HInstruction condition) : super(<HInstruction>[condition]);
- toString() => 'if';
- accept(HVisitor visitor) => visitor.visitIf(this);
-
- HBasicBlock get thenBlock {
- assert(identical(block.dominatedBlocks[0], block.successors[0]));
- return block.successors[0];
- }
-
- HBasicBlock get elseBlock {
- assert(identical(block.dominatedBlocks[1], block.successors[1]));
- return block.successors[1];
- }
-
- HBasicBlock get joinBlock => blockInformation.continuation;
-}
-
-class HLoopBranch extends HConditionalBranch {
- static const int CONDITION_FIRST_LOOP = 0;
- static const int DO_WHILE_LOOP = 1;
-
- final int kind;
- HLoopBranch(HInstruction condition, [this.kind = CONDITION_FIRST_LOOP])
- : super(<HInstruction>[condition]);
- toString() => 'loop-branch';
- accept(HVisitor visitor) => visitor.visitLoopBranch(this);
-}
-
-class HConstant extends HInstruction {
- final ConstantValue constant;
- HConstant.internal(this.constant, TypeMask constantType)
- : super(<HInstruction>[], constantType);
-
- toString() => 'literal: $constant';
- accept(HVisitor visitor) => visitor.visitConstant(this);
-
- bool isConstant() => true;
- bool isConstantBoolean() => constant.isBool;
- bool isConstantNull() => constant.isNull;
- bool isConstantNumber() => constant.isNum;
- bool isConstantInteger() => constant.isInt;
- bool isConstantString() => constant.isString;
- bool isConstantList() => constant.isList;
- bool isConstantMap() => constant.isMap;
- bool isConstantFalse() => constant.isFalse;
- bool isConstantTrue() => constant.isTrue;
-
- bool isInterceptor(Compiler compiler) => constant.isInterceptor;
-
- // Maybe avoid this if the literal is big?
- bool isCodeMotionInvariant() => true;
-
- set instructionType(type) {
- // Only lists can be specialized. The SSA builder uses the
- // inferrer for finding the type of a constant list. We should
- // have the constant know its type instead.
- if (!isConstantList()) return;
- super.instructionType = type;
- }
-}
-
-class HNot extends HInstruction {
- HNot(HInstruction value, TypeMask type) : super(<HInstruction>[value], type) {
- setUseGvn();
- }
-
- accept(HVisitor visitor) => visitor.visitNot(this);
- int typeCode() => HInstruction.NOT_TYPECODE;
- bool typeEquals(other) => other is HNot;
- bool dataEquals(HInstruction other) => true;
-}
-
-/**
- * An [HLocalValue] represents a local. Unlike [HParameterValue]s its
- * first use must be in an HLocalSet. That is, [HParameterValue]s have a
- * value from the start, whereas [HLocalValue]s need to be initialized first.
- */
-class HLocalValue extends HInstruction {
- HLocalValue(Entity variable, TypeMask type)
- : super(<HInstruction>[], type) {
- sourceElement = variable;
- }
-
- toString() => 'local ${sourceElement.name}';
- accept(HVisitor visitor) => visitor.visitLocalValue(this);
-}
-
-class HParameterValue extends HLocalValue {
- HParameterValue(Entity variable, type) : super(variable, type);
-
- toString() => 'parameter ${sourceElement.name}';
- accept(HVisitor visitor) => visitor.visitParameterValue(this);
-}
-
-class HThis extends HParameterValue {
- HThis(ThisLocal element, TypeMask type) : super(element, type);
-
- ThisLocal get sourceElement => super.sourceElement;
-
- accept(HVisitor visitor) => visitor.visitThis(this);
-
- bool isCodeMotionInvariant() => true;
-
- bool isInterceptor(Compiler compiler) {
- JavaScriptBackend backend = compiler.backend;
- return backend.isInterceptorClass(sourceElement.enclosingClass);
- }
-
- String toString() => 'this';
-}
-
-class HPhi extends HInstruction {
- static const IS_NOT_LOGICAL_OPERATOR = 0;
- static const IS_AND = 1;
- static const IS_OR = 2;
-
- int logicalOperatorType = IS_NOT_LOGICAL_OPERATOR;
-
- // The order of the [inputs] must correspond to the order of the
- // predecessor-edges. That is if an input comes from the first predecessor
- // of the surrounding block, then the input must be the first in the [HPhi].
- HPhi(Local variable, List<HInstruction> inputs, TypeMask type)
- : super(inputs, type) {
- sourceElement = variable;
- }
- HPhi.noInputs(Local variable, TypeMask type)
- : this(variable, <HInstruction>[], type);
- HPhi.singleInput(Local variable, HInstruction input, TypeMask type)
- : this(variable, <HInstruction>[input], type);
- HPhi.manyInputs(Local variable,
- List<HInstruction> inputs,
- TypeMask type)
- : this(variable, inputs, type);
-
- void addInput(HInstruction input) {
- assert(isInBasicBlock());
- inputs.add(input);
- assert(inputs.length <= block.predecessors.length);
- input.usedBy.add(this);
- }
-
- toString() => 'phi';
- accept(HVisitor visitor) => visitor.visitPhi(this);
-}
-
-abstract class HRelational extends HInvokeBinary {
- bool usesBoolifiedInterceptor = false;
- HRelational(left, right, selector, type) : super(left, right, selector, type);
-}
-
-class HIdentity extends HRelational {
- // Cached codegen decision.
- String singleComparisonOp; // null, '===', '=='
-
- HIdentity(left, right, selector, type) : super(left, right, selector, type);
- accept(HVisitor visitor) => visitor.visitIdentity(this);
-
- BinaryOperation operation(ConstantSystem constantSystem)
- => constantSystem.identity;
- int typeCode() => HInstruction.IDENTITY_TYPECODE;
- bool typeEquals(other) => other is HIdentity;
- bool dataEquals(HInstruction other) => true;
-}
-
-class HGreater extends HRelational {
- HGreater(left, right, selector, type) : super(left, right, selector, type);
- accept(HVisitor visitor) => visitor.visitGreater(this);
-
- BinaryOperation operation(ConstantSystem constantSystem)
- => constantSystem.greater;
- int typeCode() => HInstruction.GREATER_TYPECODE;
- bool typeEquals(other) => other is HGreater;
- bool dataEquals(HInstruction other) => true;
-}
-
-class HGreaterEqual extends HRelational {
- HGreaterEqual(left, right, selector, type)
- : super(left, right, selector, type);
- accept(HVisitor visitor) => visitor.visitGreaterEqual(this);
-
- BinaryOperation operation(ConstantSystem constantSystem)
- => constantSystem.greaterEqual;
- int typeCode() => HInstruction.GREATER_EQUAL_TYPECODE;
- bool typeEquals(other) => other is HGreaterEqual;
- bool dataEquals(HInstruction other) => true;
-}
-
-class HLess extends HRelational {
- HLess(left, right, selector, type) : super(left, right, selector, type);
- accept(HVisitor visitor) => visitor.visitLess(this);
-
- BinaryOperation operation(ConstantSystem constantSystem)
- => constantSystem.less;
- int typeCode() => HInstruction.LESS_TYPECODE;
- bool typeEquals(other) => other is HLess;
- bool dataEquals(HInstruction other) => true;
-}
-
-class HLessEqual extends HRelational {
- HLessEqual(left, right, selector, type) : super(left, right, selector, type);
- accept(HVisitor visitor) => visitor.visitLessEqual(this);
-
- BinaryOperation operation(ConstantSystem constantSystem)
- => constantSystem.lessEqual;
- int typeCode() => HInstruction.LESS_EQUAL_TYPECODE;
- bool typeEquals(other) => other is HLessEqual;
- bool dataEquals(HInstruction other) => true;
-}
-
-class HReturn extends HControlFlow {
- HReturn(value) : super(<HInstruction>[value]);
- toString() => 'return';
- accept(HVisitor visitor) => visitor.visitReturn(this);
-}
-
-class HThrowExpression extends HInstruction {
- HThrowExpression(value)
- : super(<HInstruction>[value], const TypeMask.nonNullEmpty());
- toString() => 'throw expression';
- accept(HVisitor visitor) => visitor.visitThrowExpression(this);
- bool canThrow() => true;
-}
-
-class HThrow extends HControlFlow {
- final bool isRethrow;
- HThrow(value, {this.isRethrow: false}) : super(<HInstruction>[value]);
- toString() => 'throw';
- accept(HVisitor visitor) => visitor.visitThrow(this);
-}
-
-class HStatic extends HInstruction {
- final Element element;
- HStatic(this.element, type) : super(<HInstruction>[], type) {
- assert(element != null);
- assert(invariant(this, element.isDeclaration));
- sideEffects.clearAllSideEffects();
- sideEffects.clearAllDependencies();
- if (element.isAssignable) {
- sideEffects.setDependsOnStaticPropertyStore();
- }
- setUseGvn();
- }
- toString() => 'static ${element.name}';
- accept(HVisitor visitor) => visitor.visitStatic(this);
-
- int gvnHashCode() => super.gvnHashCode() ^ element.hashCode;
- int typeCode() => HInstruction.STATIC_TYPECODE;
- bool typeEquals(other) => other is HStatic;
- bool dataEquals(HStatic other) => element == other.element;
- bool isCodeMotionInvariant() => !element.isAssignable;
-}
-
-class HInterceptor extends HInstruction {
- // This field should originally be null to allow GVN'ing all
- // [HInterceptor] on the same input.
- Set<ClassElement> interceptedClasses;
- HInterceptor(HInstruction receiver, TypeMask type)
- : super(<HInstruction>[receiver], type) {
- sideEffects.clearAllSideEffects();
- sideEffects.clearAllDependencies();
- setUseGvn();
- }
- String toString() => 'interceptor on $interceptedClasses';
- accept(HVisitor visitor) => visitor.visitInterceptor(this);
- HInstruction get receiver => inputs[0];
- bool isInterceptor(Compiler compiler) => true;
-
- int typeCode() => HInstruction.INTERCEPTOR_TYPECODE;
- bool typeEquals(other) => other is HInterceptor;
- bool dataEquals(HInterceptor other) {
- return interceptedClasses == other.interceptedClasses
- || (interceptedClasses.length == other.interceptedClasses.length
- && interceptedClasses.containsAll(other.interceptedClasses));
- }
-}
-
-/**
- * A "one-shot" interceptor is a call to a synthetized method that
- * will fetch the interceptor of its first parameter, and make a call
- * on a given selector with the remaining parameters.
- *
- * In order to share the same optimizations with regular interceptor
- * calls, this class extends [HInvokeDynamic] and also has the null
- * constant as the first input.
- */
-class HOneShotInterceptor extends HInvokeDynamic {
- Set<ClassElement> interceptedClasses;
- HOneShotInterceptor(Selector selector,
- List<HInstruction> inputs,
- TypeMask type,
- this.interceptedClasses)
- : super(selector, null, inputs, type, true) {
- assert(inputs[0] is HConstant);
- assert(inputs[0].isNull());
- }
- bool isCallOnInterceptor(Compiler compiler) => true;
-
- String toString() => 'one shot interceptor on $selector';
- accept(HVisitor visitor) => visitor.visitOneShotInterceptor(this);
-}
-
-/** An [HLazyStatic] is a static that is initialized lazily at first read. */
-class HLazyStatic extends HInstruction {
- final Element element;
- HLazyStatic(this.element, type) : super(<HInstruction>[], type) {
- // TODO(4931): The first access has side-effects, but we afterwards we
- // should be able to GVN.
- sideEffects.setAllSideEffects();
- sideEffects.setDependsOnSomething();
- }
-
- toString() => 'lazy static ${element.name}';
- accept(HVisitor visitor) => visitor.visitLazyStatic(this);
-
- int typeCode() => 30;
- // TODO(4931): can we do better here?
- bool isCodeMotionInvariant() => false;
- bool canThrow() => true;
-}
-
-class HStaticStore extends HInstruction {
- Element element;
- HStaticStore(this.element, HInstruction value)
- : super(<HInstruction>[value], const TypeMask.nonNullEmpty()) {
- sideEffects.clearAllSideEffects();
- sideEffects.clearAllDependencies();
- sideEffects.setChangesStaticProperty();
- }
- toString() => 'static store ${element.name}';
- accept(HVisitor visitor) => visitor.visitStaticStore(this);
-
- int typeCode() => HInstruction.STATIC_STORE_TYPECODE;
- bool typeEquals(other) => other is HStaticStore;
- bool dataEquals(HStaticStore other) => element == other.element;
- bool isJsStatement() => true;
-}
-
-class HLiteralList extends HInstruction {
- HLiteralList(List<HInstruction> inputs, TypeMask type) : super(inputs, type);
- toString() => 'literal list';
- accept(HVisitor visitor) => visitor.visitLiteralList(this);
-}
-
-/**
- * The primitive array indexing operation. Note that this instruction
- * does not throw because we generate the checks explicitly.
- */
-class HIndex extends HInstruction {
- final Selector selector;
- HIndex(HInstruction receiver, HInstruction index, this.selector, type)
- : super(<HInstruction>[receiver, index], type) {
- sideEffects.clearAllSideEffects();
- sideEffects.clearAllDependencies();
- sideEffects.setDependsOnIndexStore();
- setUseGvn();
- }
-
- String toString() => 'index operator';
- accept(HVisitor visitor) => visitor.visitIndex(this);
-
- HInstruction get receiver => inputs[0];
- HInstruction get index => inputs[1];
-
- HInstruction getDartReceiver(Compiler compiler) => receiver;
- bool onlyThrowsNSM() => true;
- bool canThrow() => receiver.canBeNull();
-
- int typeCode() => HInstruction.INDEX_TYPECODE;
- bool typeEquals(HInstruction other) => other is HIndex;
- bool dataEquals(HIndex other) => true;
-}
-
-/**
- * The primitive array assignment operation. Note that this instruction
- * does not throw because we generate the checks explicitly.
- */
-class HIndexAssign extends HInstruction {
- final Selector selector;
- HIndexAssign(HInstruction receiver,
- HInstruction index,
- HInstruction value,
- this.selector)
- : super(<HInstruction>[receiver, index, value],
- const TypeMask.nonNullEmpty()) {
- sideEffects.clearAllSideEffects();
- sideEffects.clearAllDependencies();
- sideEffects.setChangesIndex();
- }
- String toString() => 'index assign operator';
- accept(HVisitor visitor) => visitor.visitIndexAssign(this);
-
- HInstruction get receiver => inputs[0];
- HInstruction get index => inputs[1];
- HInstruction get value => inputs[2];
-
- HInstruction getDartReceiver(Compiler compiler) => receiver;
- bool onlyThrowsNSM() => true;
- bool canThrow() => receiver.canBeNull();
-}
-
-class HIs extends HInstruction {
- /// A check against a raw type: 'o is int', 'o is A'.
- static const int RAW_CHECK = 0;
- /// A check against a type with type arguments: 'o is List<int>', 'o is C<T>'.
- static const int COMPOUND_CHECK = 1;
- /// A check against a single type variable: 'o is T'.
- static const int VARIABLE_CHECK = 2;
-
- final DartType typeExpression;
- final int kind;
-
- HIs.direct(DartType typeExpression,
- HInstruction expression,
- TypeMask type)
- : this.internal(typeExpression, [expression], RAW_CHECK, type);
-
- HIs.raw(DartType typeExpression,
- HInstruction expression,
- HInterceptor interceptor,
- TypeMask type)
- : this.internal(
- typeExpression, [expression, interceptor], RAW_CHECK, type);
-
- HIs.compound(DartType typeExpression,
- HInstruction expression,
- HInstruction call,
- TypeMask type)
- : this.internal(typeExpression, [expression, call], COMPOUND_CHECK, type);
-
- HIs.variable(DartType typeExpression,
- HInstruction expression,
- HInstruction call,
- TypeMask type)
- : this.internal(typeExpression, [expression, call], VARIABLE_CHECK, type);
-
- HIs.internal(this.typeExpression, List<HInstruction> inputs, this.kind, type)
- : super(inputs, type) {
- assert(kind >= RAW_CHECK && kind <= VARIABLE_CHECK);
- setUseGvn();
- }
-
- HInstruction get expression => inputs[0];
-
- HInstruction get interceptor {
- assert(kind == RAW_CHECK);
- return inputs.length > 1 ? inputs[1] : null;
- }
-
- HInstruction get checkCall {
- assert(kind == VARIABLE_CHECK || kind == COMPOUND_CHECK);
- return inputs[1];
- }
-
- bool get isRawCheck => kind == RAW_CHECK;
- bool get isVariableCheck => kind == VARIABLE_CHECK;
- bool get isCompoundCheck => kind == COMPOUND_CHECK;
-
- accept(HVisitor visitor) => visitor.visitIs(this);
-
- toString() => "$expression is $typeExpression";
-
- int typeCode() => HInstruction.IS_TYPECODE;
-
- bool typeEquals(HInstruction other) => other is HIs;
-
- bool dataEquals(HIs other) {
- return typeExpression == other.typeExpression
- && kind == other.kind;
- }
-}
-
-/**
- * HIsViaInterceptor is a late-stage instruction for a type test that can be
- * done entirely on an interceptor. It is not a HCheck because the checked
- * input is not one of the inputs.
- */
-class HIsViaInterceptor extends HLateInstruction {
- final DartType typeExpression;
- HIsViaInterceptor(this.typeExpression, HInstruction interceptor,
- TypeMask type)
- : super(<HInstruction>[interceptor], type) {
- setUseGvn();
- }
-
- HInstruction get interceptor => inputs[0];
-
- accept(HVisitor visitor) => visitor.visitIsViaInterceptor(this);
- toString() => "$interceptor is $typeExpression";
- int typeCode() => HInstruction.IS_VIA_INTERCEPTOR_TYPECODE;
- bool typeEquals(HInstruction other) => other is HIsViaInterceptor;
- bool dataEquals(HIs other) {
- return typeExpression == other.typeExpression;
- }
-}
-
-class HTypeConversion extends HCheck {
- final DartType typeExpression;
- final int kind;
- final Selector receiverTypeCheckSelector;
- final bool contextIsTypeArguments;
- TypeMask checkedType; // Not final because we refine it.
-
- static const int CHECKED_MODE_CHECK = 0;
- static const int ARGUMENT_TYPE_CHECK = 1;
- static const int CAST_TYPE_CHECK = 2;
- static const int BOOLEAN_CONVERSION_CHECK = 3;
- static const int RECEIVER_TYPE_CHECK = 4;
-
- HTypeConversion(this.typeExpression, this.kind,
- TypeMask type, HInstruction input,
- [this.receiverTypeCheckSelector])
- : contextIsTypeArguments = false,
- checkedType = type,
- super(<HInstruction>[input], type) {
- assert(!isReceiverTypeCheck || receiverTypeCheckSelector != null);
- assert(typeExpression == null ||
- typeExpression.kind != TypeKind.TYPEDEF);
- sourceElement = input.sourceElement;
- }
-
- HTypeConversion.withTypeRepresentation(this.typeExpression, this.kind,
- TypeMask type, HInstruction input,
- HInstruction typeRepresentation)
- : contextIsTypeArguments = false,
- checkedType = type,
- super(<HInstruction>[input, typeRepresentation],type),
- receiverTypeCheckSelector = null {
- assert(typeExpression.kind != TypeKind.TYPEDEF);
- sourceElement = input.sourceElement;
- }
-
- HTypeConversion.withContext(this.typeExpression, this.kind,
- TypeMask type, HInstruction input,
- HInstruction context,
- {bool this.contextIsTypeArguments})
- : super(<HInstruction>[input, context], type),
- checkedType = type,
- receiverTypeCheckSelector = null {
- assert(typeExpression.kind != TypeKind.TYPEDEF);
- sourceElement = input.sourceElement;
- }
-
- bool get hasTypeRepresentation {
- return typeExpression.isInterfaceType && inputs.length > 1;
- }
- HInstruction get typeRepresentation => inputs[1];
-
- bool get hasContext {
- return typeExpression.isFunctionType && inputs.length > 1;
- }
- HInstruction get context => inputs[1];
-
- HInstruction convertType(Compiler compiler, DartType type, int kind) {
- if (typeExpression == type) return this;
- return super.convertType(compiler, type, kind);
- }
-
- bool get isCheckedModeCheck {
- return kind == CHECKED_MODE_CHECK
- || kind == BOOLEAN_CONVERSION_CHECK;
- }
- bool get isArgumentTypeCheck => kind == ARGUMENT_TYPE_CHECK;
- bool get isReceiverTypeCheck => kind == RECEIVER_TYPE_CHECK;
- bool get isCastTypeCheck => kind == CAST_TYPE_CHECK;
- bool get isBooleanConversionCheck => kind == BOOLEAN_CONVERSION_CHECK;
-
- accept(HVisitor visitor) => visitor.visitTypeConversion(this);
-
- bool isJsStatement() => isControlFlow();
- bool isControlFlow() => isArgumentTypeCheck || isReceiverTypeCheck;
-
- int typeCode() => HInstruction.TYPE_CONVERSION_TYPECODE;
- bool typeEquals(HInstruction other) => other is HTypeConversion;
- bool isCodeMotionInvariant() => false;
-
- bool dataEquals(HTypeConversion other) {
- return kind == other.kind
- && typeExpression == other.typeExpression
- && checkedType == other.checkedType
- && receiverTypeCheckSelector == other.receiverTypeCheckSelector;
- }
-}
-
-/// The [HTypeKnown] instruction marks a value with a refined type.
-class HTypeKnown extends HCheck {
- TypeMask knownType;
- bool _isMovable;
-
- HTypeKnown.pinned(TypeMask knownType, HInstruction input)
- : this.knownType = knownType,
- this._isMovable = false,
- super(<HInstruction>[input], knownType);
-
- HTypeKnown.witnessed(TypeMask knownType, HInstruction input,
- HInstruction witness)
- : this.knownType = knownType,
- this._isMovable = true,
- super(<HInstruction>[input, witness], knownType);
-
- toString() => 'TypeKnown $knownType';
- accept(HVisitor visitor) => visitor.visitTypeKnown(this);
-
- bool isJsStatement() => false;
- bool isControlFlow() => false;
- bool canThrow() => false;
-
- HInstruction get witness => inputs.length == 2 ? inputs[1] : null;
-
- int typeCode() => HInstruction.TYPE_KNOWN_TYPECODE;
- bool typeEquals(HInstruction other) => other is HTypeKnown;
- bool isCodeMotionInvariant() => true;
- bool get isMovable => _isMovable && useGvn();
-
- bool dataEquals(HTypeKnown other) {
- return knownType == other.knownType
- && instructionType == other.instructionType;
- }
-}
-
-class HRangeConversion extends HCheck {
- HRangeConversion(HInstruction input, type)
- : super(<HInstruction>[input], type) {
- sourceElement = input.sourceElement;
- }
-
- bool get isMovable => false;
-
- accept(HVisitor visitor) => visitor.visitRangeConversion(this);
-}
-
-class HStringConcat extends HInstruction {
- final ast.Node node;
- HStringConcat(HInstruction left, HInstruction right, this.node, TypeMask type)
- : super(<HInstruction>[left, right], type) {
- // TODO(sra): Until Issue 9293 is fixed, this false dependency keeps the
- // concats bunched with stringified inputs for much better looking code with
- // fewer temps.
- sideEffects.setDependsOnSomething();
- }
-
- HInstruction get left => inputs[0];
- HInstruction get right => inputs[1];
-
- accept(HVisitor visitor) => visitor.visitStringConcat(this);
- toString() => "string concat";
-}
-
-/**
- * The part of string interpolation which converts and interpolated expression
- * into a String value.
- */
-class HStringify extends HInstruction {
- final ast.Node node;
- HStringify(HInstruction input, this.node, TypeMask type)
- : super(<HInstruction>[input], type) {
- sideEffects.setAllSideEffects();
- sideEffects.setDependsOnSomething();
- }
-
- accept(HVisitor visitor) => visitor.visitStringify(this);
- toString() => "stringify";
-}
-
-/** Non-block-based (aka. traditional) loop information. */
-class HLoopInformation {
- final HBasicBlock header;
- final List<HBasicBlock> blocks;
- final List<HBasicBlock> backEdges;
- final List<LabelDefinition> labels;
- final JumpTarget target;
-
- /** Corresponding block information for the loop. */
- HLoopBlockInformation loopBlockInformation;
-
- HLoopInformation(this.header, this.target, this.labels)
- : blocks = new List<HBasicBlock>(),
- backEdges = new List<HBasicBlock>();
-
- void addBackEdge(HBasicBlock predecessor) {
- backEdges.add(predecessor);
- List<HBasicBlock> workQueue = <HBasicBlock>[predecessor];
- do {
- HBasicBlock current = workQueue.removeLast();
- addBlock(current, workQueue);
- } while (!workQueue.isEmpty);
- }
-
- // Adds a block and transitively all its predecessors in the loop as
- // loop blocks.
- void addBlock(HBasicBlock block, List<HBasicBlock> workQueue) {
- if (identical(block, header)) return;
- HBasicBlock parentHeader = block.parentLoopHeader;
- if (identical(parentHeader, header)) {
- // Nothing to do in this case.
- } else if (parentHeader != null) {
- workQueue.add(parentHeader);
- } else {
- block.parentLoopHeader = header;
- blocks.add(block);
- workQueue.addAll(block.predecessors);
- }
- }
-}
-
-
-/**
- * Embedding of a [HBlockInformation] for block-structure based traversal
- * in a dominator based flow traversal by attaching it to a basic block.
- * To go back to dominator-based traversal, a [HSubGraphBlockInformation]
- * structure can be added in the block structure.
- */
-class HBlockFlow {
- final HBlockInformation body;
- final HBasicBlock continuation;
- HBlockFlow(this.body, this.continuation);
-}
-
-
-/**
- * Information about a syntactic-like structure.
- */
-abstract class HBlockInformation {
- HBasicBlock get start;
- HBasicBlock get end;
- bool accept(HBlockInformationVisitor visitor);
-}
-
-
-/**
- * Information about a statement-like structure.
- */
-abstract class HStatementInformation extends HBlockInformation {
- bool accept(HStatementInformationVisitor visitor);
-}
-
-
-/**
- * Information about an expression-like structure.
- */
-abstract class HExpressionInformation extends HBlockInformation {
- bool accept(HExpressionInformationVisitor visitor);
- HInstruction get conditionExpression;
-}
-
-
-abstract class HStatementInformationVisitor {
- bool visitLabeledBlockInfo(HLabeledBlockInformation info);
- bool visitLoopInfo(HLoopBlockInformation info);
- bool visitIfInfo(HIfBlockInformation info);
- bool visitTryInfo(HTryBlockInformation info);
- bool visitSwitchInfo(HSwitchBlockInformation info);
- bool visitSequenceInfo(HStatementSequenceInformation info);
- // Pseudo-structure embedding a dominator-based traversal into
- // the block-structure traversal. This will eventually go away.
- bool visitSubGraphInfo(HSubGraphBlockInformation info);
-}
-
-
-abstract class HExpressionInformationVisitor {
- bool visitAndOrInfo(HAndOrBlockInformation info);
- bool visitSubExpressionInfo(HSubExpressionBlockInformation info);
-}
-
-
-abstract class HBlockInformationVisitor
- implements HStatementInformationVisitor, HExpressionInformationVisitor {
-}
-
-
-/**
- * Generic class wrapping a [SubGraph] as a block-information until
- * all structures are handled properly.
- */
-class HSubGraphBlockInformation implements HStatementInformation {
- final SubGraph subGraph;
- HSubGraphBlockInformation(this.subGraph);
-
- HBasicBlock get start => subGraph.start;
- HBasicBlock get end => subGraph.end;
-
- bool accept(HStatementInformationVisitor visitor) =>
- visitor.visitSubGraphInfo(this);
-}
-
-/**
- * Generic class wrapping a [SubExpression] as a block-information until
- * expressions structures are handled properly.
- */
-class HSubExpressionBlockInformation implements HExpressionInformation {
- final SubExpression subExpression;
- HSubExpressionBlockInformation(this.subExpression);
-
- HBasicBlock get start => subExpression.start;
- HBasicBlock get end => subExpression.end;
-
- HInstruction get conditionExpression => subExpression.conditionExpression;
-
- bool accept(HExpressionInformationVisitor visitor) =>
- visitor.visitSubExpressionInfo(this);
-}
-
-/** A sequence of separate statements. */
-class HStatementSequenceInformation implements HStatementInformation {
- final List<HStatementInformation> statements;
- HStatementSequenceInformation(this.statements);
-
- HBasicBlock get start => statements[0].start;
- HBasicBlock get end => statements.last.end;
-
- bool accept(HStatementInformationVisitor visitor) =>
- visitor.visitSequenceInfo(this);
-}
-
-class HLabeledBlockInformation implements HStatementInformation {
- final HStatementInformation body;
- final List<LabelDefinition> labels;
- final JumpTarget target;
- final bool isContinue;
-
- HLabeledBlockInformation(this.body,
- List<LabelDefinition> labels,
- {this.isContinue: false}) :
- this.labels = labels, this.target = labels[0].target;
-
- HLabeledBlockInformation.implicit(this.body,
- this.target,
- {this.isContinue: false})
- : this.labels = const<LabelDefinition>[];
-
- HBasicBlock get start => body.start;
- HBasicBlock get end => body.end;
-
- bool accept(HStatementInformationVisitor visitor) =>
- visitor.visitLabeledBlockInfo(this);
-}
-
-class LoopTypeVisitor extends ast.Visitor {
- const LoopTypeVisitor();
- int visitNode(ast.Node node) => HLoopBlockInformation.NOT_A_LOOP;
- int visitWhile(ast.While node) => HLoopBlockInformation.WHILE_LOOP;
- int visitFor(ast.For node) => HLoopBlockInformation.FOR_LOOP;
- int visitDoWhile(ast.DoWhile node) => HLoopBlockInformation.DO_WHILE_LOOP;
- int visitForIn(ast.ForIn node) => HLoopBlockInformation.FOR_IN_LOOP;
- int visitSwitchStatement(ast.SwitchStatement node) =>
- HLoopBlockInformation.SWITCH_CONTINUE_LOOP;
-}
-
-class HLoopBlockInformation implements HStatementInformation {
- static const int WHILE_LOOP = 0;
- static const int FOR_LOOP = 1;
- static const int DO_WHILE_LOOP = 2;
- static const int FOR_IN_LOOP = 3;
- static const int SWITCH_CONTINUE_LOOP = 4;
- static const int NOT_A_LOOP = -1;
-
- final int kind;
- final HExpressionInformation initializer;
- final HExpressionInformation condition;
- final HStatementInformation body;
- final HExpressionInformation updates;
- final JumpTarget target;
- final List<LabelDefinition> labels;
- final SourceFileLocation sourcePosition;
- final SourceFileLocation endSourcePosition;
-
- HLoopBlockInformation(this.kind,
- this.initializer,
- this.condition,
- this.body,
- this.updates,
- this.target,
- this.labels,
- this.sourcePosition,
- this.endSourcePosition) {
- assert(
- (kind == DO_WHILE_LOOP ? body.start : condition.start).isLoopHeader());
- }
-
- HBasicBlock get start {
- if (initializer != null) return initializer.start;
- if (kind == DO_WHILE_LOOP) {
- return body.start;
- }
- return condition.start;
- }
-
- HBasicBlock get loopHeader {
- return kind == DO_WHILE_LOOP ? body.start : condition.start;
- }
-
- HBasicBlock get end {
- if (updates != null) return updates.end;
- if (kind == DO_WHILE_LOOP && condition != null) {
- return condition.end;
- }
- return body.end;
- }
-
- static int loopType(ast.Node node) {
- return node.accept(const LoopTypeVisitor());
- }
-
- bool accept(HStatementInformationVisitor visitor) =>
- visitor.visitLoopInfo(this);
-}
-
-class HIfBlockInformation implements HStatementInformation {
- final HExpressionInformation condition;
- final HStatementInformation thenGraph;
- final HStatementInformation elseGraph;
- HIfBlockInformation(this.condition,
- this.thenGraph,
- this.elseGraph);
-
- HBasicBlock get start => condition.start;
- HBasicBlock get end => elseGraph == null ? thenGraph.end : elseGraph.end;
-
- bool accept(HStatementInformationVisitor visitor) =>
- visitor.visitIfInfo(this);
-}
-
-class HAndOrBlockInformation implements HExpressionInformation {
- final bool isAnd;
- final HExpressionInformation left;
- final HExpressionInformation right;
- HAndOrBlockInformation(this.isAnd,
- this.left,
- this.right);
-
- HBasicBlock get start => left.start;
- HBasicBlock get end => right.end;
-
- // We don't currently use HAndOrBlockInformation.
- HInstruction get conditionExpression {
- return null;
- }
- bool accept(HExpressionInformationVisitor visitor) =>
- visitor.visitAndOrInfo(this);
-}
-
-class HTryBlockInformation implements HStatementInformation {
- final HStatementInformation body;
- final HLocalValue catchVariable;
- final HStatementInformation catchBlock;
- final HStatementInformation finallyBlock;
- HTryBlockInformation(this.body,
- this.catchVariable,
- this.catchBlock,
- this.finallyBlock);
-
- HBasicBlock get start => body.start;
- HBasicBlock get end =>
- finallyBlock == null ? catchBlock.end : finallyBlock.end;
-
- bool accept(HStatementInformationVisitor visitor) =>
- visitor.visitTryInfo(this);
-}
-
-class HSwitchBlockInformation implements HStatementInformation {
- final HExpressionInformation expression;
- final List<HStatementInformation> statements;
- final JumpTarget target;
- final List<LabelDefinition> labels;
-
- HSwitchBlockInformation(this.expression,
- this.statements,
- this.target,
- this.labels);
-
- HBasicBlock get start => expression.start;
- HBasicBlock get end {
- // We don't create a switch block if there are no cases.
- assert(!statements.isEmpty);
- return statements.last.end;
- }
-
- bool accept(HStatementInformationVisitor visitor) =>
- visitor.visitSwitchInfo(this);
-}
-
-class HReadTypeVariable extends HInstruction {
- /// The type variable being read.
- final TypeVariableType dartType;
-
- final bool hasReceiver;
-
- HReadTypeVariable(this.dartType,
- HInstruction receiver,
- TypeMask instructionType)
- : hasReceiver = true,
- super(<HInstruction>[receiver], instructionType) {
- setUseGvn();
- }
-
- HReadTypeVariable.noReceiver(this.dartType,
- HInstruction typeArgument,
- TypeMask instructionType)
- : hasReceiver = false,
- super(<HInstruction>[typeArgument], instructionType) {
- setUseGvn();
- }
-
- accept(HVisitor visitor) => visitor.visitReadTypeVariable(this);
-
- bool canThrow() => false;
-
- int typeCode() => HInstruction.READ_TYPE_VARIABLE_TYPECODE;
- bool typeEquals(HInstruction other) => other is HReadTypeVariable;
-
- bool dataEquals(HReadTypeVariable other) {
- return dartType.element == other.dartType.element
- && hasReceiver == other.hasReceiver;
- }
-}
-
-abstract class HRuntimeType extends HInstruction {
- final DartType dartType;
-
- HRuntimeType(List<HInstruction> inputs,
- this.dartType,
- TypeMask instructionType)
- : super(inputs, instructionType) {
- setUseGvn();
- }
-
- bool canThrow() => false;
-
- int typeCode() {
- throw 'abstract method';
- }
-
- bool typeEquals(HInstruction other) {
- throw 'abstract method';
- }
-
- bool dataEquals(HRuntimeType other) {
- return dartType == other.dartType;
- }
-}
-
-class HFunctionType extends HRuntimeType {
- HFunctionType(List<HInstruction> inputs,
- FunctionType dartType,
- TypeMask instructionType)
- : super(inputs, dartType, instructionType);
-
- accept(HVisitor visitor) => visitor.visitFunctionType(this);
-
- int typeCode() => HInstruction.FUNCTION_TYPE_TYPECODE;
-
- bool typeEquals(HInstruction other) => other is HFunctionType;
-}
-
-class HVoidType extends HRuntimeType {
- HVoidType(VoidType dartType, TypeMask instructionType)
- : super(const <HInstruction>[], dartType, instructionType);
-
- accept(HVisitor visitor) => visitor.visitVoidType(this);
-
- int typeCode() => HInstruction.VOID_TYPE_TYPECODE;
-
- bool typeEquals(HInstruction other) => other is HVoidType;
-}
-
-class HInterfaceType extends HRuntimeType {
- HInterfaceType(List<HInstruction> inputs,
- InterfaceType dartType,
- TypeMask instructionType)
- : super(inputs, dartType, instructionType);
-
- accept(HVisitor visitor) => visitor.visitInterfaceType(this);
-
- int typeCode() => HInstruction.INTERFACE_TYPE_TYPECODE;
-
- bool typeEquals(HInstruction other) => other is HInterfaceType;
-}
-
-class HDynamicType extends HRuntimeType {
- HDynamicType(DynamicType dartType, TypeMask instructionType)
- : super(const <HInstruction>[], dartType, instructionType);
-
- accept(HVisitor visitor) => visitor.visitDynamicType(this);
-
- int typeCode() => HInstruction.DYNAMIC_TYPE_TYPECODE;
-
- bool typeEquals(HInstruction other) => other is HDynamicType;
-}

Powered by Google App Engine
This is Rietveld 408576698