Class ControlFlowContext
- java.lang.Object
-
- com.tonic.analysis.source.recovery.ControlFlowContext
-
public class ControlFlowContext extends Object
Shared context for control flow recovery operations.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static classControlFlowContext.FieldKeyRepresents a field by its owner class and field name.static classControlFlowContext.JumpKindWhich loop boundary an edge crosses.static classControlFlowContext.LoopFrameAn enclosing loop: its header (label anchor), continue-target (latch/increment) and exit block.static classControlFlowContext.LoopJumpA break/continue jump.static classControlFlowContext.StructuredRegionRepresents a structured control flow region.static classControlFlowContext.SwitchFrameAn enclosingswitch.static classControlFlowContext.SwitchJumpA jump within a switch: leaving it at its merge, or falling through to a siblingcaseHeader.static classControlFlowContext.SwitchJumpKindHow an edge leaves a switch case - out at the merge, or on to the next case.
-
Constructor Summary
Constructors Constructor Description ControlFlowContext(IRMethod irMethod, DominatorTree dominatorTree, LoopAnalysis loopAnalysis, RecoveryContext expressionContext)Creates a recovery context over one method's analyses.
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description voidaddPendingStatements(List<Statement> stmts)Queues statements to be emitted before the next structured statement, as header block instructions of an if or while need.ControlFlowContext.LoopJumpclassifyLoopJump(IRBlock target)Classifies a control-flow edge intotarget.ControlFlowContext.SwitchJumpclassifySwitchJump(IRBlock target)Classifies an edge intotargetrelative to the innermostswitch.List<Statement>collectPendingStatements()Collects and clears any pending statements.Set<IRBlock>getAllStopBlocks()Flattens the stop blocks of every enclosing scope so an inner structure honours the outer exit points too.Map<IRBlock,String>getBlockLabels()Map<IRBlock,List<Statement>>getBlockStatements()Map<IRBlock,ControlFlowContext.StructuredRegion>getBlockToRegion()DominatorTreegetDominatorTree()RecoveryContextgetExpressionContext()Set<IRBlock>getForLoopHeaderBlocks()Set<Integer>getForLoopInductionLocalIndices()Set<SSAValue>getForLoopInductionPhis()Set<IRInstruction>getForLoopInitInstructions()IRMethodgetIrMethod()Deque<Set<ControlFlowContext.FieldKey>>getKnownFalseFieldsStack()Deque<Set<SSAValue>>getKnownFalseValuesStack()StringgetLabel(IRBlock block)intgetLabelCounter()LoopAnalysisgetLoopAnalysis()Deque<ControlFlowContext.LoopFrame>getLoopStack()StringgetOrCreateLabel(IRBlock block)Returns a block's break/continue label, minting "labelN" on first use.List<Statement>getPendingStatements()Set<IRBlock>getProcessedBlocks()ControlFlowContext.StructuredRegiongetRegion(IRBlock block)Deque<Set<IRInstruction>>getSkipInstructionsStack()List<Statement>getStatements(IRBlock block)Deque<Set<IRBlock>>getStopBlocksStack()booleanhasLabel(IRBlock block)booleaninInnermostSwitchCase(IRBlock block)True whenblocklies in a case body of the innermost enclosing switch (is dominated by one of its case headers).IRBlockinnermostLoopExit()IRBlockinnermostLoopHeader()IRBlockinnermostLoopLatch()IRBlockinnermostSwitchMerge()booleanisFieldKnownFalse(String owner, String fieldName)Searches every enclosing scope for a field pinned to false or zero.booleanisForLoopHeader(IRBlock block)booleanisForLoopInductionLocal(int localIndex)booleanisForLoopInductionPhi(SSAValue phiResult)booleanisForLoopInit(IRInstruction instruction)booleanisKnownFalse(SSAValue value)Searches every enclosing scope for a value pinned to false or zero.booleanisProcessed(IRBlock block)voidmarkAsForLoopHeader(IRBlock block)Records a block as a for-loop header, which scopes the induction local checks.voidmarkAsForLoopInductionLocal(int localIndex)Records a local slot as a for-loop induction variable so its PHI declaration is skipped - the variable is declared in the loop's init instead.voidmarkAsForLoopInductionPhi(SSAValue phiResult)Records a PHI as carrying a for-loop induction variable so its declaration is not emitted early.voidmarkAsForLoopInit(IRInstruction instruction)Claims an instruction as a for-loop initializer, permanently skipping it in predecessor blocks because the loop inlines it into its init clause.voidmarkProcessed(IRBlock block)Marks a block as emitted so it is not recovered a second time.voidpopKnownFalseFields()Pops the current known false fields from the stack.voidpopKnownFalseValues()Pops the current known false values from the stack.voidpopLoop()Pops the innermost loop frame, if any.voidpopSkipInstructions()Pops the current skip instructions from the stack.voidpopStopBlocks()Pops the current stop blocks from the stack.voidpopSwitch()Pops the innermost switch frame, if any.voidpushKnownFalseFields(Set<ControlFlowContext.FieldKey> fields)Enters a scope in which the given fields are proven false or zero, the field-level counterpart ofpushKnownFalseValues(java.util.Set<com.tonic.analysis.ssa.value.SSAValue>).voidpushKnownFalseValues(Set<SSAValue> values)Enters a scope in which the given values are proven false or zero, as the then-branch of an inverted condition is.voidpushLoop(IRBlock header, IRBlock continueTarget, IRBlock exit)Enters a loop scope so edges to its exit or continue-target classify as break or continue, recording the current scope depth for labeling.voidpushLoop(IRBlock header, IRBlock continueTarget, IRBlock exit, IRBlock latch)AspushLoop(IRBlock, IRBlock, IRBlock)but records the loop'sfor-update latch.voidpushSkipInstructions(Set<IRInstruction> instructions)Enters a scope that suppresses instructions, as a for-loop does with the increment it lifted into its update clause.voidpushStopBlocks(Set<IRBlock> stopBlocks)Enters a control structure whose recovery must stop at the given blocks.voidpushSwitch(IRBlock header, IRBlock merge, Set<IRBlock> caseHeaders)Enters a switch scope so edges to its merge or sibling cases classify as break or fall-through.voidresetProcessedBlocks()Clears the emitted-block marks and their cached statements so a fresh recovery pass over the same method starts clean.voidsetRegion(IRBlock block, ControlFlowContext.StructuredRegion region)Records the structured shape a block was recovered as.voidsetStatements(IRBlock block, List<Statement> stmts)Records the statements recovered for a block, replacing any earlier set.booleanshouldSkipInstruction(IRInstruction instruction)Tests an instruction against the permanent for-loop init claims and every pushed skip set.Set<IRBlock>switchBoundaries()The boundaries - case headers and merge - of every currently enclosingswitch.
-
-
-
Constructor Detail
-
ControlFlowContext
public ControlFlowContext(IRMethod irMethod, DominatorTree dominatorTree, LoopAnalysis loopAnalysis, RecoveryContext expressionContext)
Creates a recovery context over one method's analyses.- Parameters:
irMethod- the method being recovereddominatorTree- its dominator treeloopAnalysis- its loop analysisexpressionContext- the expression-level recovery context
-
-
Method Detail
-
getIrMethod
public IRMethod getIrMethod()
- Returns:
- the ir method
-
getDominatorTree
public DominatorTree getDominatorTree()
- Returns:
- the dominator tree
-
getLoopAnalysis
public LoopAnalysis getLoopAnalysis()
- Returns:
- the loop analysis
-
getExpressionContext
public RecoveryContext getExpressionContext()
- Returns:
- the expression context
-
getProcessedBlocks
public Set<IRBlock> getProcessedBlocks()
- Returns:
- the live set of blocks recovery has already consumed
-
getBlockStatements
public Map<IRBlock,List<Statement>> getBlockStatements()
- Returns:
- the recovered statements keyed by the block they came from
-
getBlockToRegion
public Map<IRBlock,ControlFlowContext.StructuredRegion> getBlockToRegion()
- Returns:
- the structured region each block was assigned to
-
getBlockLabels
public Map<IRBlock,String> getBlockLabels()
- Returns:
- the labels generated for blocks that are break or continue targets
-
getLoopStack
public Deque<ControlFlowContext.LoopFrame> getLoopStack()
- Returns:
- the enclosing loop frames, innermost first, which resolve break and continue targets and decide when a label is needed
-
getPendingStatements
public List<Statement> getPendingStatements()
- Returns:
- the live queue of statements to emit before the next structured statement
-
getStopBlocksStack
public Deque<Set<IRBlock>> getStopBlocksStack()
- Returns:
- the scoped stack of blocks that bound each enclosing control structure
-
getKnownFalseValuesStack
public Deque<Set<SSAValue>> getKnownFalseValuesStack()
- Returns:
- the scoped stack of SSA values proven false or zero
-
getKnownFalseFieldsStack
public Deque<Set<ControlFlowContext.FieldKey>> getKnownFalseFieldsStack()
- Returns:
- the scoped stack of fields, keyed by owner and name, proven false or zero
-
getSkipInstructionsStack
public Deque<Set<IRInstruction>> getSkipInstructionsStack()
- Returns:
- the scoped stack of instruction sets recovery must not emit, such as a lifted for-loop increment
-
getForLoopInitInstructions
public Set<IRInstruction> getForLoopInitInstructions()
- Returns:
- the instructions permanently skipped because a for-loop claimed them as initializers
-
getForLoopInductionLocalIndices
public Set<Integer> getForLoopInductionLocalIndices()
- Returns:
- the local slots holding for-loop induction variables, whose PHI declarations are skipped
-
getForLoopInductionPhis
public Set<SSAValue> getForLoopInductionPhis()
- Returns:
- the PHI results carrying for-loop induction variables, which must not be declared early
-
getForLoopHeaderBlocks
public Set<IRBlock> getForLoopHeaderBlocks()
- Returns:
- the for-loop header blocks, which scope the induction local index checks
-
getLabelCounter
public int getLabelCounter()
- Returns:
- the label counter
-
markProcessed
public void markProcessed(IRBlock block)
Marks a block as emitted so it is not recovered a second time.- Parameters:
block- the block to mark- Throws:
NumberFormatException- if "yabr.debug.mark" is not an integer
-
isProcessed
public boolean isProcessed(IRBlock block)
- Parameters:
block- the block to test- Returns:
- true if the block has already been emitted
-
resetProcessedBlocks
public void resetProcessedBlocks()
Clears the emitted-block marks and their cached statements so a fresh recovery pass over the same method starts clean.
-
setStatements
public void setStatements(IRBlock block, List<Statement> stmts)
Records the statements recovered for a block, replacing any earlier set.- Parameters:
block- the blockstmts- its statements
-
getStatements
public List<Statement> getStatements(IRBlock block)
- Parameters:
block- the block to look up- Returns:
- its recovered statements, empty if none were recorded
-
setRegion
public void setRegion(IRBlock block, ControlFlowContext.StructuredRegion region)
Records the structured shape a block was recovered as.- Parameters:
block- the blockregion- the region shape
-
getRegion
public ControlFlowContext.StructuredRegion getRegion(IRBlock block)
- Parameters:
block- the block to look up- Returns:
- its recovered region shape, or null if unassigned
-
getOrCreateLabel
public String getOrCreateLabel(IRBlock block)
Returns a block's break/continue label, minting "labelN" on first use.- Parameters:
block- the block to label- Returns:
- the label name
-
hasLabel
public boolean hasLabel(IRBlock block)
- Parameters:
block- the block to test- Returns:
- true if a label has already been created for it
-
getLabel
public String getLabel(IRBlock block)
- Parameters:
block- the block to look up- Returns:
- its label, or null if none was created
-
pushLoop
public void pushLoop(IRBlock header, IRBlock continueTarget, IRBlock exit)
Enters a loop scope so edges to its exit or continue-target classify as break or continue, recording the current scope depth for labeling.- Parameters:
header- the loop header, used as the label anchorcontinueTarget- where a continue jumps toexit- where a break jumps to
-
pushLoop
public void pushLoop(IRBlock header, IRBlock continueTarget, IRBlock exit, IRBlock latch)
AspushLoop(IRBlock, IRBlock, IRBlock)but records the loop'sfor-update latch.- Parameters:
header- the loop header, used as the label anchorcontinueTarget- where a continue jumps toexit- where a break jumps tolatch- the update block that back-edges to the header
-
popLoop
public void popLoop()
Pops the innermost loop frame, if any.
-
pushSwitch
public void pushSwitch(IRBlock header, IRBlock merge, Set<IRBlock> caseHeaders)
Enters a switch scope so edges to its merge or sibling cases classify as break or fall-through.- Parameters:
header- the switch header blockmerge- where control leaves the switchcaseHeaders- the case entry blocks
-
popSwitch
public void popSwitch()
Pops the innermost switch frame, if any.
-
innermostLoopExit
public IRBlock innermostLoopExit()
- Returns:
- the exit, that is the break target, of the innermost enclosing loop, or null when no loop encloses
-
innermostLoopHeader
public IRBlock innermostLoopHeader()
- Returns:
- the header of the innermost enclosing loop, or null when no loop encloses
-
innermostLoopLatch
public IRBlock innermostLoopLatch()
- Returns:
- the
for-update latch of the innermost enclosing loop, or null when none encloses or it is not a counted loop
-
innermostSwitchMerge
public IRBlock innermostSwitchMerge()
- Returns:
- the merge of the innermost enclosing switch, or null when no switch encloses
-
switchBoundaries
public Set<IRBlock> switchBoundaries()
The boundaries - case headers and merge - of every currently enclosingswitch.- Returns:
- the case headers and merges of every enclosing switch
-
inInnermostSwitchCase
public boolean inInnermostSwitchCase(IRBlock block)
True whenblocklies in a case body of the innermost enclosing switch (is dominated by one of its case headers).- Parameters:
block- the block to locate- Returns:
- true if a case header of the innermost switch dominates it
-
classifyLoopJump
public ControlFlowContext.LoopJump classifyLoopJump(IRBlock target)
Classifies a control-flow edge intotarget.- Parameters:
target- the edge destination- Returns:
- the loop jump and its label anchor, or null when the target is not a loop boundary
-
classifySwitchJump
public ControlFlowContext.SwitchJump classifySwitchJump(IRBlock target)
Classifies an edge intotargetrelative to the innermostswitch.- Parameters:
target- the edge destination- Returns:
- the switch jump, or null when the target is not an innermost-switch boundary
-
addPendingStatements
public void addPendingStatements(List<Statement> stmts)
Queues statements to be emitted before the next structured statement, as header block instructions of an if or while need.- Parameters:
stmts- the statements to queue
-
collectPendingStatements
public List<Statement> collectPendingStatements()
Collects and clears any pending statements.- Returns:
- the pending statements, now cleared from context
-
pushStopBlocks
public void pushStopBlocks(Set<IRBlock> stopBlocks)
Enters a control structure whose recovery must stop at the given blocks.- Parameters:
stopBlocks- the blocks that bound this structure
-
popStopBlocks
public void popStopBlocks()
Pops the current stop blocks from the stack.
-
getAllStopBlocks
public Set<IRBlock> getAllStopBlocks()
Flattens the stop blocks of every enclosing scope so an inner structure honours the outer exit points too.- Returns:
- the union of all pushed stop block sets
-
pushSkipInstructions
public void pushSkipInstructions(Set<IRInstruction> instructions)
Enters a scope that suppresses instructions, as a for-loop does with the increment it lifted into its update clause.- Parameters:
instructions- the instructions recovery must not emit inside this scope
-
popSkipInstructions
public void popSkipInstructions()
Pops the current skip instructions from the stack.
-
shouldSkipInstruction
public boolean shouldSkipInstruction(IRInstruction instruction)
Tests an instruction against the permanent for-loop init claims and every pushed skip set.- Parameters:
instruction- the instruction to test- Returns:
- true if recovery should not emit it
-
markAsForLoopInit
public void markAsForLoopInit(IRInstruction instruction)
Claims an instruction as a for-loop initializer, permanently skipping it in predecessor blocks because the loop inlines it into its init clause.- Parameters:
instruction- the initializing instruction
-
isForLoopInit
public boolean isForLoopInit(IRInstruction instruction)
- Parameters:
instruction- the instruction to test- Returns:
- true if a for-loop has claimed it as an initializer
-
markAsForLoopInductionLocal
public void markAsForLoopInductionLocal(int localIndex)
Records a local slot as a for-loop induction variable so its PHI declaration is skipped - the variable is declared in the loop's init instead.- Parameters:
localIndex- the local slot
-
isForLoopInductionLocal
public boolean isForLoopInductionLocal(int localIndex)
- Parameters:
localIndex- the local slot to test- Returns:
- true if the slot holds a for-loop induction variable
-
markAsForLoopInductionPhi
public void markAsForLoopInductionPhi(SSAValue phiResult)
Records a PHI as carrying a for-loop induction variable so its declaration is not emitted early.- Parameters:
phiResult- the PHI result value
-
isForLoopInductionPhi
public boolean isForLoopInductionPhi(SSAValue phiResult)
- Parameters:
phiResult- the PHI result to test- Returns:
- true if the PHI carries a for-loop induction variable
-
markAsForLoopHeader
public void markAsForLoopHeader(IRBlock block)
Records a block as a for-loop header, which scopes the induction local checks.- Parameters:
block- the header block
-
isForLoopHeader
public boolean isForLoopHeader(IRBlock block)
- Parameters:
block- the block to test- Returns:
- true if the block was marked as a for-loop header
-
pushKnownFalseValues
public void pushKnownFalseValues(Set<SSAValue> values)
Enters a scope in which the given values are proven false or zero, as the then-branch of an inverted condition is.- Parameters:
values- the SSA values pinned to false or zero
-
popKnownFalseValues
public void popKnownFalseValues()
Pops the current known false values from the stack.
-
isKnownFalse
public boolean isKnownFalse(SSAValue value)
Searches every enclosing scope for a value pinned to false or zero.- Parameters:
value- the SSA value to test- Returns:
- true if some enclosing scope proved it false or zero
-
pushKnownFalseFields
public void pushKnownFalseFields(Set<ControlFlowContext.FieldKey> fields)
Enters a scope in which the given fields are proven false or zero, the field-level counterpart ofpushKnownFalseValues(java.util.Set<com.tonic.analysis.ssa.value.SSAValue>).- Parameters:
fields- the owner and name pairs pinned to false or zero
-
popKnownFalseFields
public void popKnownFalseFields()
Pops the current known false fields from the stack.
-
isFieldKnownFalse
public boolean isFieldKnownFalse(String owner, String fieldName)
Searches every enclosing scope for a field pinned to false or zero.- Parameters:
owner- the internal name of the class declaring the fieldfieldName- the field name- Returns:
- true if some enclosing scope proved the field false or zero
-
-