| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
JVM.Data.Analyse.StackMap
Description
Generate a stack map table for a method. This process MUST run last in the high level stage - modifications to the code after this point will invalidate the stack map table and cause invalid class files to be generated.
Synopsis
- data BasicBlock = BasicBlock {
- index :: Int
- instructions :: [Instruction]
- start :: Maybe Label
- end :: Maybe Label
- data Frame = Frame {
- locals :: [LocalVariable]
- stack :: [StackEntry]
- data LocalVariable
- data StackEntry
- lvToStackEntry :: LocalVariable -> StackEntry
- stackEntryToLV :: StackEntry -> LocalVariable
- splitIntoBasicBlocks :: [Instruction] -> [BasicBlock]
- buildLabelToBlockMap :: [BasicBlock] -> Map Label Int
- splitOnLabels :: [Instruction] -> [(Maybe Label, [Instruction])]
- topFrame :: QualifiedClassName -> [MethodAccessFlag] -> MethodDescriptor -> Frame
- analyseBlockDiff :: HasCallStack => Frame -> BasicBlock -> Frame
- diffFrames :: Frame -> Frame -> Label -> StackMapFrame
- lvToVerificationTypeInfo :: LocalVariable -> VerificationTypeInfo
- seToVerificationTypeInfo :: StackEntry -> VerificationTypeInfo
- mergeFrames :: Frame -> Frame -> Maybe Frame
- getSuccessors :: Map Label Int -> Int -> BasicBlock -> [Int]
- computeBlockFrames :: HasCallStack => Frame -> [BasicBlock] -> Map Int Frame
- calculateStackMapFrames :: HasCallStack => QualifiedClassName -> [MethodAccessFlag] -> MethodDescriptor -> [Instruction] -> [StackMapFrame]
- replaceAtOrGrow :: Int -> LocalVariable -> [LocalVariable] -> [LocalVariable]
- replaceAt :: Int -> a -> [a] -> [a]
- type Analyser = Eff '[State Frame, Reader BasicBlock] ()
- pops :: Int -> Analyser
- pushes :: FieldType -> Analyser
- pushesEntry :: StackEntry -> Analyser
- pushesMaybe :: Maybe FieldType -> Analyser
- replaceTop :: FieldType -> Analyser
- loads :: String -> U2 -> Analyser
- stores :: Int -> Analyser
- indexOOBError :: HasCallStack => String -> U2 -> Frame -> BasicBlock -> a
Documentation
data BasicBlock Source #
A basic block is a sequence of instructions with a single entry and exit point. Control flow only enters at the beginning and exits at the end.
Constructors
| BasicBlock | |
Fields
| |
Instances
| Show BasicBlock Source # | |
Defined in JVM.Data.Analyse.StackMap Methods showsPrec :: Int -> BasicBlock -> ShowS # show :: BasicBlock -> String # showList :: [BasicBlock] -> ShowS # | |
| Eq BasicBlock Source # | |
Defined in JVM.Data.Analyse.StackMap | |
Represents the JVM frame state at a particular program point. Used for computing stack map frames required by the JVM verifier.
Constructors
| Frame | |
Fields
| |
data LocalVariable Source #
Represents the type of a local variable slot in the stack frame
Constructors
| Uninitialised | The slot has not been initialised or contains an unusable value |
| LocalVariable FieldType | The slot contains a value of the given type |
Instances
| Show LocalVariable Source # | |
Defined in JVM.Data.Analyse.StackMap Methods showsPrec :: Int -> LocalVariable -> ShowS # show :: LocalVariable -> String # showList :: [LocalVariable] -> ShowS # | |
| Eq LocalVariable Source # | |
Defined in JVM.Data.Analyse.StackMap Methods (==) :: LocalVariable -> LocalVariable -> Bool # (/=) :: LocalVariable -> LocalVariable -> Bool # | |
| Pretty LocalVariable Source # | |
Defined in JVM.Data.Analyse.StackMap | |
data StackEntry Source #
Represents the type of a stack slot.
Constructors
| StackEntry FieldType | A typed value on the stack |
| StackEntryTop | An unusable or uninitialised stack slot |
| StackEntryNull | A null reference on the stack |
Instances
| Show StackEntry Source # | |
Defined in JVM.Data.Analyse.StackMap Methods showsPrec :: Int -> StackEntry -> ShowS # show :: StackEntry -> String # showList :: [StackEntry] -> ShowS # | |
| Eq StackEntry Source # | |
Defined in JVM.Data.Analyse.StackMap | |
| Pretty StackEntry Source # | |
Defined in JVM.Data.Analyse.StackMap | |
lvToStackEntry :: LocalVariable -> StackEntry Source #
Convert a local variable to a stack entry
stackEntryToLV :: StackEntry -> LocalVariable Source #
Convert a stack entry to a local variable
splitIntoBasicBlocks :: [Instruction] -> [BasicBlock] Source #
Split a list of instructions into basic blocks. Blocks are split at labels and after branch/return instructions.
buildLabelToBlockMap :: [BasicBlock] -> Map Label Int Source #
Build a map from labels to the index of the block that starts with that label.
splitOnLabels :: [Instruction] -> [(Maybe Label, [Instruction])] Source #
Split instructions into groups, each starting with an optional label. Also splits after branch instructions to ensure proper block boundaries.
topFrame :: QualifiedClassName -> [MethodAccessFlag] -> MethodDescriptor -> Frame Source #
Compute the initial frame state at method entry.
Includes this reference for instance methods, followed by method parameters.
analyseBlockDiff :: HasCallStack => Frame -> BasicBlock -> Frame Source #
Compute the frame state after executing all instructions in a basic block. Takes the frame state at block entry and returns the state at block exit.
diffFrames :: Frame -> Frame -> Label -> StackMapFrame Source #
Compute the delta between two frames to produce a StackMapFrame
lvToVerificationTypeInfo :: LocalVariable -> VerificationTypeInfo Source #
Convert a local variable to its JVM verification type info representation.
seToVerificationTypeInfo :: StackEntry -> VerificationTypeInfo Source #
Convert a stack entry to its JVM verification type info representation.
mergeFrames :: Frame -> Frame -> Maybe Frame Source #
Merge two frames that could both reach the same program point.
Returns Nothing if frames are identical, Just the merged frame otherwise.
Uses a conservative merge: differing types become Uninitialised.
getSuccessors :: Map Label Int -> Int -> BasicBlock -> [Int] Source #
Get the indices of successor blocks (blocks reachable from this block). Includes both jump targets and fall-through to the next block (if not terminated).
computeBlockFrames :: HasCallStack => Frame -> [BasicBlock] -> Map Int Frame Source #
Compute the frame state at the entry of each basic block using a worklist algorithm. Handles control flow merges by conservatively merging frame states.
calculateStackMapFrames Source #
Arguments
| :: HasCallStack | |
| => QualifiedClassName | The class containing this method |
| -> [MethodAccessFlag] | Method access flags (to determine if static) |
| -> MethodDescriptor | The method descriptor |
| -> [Instruction] | The method's instruction list |
| -> [StackMapFrame] |
Calculate the stack map frames for a method's bytecode. This function works by first splitting the code into basic blocks, then computing the frame state at the start of each block using a dataflow analysis, and finally generating the stack map frames by comparing the frame states at block entries.
replaceAtOrGrow :: Int -> LocalVariable -> [LocalVariable] -> [LocalVariable] Source #
Replace element at index in list, growing with Uninitialised if needed.
replaceAt :: Int -> a -> [a] -> [a] Source #
Replace element at index i in list. Appends to end if i is out of bounds.
type Analyser = Eff '[State Frame, Reader BasicBlock] () Source #
Effect stack for analysing instruction effects on the frame state. We can modify the current frame and read the current basic block.
pushesEntry :: StackEntry -> Analyser Source #
Pushes a raw StackEntry
pushesMaybe :: Maybe FieldType -> Analyser Source #
Pushes an item only if it exists (for void returns)
replaceTop :: FieldType -> Analyser Source #
Replaces the top stack entry with the given type
stores :: Int -> Analyser Source #
Stores the top of the stack into a local variable at the given index
indexOOBError :: HasCallStack => String -> U2 -> Frame -> BasicBlock -> a Source #
Report an error when a local variable index is out of bounds.