Index: pkg/compiler/lib/src/ssa/nodes.dart |
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart |
deleted file mode 100644 |
index 29731459e1e1ac9d8858995a16f21a719da7b72d..0000000000000000000000000000000000000000 |
--- a/pkg/compiler/lib/src/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; |
-} |