Class MethodEditor
- java.lang.Object
-
- com.ibm.wala.shrike.shrikeBT.MethodEditor
-
public final class MethodEditor extends java.lang.ObjectThe MethodEditor is the core of the ShrikeBT code rewriting mechanism. To rewrite code, construct a MethodEditor initialized with the intial code for the method. Then perform a series of passes. In each pass you call beginPass(), insert a number of patches using the insert...() or replace...() methods, then optionally call applyPatches() to update the code with your changes, then call endPass(). The end of each pass updates the code in the MethodData that you passed in, so the new code can be extracted from that MethodData object. Note that if applyPatches() is not called, or it is called but no patches had been inserted, then the code will not be updated and that pass is essentially aborted.A patch is simply a subclass of MethodEditor.Patch, representing a code sequence to insert into the method. Each patch class implements one method, emitTo(), which writes the patch code into the code stream using the provided MethodEditor.Output instance. Anonymous inner classes are very useful for writing patches.
Patches can be inserted at the following points:
- Before the start of the method
- Before or after a particular instruction
- Replacing a particular instruction
- Handling an exception on a particular instruction
- Handling an exception anywhere in the method
- After the end of the method, where code will not normally be executed, but can be branched to by another patch
MethodEditor relies on labels. A label is an integer representing a point in the code. Labels are valid only during a single pass; at the end of each pass, instructions are reordered and old labels become invalid. At the beginning of a pass every instruction in the instructions array is labelled with the index of that instruction in the array. During instrumentation new labels can be allocated by calling MethodEditor.allocateLabel(); control instructions can be created referring to these new labels or the existing labels. At the end of a pass, as patch code is spliced into the method body, all instructions are updated to refer to the new labels which are simply the indices of instructions in the instruction array.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static classMethodEditor.OutputOutput is the interface that patches use to emit their code into a method body.static classMethodEditor.PatchThis class is subclassed for each kind of patch that you want to apply.static classMethodEditor.VisitorA specialized Instruction.Visitor providing convenience methods for inserting patches.
-
Constructor Summary
Constructors Constructor Description MethodEditor(Instruction[] instructions, ExceptionHandler[][] handlers, int[] instructionsToBytecodes)Build an editor for specific method data.MethodEditor(MethodData info)Build an editor for the given method.
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description voidaddInstructionExceptionHandler(int i, java.lang.String catchClass, MethodEditor.Patch p)An "instruction exception handler" handles exceptions generated by a specific instruction (including patch code that may be inserted before, after, or instead of the instruction in this pass).voidaddMethodExceptionHandler(java.lang.String catchClass, MethodEditor.Patch p)A "method exception handler" handles exceptions generated anywhere in the method.intallocateLabel()Allocate a fresh label.booleanapplyPatches()This method finishes a pass.voidbeginPass()This must be called before inserting any patches.voidendPass()This must be called after inserting any patches.MethodDatagetData()ExceptionHandler[][]getHandlers()IInstruction[]getInstructions()int[]getInstructionsToBytecodes()voidinsertAfter(int i, MethodEditor.Patch p)Insert code to be executed after the instruction.voidinsertAfterBody(MethodEditor.Patch p)This method inserts code that will be placed after the method body.voidinsertAtStart(MethodEditor.Patch p)Insert code to be executed whenever the method is entered.voidinsertBefore(int i, MethodEditor.Patch p)Insert code to be executed before the instruction.voidreplaceWith(int i, MethodEditor.Patch p)Insert code to replace the instruction.voidvisitInstructions(MethodEditor.Visitor v)Apply Visitor v to each instruction in the code, for the purpose of patching the code.
-
-
-
Constructor Detail
-
MethodEditor
public MethodEditor(MethodData info)
Build an editor for the given method. This editor will write back its changes to the method info.- Throws:
java.lang.IllegalArgumentException- if info is null
-
MethodEditor
public MethodEditor(Instruction[] instructions, ExceptionHandler[][] handlers, int[] instructionsToBytecodes)
Build an editor for specific method data. After patching the code you can retrieve the new code, handlers and instructions-to-bytecode-offsets map.
-
-
Method Detail
-
getHandlers
public ExceptionHandler[][] getHandlers()
- Returns:
- the current handler array
-
getInstructions
public IInstruction[] getInstructions()
- Returns:
- the current instruction array
-
getInstructionsToBytecodes
public int[] getInstructionsToBytecodes()
- Returns:
- the current instructions-to-bytecode-offsets map
-
beginPass
public void beginPass()
This must be called before inserting any patches.
-
endPass
public void endPass()
This must be called after inserting any patches.
-
allocateLabel
public int allocateLabel() throws java.lang.IllegalArgumentExceptionAllocate a fresh label. This must be called during a pass and not during code emission.- Throws:
java.lang.IllegalArgumentException
-
insertAtStart
public void insertAtStart(MethodEditor.Patch p)
Insert code to be executed whenever the method is entered. This code is not protected by any exception handlers (other than handlers declared in the patch).When multiple 'start' patches are given, the last one added is first in execution order.
- Throws:
java.lang.IllegalArgumentException- if p is null
-
insertBefore
public void insertBefore(int i, MethodEditor.Patch p)Insert code to be executed before the instruction. Branches to the instruction will branch to this code. Exception handlers that cover the instruction will be extended to cover the patch.When multiple 'before' patches are given, the last one added is first in execution order.
- Throws:
java.lang.IllegalArgumentException- if p is null
-
insertAfter
public void insertAfter(int i, MethodEditor.Patch p)Insert code to be executed after the instruction. This code will only execute if the instruction "falls through". For example, code inserted after a "goto" will never be executed. Likewise if the instruction throws an execution the 'after' code will not be executed. Exception handlers that cover the instruction will be extended to cover the patch.When multiple 'after' patches are given, the last one added is LAST in execution order.
-
replaceWith
public void replaceWith(int i, MethodEditor.Patch p) throws java.lang.NullPointerExceptionInsert code to replace the instruction. Exception handlers that cover the instruction will cover the patch.Multiple replacements are not allowed.
- Throws:
java.lang.NullPointerException- if p is nulljava.lang.IllegalArgumentException- if p is null
-
addInstructionExceptionHandler
public void addInstructionExceptionHandler(int i, java.lang.String catchClass, MethodEditor.Patch p)An "instruction exception handler" handles exceptions generated by a specific instruction (including patch code that may be inserted before, after, or instead of the instruction in this pass). If the patch code falls through, control resumes with the next instruction. This exception handler handles exceptions before any exception handler already attached to the instruction. Furthermore, the patch itself is covered by the exception handlers already attached to the instruction.If multiple instruction exception handlers are given, then the last one added handles the exception first; if an exception is rethrown, then the next-to-last one added handles that exception, etc.
-
addMethodExceptionHandler
public void addMethodExceptionHandler(java.lang.String catchClass, MethodEditor.Patch p)A "method exception handler" handles exceptions generated anywhere in the method. The patch code must not fall through; it must return or throw an exception.If multiple method exception handlers are given, then the last one added handles the exception first; if an exception is rethrown, then the next-to-last one added handles that exception, etc.
-
insertAfterBody
public void insertAfterBody(MethodEditor.Patch p)
This method inserts code that will be placed after the method body. This code will not be executed normally, but it can emit label definitions that other patches can branch to. No exception handlers cover this code (other than exception handlers emitted by patch p itself).- Throws:
java.lang.IllegalArgumentException- if p is null
-
getData
public MethodData getData()
- Returns:
- the MethodData used to create this editor, or null if no MethodData is linked to this editor
-
applyPatches
public boolean applyPatches() throws java.lang.IllegalArgumentExceptionThis method finishes a pass. All code is updated; instructions are reordered and old labels may not be valid.If no patches were issued, we don't need to do anything at all; this case is detected quickly and no updates are made.
- Returns:
- true iff non-trivial patches were applied
- Throws:
java.lang.IllegalArgumentException
-
visitInstructions
public void visitInstructions(MethodEditor.Visitor v)
Apply Visitor v to each instruction in the code, for the purpose of patching the code.
-
-