Package org.plumelib.bcelutil
Class StackMapUtils
- java.lang.Object
-
- org.plumelib.bcelutil.StackMapUtils
-
- Direct Known Subclasses:
InstructionListUtils
public abstract class StackMapUtils extends Object
This class provides utility methods to maintain and modify a method's StackMapTable within a Java class file. It can be thought of as an extension to BCEL.BCEL ought to automatically build and maintain the StackMapTable in a manner similar to the LineNumberTable and the LocalVariableTable. However, for historical reasons, it does not.
This class cannot be a set of static methods (like
BcelUtil) as it maintains state during the client's processing of a method that must be available on a per thread basis. Thus it is an abstract class extended byInstructionListUtils. A client would not normally extend this class directly.
-
-
Field Summary
Fields Modifier and Type Field Description protected SimpleLogdebug_instrumentA log to which to print debugging information about program instrumentation.private org.apache.bcel.classfile.StackMapEntry @InternedDistinct []empty_stack_map_tableAn empty StackMap used for initialization.protected intfirst_local_indexThe index of the first 'true' local in the local variable table.protected intinitial_locals_countThe number of local variables in the current method prior to any modifications.protected org.apache.bcel.classfile.StackMapType @MonotonicNonNull []initial_type_listInitial state of StackMapTypes for locals on method entry.protected booleanneedStackMapWhether or not the current method needs a StackMap; set by set_current_stack_map_table.protected @org.checkerframework.checker.index.qual.NonNegative intnumber_active_localsA number of methods in this class search and locate a particular StackMap within the current method.protected @Nullable org.apache.bcel.generic.ConstantPoolGenpoolThe pool for the method currently being processed.protected intrunning_offsetOffset into code that corresponds to the current StackMap of interest.protected @Nullable org.apache.bcel.classfile.StackMapsmtaOriginal stack map table attribute; set by set_current_stack_map_table.protected org.apache.bcel.classfile.StackMapEntry @Nullable []stack_map_tableWorking copy of StackMapTable; set by set_current_stack_map_table.private Map<org.apache.bcel.generic.InstructionHandle,Integer>uninitialized_NEW_mapA map from instructions that create uninitialized NEW objects to the corresponding StackMap entry.
-
Constructor Summary
Constructors Constructor Description StackMapUtils()
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Deprecated Methods Modifier and Type Method Description protected org.apache.bcel.generic.LocalVariableGenadd_new_argument(org.apache.bcel.generic.MethodGen mgen, String arg_name, org.apache.bcel.generic.Type arg_type)protected org.apache.bcel.generic.LocalVariableGenadd_new_parameter(org.apache.bcel.generic.MethodGen mgen, String arg_name, org.apache.bcel.generic.Type arg_type)Add a new parameter to the method.protected String[]add_string(String[] arr, String new_string)Returns a String array with new_string added to the end of arr.protected voidadjust_code_for_locals_change(org.apache.bcel.generic.MethodGen mgen, int index_first_moved_local, int size)Process the instruction list, adding size (1 or 2) to the index of each Instruction that references a local that is equal or higher in the local map than index_first_moved_local.protected StackTypesbcel_calc_stack_types(org.apache.bcel.generic.MethodGen mg)Calculates the types on the stack for each instruction using the BCEL stack verification routines.protected voidbuild_unitialized_NEW_map(org.apache.bcel.generic.InstructionList il)We need to locate and remember any NEW instructions that create uninitialized objects.protected org.apache.bcel.generic.LocalVariableGencreate_method_scope_local(org.apache.bcel.generic.MethodGen mgen, String local_name, org.apache.bcel.generic.Type local_type)Create a new local with a scope of the full method.protected voidcreate_new_stack_map_attribute(org.apache.bcel.generic.MethodGen mgen)Create a new StackMap code attribute from stack_map_table.protected voidfetch_current_stack_map_table(org.apache.bcel.generic.MethodGen mgen, int java_class_version)protected org.apache.bcel.classfile.StackMapEntryfind_stack_map_equal(int offset)Find the StackMap entry whose offset matches the input argument.protected @org.checkerframework.checker.index.qual.IndexOrLow({"stack_map_table"}) intfind_stack_map_index_after(int offset)Find the index of the StackMap entry whose offset is the first one after the input argument.protected intfind_stack_map_index_before(int offset)Find the index of the StackMap entry whose offset is the last one before the input argument.protected voidfix_local_variable_table(org.apache.bcel.generic.MethodGen mgen)Under some circumstances, there may be problems with the local variable table.protected intgen_temp_locals(org.apache.bcel.generic.MethodGen mgen, int offset)Find the live range of the compiler temp(s) at the given offset and create a LocalVariableGen for each.protected org.apache.bcel.classfile.StackMapTypegenerate_StackMapType_from_Type(org.apache.bcel.generic.Type t)Convert a Type to a StackMapType.protected org.apache.bcel.generic.Typegenerate_Type_from_StackMapType(org.apache.bcel.classfile.StackMapType smt)Convert a StackMapType to a Type.protected Stringget_attribute_name(org.apache.bcel.classfile.Attribute a)Return the attribute name for the specified attribute.protected @Nullable org.apache.bcel.classfile.Attributeget_local_variable_type_table_attribute(org.apache.bcel.generic.MethodGen mgen)Find the LocalVariableTypeTable attribute for a method.protected @Nullable org.apache.bcel.classfile.Attributeget_stack_map_table_attribute(org.apache.bcel.generic.MethodGen mgen)Find the StackMapTable attribute for a method.protected intgetSize(org.apache.bcel.classfile.StackMapType smt)Return the operand size of this type (2 for long and double, 1 otherwise).protected booleanis_local_variable_type_table(org.apache.bcel.classfile.Attribute a)Returns whether or not the specified attribute is a LocalVariableTypeTable.protected booleanis_stack_map_table(org.apache.bcel.classfile.Attribute a)Returns whether or not the specified attribute is a StackMapTable.protected voidmodify_stack_maps_for_switches(org.apache.bcel.generic.InstructionHandle ih, org.apache.bcel.generic.InstructionList il)Check to see if (due to some instruction modifications) there have been any changes in a switch statement's padding bytes.protected voidprint_stack_map_table(String prefix)Print the contents of the StackMapTable to the debug_instrument.log.protected voidremove_local_variable_type_table(org.apache.bcel.generic.MethodGen mgen)Remove the local variable type table attribute (LVTT) from mgen.protected voidset_current_stack_map_table(org.apache.bcel.generic.MethodGen mgen, int java_class_version)Get existing StackMapTable from the MethodGen argument.protected static @ClassGetName StringtypeToClassGetName(org.apache.bcel.generic.Type t)Convert a Type name to a Class name.protected voidupdate_full_frame_stack_map_entries(int offset, org.apache.bcel.generic.Type type_new_var, org.apache.bcel.generic.LocalVariableGen[] locals)Update any FULL_FRAME StackMap entries to include a new local var.private voidupdate_NEW_object_stack_map_entries(int old_offset, int new_offset)One of uninitialized NEW instructions has moved.protected voidupdate_stack_map_offset(int position, int delta)We have inserted additional byte(s) into the instruction list; update the StackMaps, if required.protected voidupdate_uninitialized_NEW_offsets(org.apache.bcel.generic.InstructionList il)Check to see if any of the uninitialized NEW instructions have moved.
-
-
-
Field Detail
-
pool
protected @Nullable org.apache.bcel.generic.ConstantPoolGen pool
The pool for the method currently being processed. Must be set by the client. See the sample code inInstructionListUtilsfor when and how to set this value.
-
debug_instrument
protected SimpleLog debug_instrument
A log to which to print debugging information about program instrumentation.
-
needStackMap
protected boolean needStackMap
Whether or not the current method needs a StackMap; set by set_current_stack_map_table.
-
stack_map_table
protected org.apache.bcel.classfile.StackMapEntry @Nullable [] stack_map_table
Working copy of StackMapTable; set by set_current_stack_map_table.
-
smta
protected @Nullable org.apache.bcel.classfile.StackMap smta
Original stack map table attribute; set by set_current_stack_map_table.
-
initial_type_list
protected org.apache.bcel.classfile.StackMapType @MonotonicNonNull [] initial_type_list
Initial state of StackMapTypes for locals on method entry.
-
initial_locals_count
protected int initial_locals_count
The number of local variables in the current method prior to any modifications.
-
number_active_locals
protected @org.checkerframework.checker.index.qual.NonNegative int number_active_locals
A number of methods in this class search and locate a particular StackMap within the current method. This variable contains the number of live local variables within the range of byte code instructions covered by this StackMap. Set by update_stack_map_offset, find_stack_map_equal, find_stack_map_index_before, or find_stack_map_index_after.
-
running_offset
protected int running_offset
Offset into code that corresponds to the current StackMap of interest. Set by find_stack_map_index_before.
-
first_local_index
protected int first_local_index
The index of the first 'true' local in the local variable table. That is, after 'this' and any parameters.
-
empty_stack_map_table
private org.apache.bcel.classfile.StackMapEntry @InternedDistinct [] empty_stack_map_table
An empty StackMap used for initialization.
-
-
Method Detail
-
add_string
protected String[] add_string(String[] arr, String new_string)
Returns a String array with new_string added to the end of arr.- Parameters:
arr- original string arraynew_string- string to be added- Returns:
- the new string array
-
get_attribute_name
@Pure protected final String get_attribute_name(org.apache.bcel.classfile.Attribute a)
Return the attribute name for the specified attribute.- Parameters:
a- the attribute- Returns:
- the attribute name for the specified attribute
-
is_local_variable_type_table
@Pure protected final boolean is_local_variable_type_table(org.apache.bcel.classfile.Attribute a)
Returns whether or not the specified attribute is a LocalVariableTypeTable.- Parameters:
a- the attribute- Returns:
- true iff the attribute is a LocalVariableTypeTable
-
is_stack_map_table
@Pure protected final boolean is_stack_map_table(org.apache.bcel.classfile.Attribute a)
Returns whether or not the specified attribute is a StackMapTable.- Parameters:
a- the attribute- Returns:
- true iff the attribute is a StackMapTable
-
get_stack_map_table_attribute
@Pure protected final @Nullable org.apache.bcel.classfile.Attribute get_stack_map_table_attribute(org.apache.bcel.generic.MethodGen mgen)
Find the StackMapTable attribute for a method. Return null if there isn't one.- Parameters:
mgen- the method- Returns:
- the StackMapTable attribute for the method (or null if not present)
-
get_local_variable_type_table_attribute
@Pure protected final @Nullable org.apache.bcel.classfile.Attribute get_local_variable_type_table_attribute(org.apache.bcel.generic.MethodGen mgen)
Find the LocalVariableTypeTable attribute for a method. Return null if there isn't one.- Parameters:
mgen- the method- Returns:
- the LocalVariableTypeTable attribute for the method (or null if not present)
-
remove_local_variable_type_table
protected final void remove_local_variable_type_table(org.apache.bcel.generic.MethodGen mgen)
Remove the local variable type table attribute (LVTT) from mgen. Some instrumentation changes require this to be updated, but without BCEL support that would be hard to do. It should be safe to just delete it since it is optional and really only of use to a debugger.- Parameters:
mgen- the method to clear out
-
update_stack_map_offset
protected final void update_stack_map_offset(int position, int delta)We have inserted additional byte(s) into the instruction list; update the StackMaps, if required. Also sets running_offset.- Parameters:
position- the location of insertiondelta- the size of the insertion
-
find_stack_map_equal
protected final org.apache.bcel.classfile.StackMapEntry find_stack_map_equal(int offset)
Find the StackMap entry whose offset matches the input argument. Also sets running_offset.- Parameters:
offset- byte code offset- Returns:
- the corresponding StackMapEntry
-
find_stack_map_index_before
protected final int find_stack_map_index_before(int offset)
Find the index of the StackMap entry whose offset is the last one before the input argument. Return -1 if there isn't one. Also sets running_offset and number_active_locals.- Parameters:
offset- byte code offset- Returns:
- the corresponding StackMapEntry index
-
find_stack_map_index_after
protected final @org.checkerframework.checker.index.qual.IndexOrLow({"stack_map_table"}) int find_stack_map_index_after(int offset)Find the index of the StackMap entry whose offset is the first one after the input argument. Return -1 if there isn't one. Also sets running_offset.- Parameters:
offset- byte code offset- Returns:
- the corresponding StackMapEntry index
-
modify_stack_maps_for_switches
protected final void modify_stack_maps_for_switches(org.apache.bcel.generic.InstructionHandle ih, org.apache.bcel.generic.InstructionList il)Check to see if (due to some instruction modifications) there have been any changes in a switch statement's padding bytes. If so, then update the corresponding StackMap to reflect this change.- Parameters:
ih- where to start looking for a switch instructionil- instruction list to search
-
gen_temp_locals
@RequiresNonNull("initial_type_list") protected final int gen_temp_locals(org.apache.bcel.generic.MethodGen mgen, int offset)Find the live range of the compiler temp(s) at the given offset and create a LocalVariableGen for each. Note the compiler might generate temps of different sizes at the same offset (must have disjoint lifetimes).- Parameters:
mgen- the methodoffset- compiler assigned local offset of hidden temp- Returns:
- offset incremented by size of smallest temp found at offset
-
build_unitialized_NEW_map
protected final void build_unitialized_NEW_map(org.apache.bcel.generic.InstructionList il)
We need to locate and remember any NEW instructions that create uninitialized objects. Their offset may be contained in a StackMap entry and will probably need to be updated as we add instrumentation code. Note that these instructions are fairly rare.- Parameters:
il- instruction list to search
-
update_NEW_object_stack_map_entries
private final void update_NEW_object_stack_map_entries(int old_offset, int new_offset)One of uninitialized NEW instructions has moved. Update its offset in StackMap entries. Note that more than one entry could refer to the same instruction. This is a helper routine used by update_uninitialized_NEW_offsets.- Parameters:
old_offset- original location of NEW instructionnew_offset- new location of NEW instruction
-
update_uninitialized_NEW_offsets
protected final void update_uninitialized_NEW_offsets(org.apache.bcel.generic.InstructionList il)
Check to see if any of the uninitialized NEW instructions have moved. Again, these are rare, so a linear pass is fine.- Parameters:
il- instruction list to search
-
adjust_code_for_locals_change
protected final void adjust_code_for_locals_change(org.apache.bcel.generic.MethodGen mgen, int index_first_moved_local, int size)Process the instruction list, adding size (1 or 2) to the index of each Instruction that references a local that is equal or higher in the local map than index_first_moved_local. Size should be the size of the new local that was just inserted at index_first_moved_local.- Parameters:
mgen- MethodGen to be modifiedindex_first_moved_local- original index of first local moved "up"size- size of new local added (1 or 2)
-
fetch_current_stack_map_table
@Deprecated protected final void fetch_current_stack_map_table(org.apache.bcel.generic.MethodGen mgen, int java_class_version)
Get existing StackMapTable from the MethodGen argument. If there is none, create a new empty one. Sets both smta and stack_map_table. Must be called prior to any other methods that manipulate the stack_map_table!- Parameters:
mgen- MethodGen to searchjava_class_version- Java version for the classfile; stack_map_table is optional before Java 1.7 (= classfile version 51)
-
set_current_stack_map_table
@EnsuresNonNull("stack_map_table") protected final void set_current_stack_map_table(org.apache.bcel.generic.MethodGen mgen, int java_class_version)Get existing StackMapTable from the MethodGen argument. If there is none, create a new empty one. Sets both smta and stack_map_table. Must be called prior to any other methods that manipulate the stack_map_table!- Parameters:
mgen- MethodGen to searchjava_class_version- Java version for the classfile; stack_map_table is optional before Java 1.7 (= classfile version 51)
-
print_stack_map_table
protected final void print_stack_map_table(String prefix)
Print the contents of the StackMapTable to the debug_instrument.log.- Parameters:
prefix- label to display with table
-
create_new_stack_map_attribute
protected final void create_new_stack_map_attribute(org.apache.bcel.generic.MethodGen mgen) throws IOExceptionCreate a new StackMap code attribute from stack_map_table.- Parameters:
mgen- MethodGen to add attribute to- Throws:
IOException- if cannot create the attribute
-
typeToClassGetName
protected static @ClassGetName String typeToClassGetName(org.apache.bcel.generic.Type t)
Convert a Type name to a Class name.- Parameters:
t- type whose name is to be converted- Returns:
- a String containing the class name
-
generate_StackMapType_from_Type
protected final org.apache.bcel.classfile.StackMapType generate_StackMapType_from_Type(org.apache.bcel.generic.Type t)
Convert a Type to a StackMapType.- Parameters:
t- Type to be converted- Returns:
- result StackMapType
-
generate_Type_from_StackMapType
protected final org.apache.bcel.generic.Type generate_Type_from_StackMapType(org.apache.bcel.classfile.StackMapType smt)
Convert a StackMapType to a Type.- Parameters:
smt- StackMapType to be converted- Returns:
- result Type
-
getSize
protected final int getSize(org.apache.bcel.classfile.StackMapType smt)
Return the operand size of this type (2 for long and double, 1 otherwise).- Parameters:
smt- a StackMapType object- Returns:
- the operand size of this type
-
update_full_frame_stack_map_entries
protected final void update_full_frame_stack_map_entries(int offset, org.apache.bcel.generic.Type type_new_var, org.apache.bcel.generic.LocalVariableGen[] locals)Update any FULL_FRAME StackMap entries to include a new local var. The locals array is a copy of the local variables PRIOR to the addition of the new local in question.- Parameters:
offset- offset into stack of the new variable we are addingtype_new_var- type of new variable we are addinglocals- a copy of the local variable table prior to this modification
-
add_new_argument
@Deprecated protected final org.apache.bcel.generic.LocalVariableGen add_new_argument(org.apache.bcel.generic.MethodGen mgen, String arg_name, org.apache.bcel.generic.Type arg_type)
Deprecated.Add a new parameter to the method. This will be added after last current parameter and before the first local variable. This might have the side effect of causing us to rewrite the method byte codes to adjust the offsets for the local variables - see below for details.Must call fix_local_variable_table (just once per method) before calling this routine.
- Parameters:
mgen- MethodGen to be modifiedarg_name- name of new parameterarg_type- type of new parameter- Returns:
- a LocalVariableGen for the new parameter
-
add_new_parameter
protected final org.apache.bcel.generic.LocalVariableGen add_new_parameter(org.apache.bcel.generic.MethodGen mgen, String arg_name, org.apache.bcel.generic.Type arg_type)Add a new parameter to the method. This will be added after last current parameter and before the first local variable. This might have the side effect of causing us to rewrite the method byte codes to adjust the offsets for the local variables - see below for details.Must call fix_local_variable_table (just once per method) before calling this routine.
- Parameters:
mgen- MethodGen to be modifiedarg_name- name of new parameterarg_type- type of new parameter- Returns:
- a LocalVariableGen for the new parameter
-
create_method_scope_local
protected final org.apache.bcel.generic.LocalVariableGen create_method_scope_local(org.apache.bcel.generic.MethodGen mgen, String local_name, org.apache.bcel.generic.Type local_type)Create a new local with a scope of the full method. This means we need to search the existing locals to find the proper index for our new local. This might have the side effect of causing us to rewrite the method byte codes to adjust the offsets for the existing local variables - see below for details.Must call fix_local_variable_table (just once per method) before calling this routine.
- Parameters:
mgen- MethodGen to be modifiedlocal_name- name of new locallocal_type- type of new local- Returns:
- a LocalVariableGen for the new local
-
fix_local_variable_table
@EnsuresNonNull("initial_type_list") protected final void fix_local_variable_table(org.apache.bcel.generic.MethodGen mgen)Under some circumstances, there may be problems with the local variable table. These problems occur when the Java compiler adds unnamed entries. There may be unnamed parameters and/or unnamed local variables. These items appear as gaps in the LocalVariable table. This routine creates LocalVariable entries for these missing items.- The java Compiler allocates a hidden parameter for the constructor of an inner class. These items are given the name $hidden$ appended with their offset.
- The Java compiler allocates unnamed local temps for:
- saving the exception in a finally clause
- the lock for a synchronized block
- interators
- (others?)
- Parameters:
mgen- MethodGen to be modified
-
bcel_calc_stack_types
protected final StackTypes bcel_calc_stack_types(org.apache.bcel.generic.MethodGen mg)
Calculates the types on the stack for each instruction using the BCEL stack verification routines.- Parameters:
mg- MethodGen for the method to be analyzed- Returns:
- a StackTypes object for the method
-
-