Class MethodEditor
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
Modifier and TypeClassDescriptionstatic final class
Output is the interface that patches use to emit their code into a method body.static class
This class is subclassed for each kind of patch that you want to apply.static class
A specialized Instruction.Visitor providing convenience methods for inserting patches. -
Constructor Summary
ConstructorDescriptionMethodEditor
(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
Modifier and TypeMethodDescriptionvoid
addInstructionExceptionHandler
(int i, 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).void
addMethodExceptionHandler
(String catchClass, MethodEditor.Patch p) A "method exception handler" handles exceptions generated anywhere in the method.int
Allocate a fresh label.boolean
This method finishes a pass.void
This must be called before inserting any patches.void
endPass()
This must be called after inserting any patches.getData()
ExceptionHandler[][]
int[]
void
insertAfter
(int i, MethodEditor.Patch p) Insert code to be executed after the instruction.void
This method inserts code that will be placed after the method body.void
Insert code to be executed whenever the method is entered.void
insertBefore
(int i, MethodEditor.Patch p) Insert code to be executed before the instruction.void
replaceWith
(int i, MethodEditor.Patch p) Insert code to replace the instruction.void
Apply Visitor v to each instruction in the code, for the purpose of patching the code.
-
Constructor Details
-
MethodEditor
Build an editor for the given method. This editor will write back its changes to the method info.- Throws:
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 Details
-
getHandlers
- Returns:
- the current handler array
-
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
Allocate a fresh label. This must be called during a pass and not during code emission.- Throws:
IllegalArgumentException
-
insertAtStart
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:
IllegalArgumentException
- if p is null
-
insertBefore
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:
IllegalArgumentException
- if p is null
-
insertAfter
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
Insert code to replace the instruction. Exception handlers that cover the instruction will cover the patch.Multiple replacements are not allowed.
- Throws:
NullPointerException
- if p is nullIllegalArgumentException
- if p is null
-
addInstructionExceptionHandler
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
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
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:
IllegalArgumentException
- if p is null
-
getData
- Returns:
- the MethodData used to create this editor, or null if no MethodData is linked to this editor
-
applyPatches
This 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:
IllegalArgumentException
-
visitInstructions
Apply Visitor v to each instruction in the code, for the purpose of patching the code.
-