|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
package com.sun.org.apache.bcel.internal.generic; |
|
|
|
import com.sun.org.apache.bcel.internal.Const; |
|
import com.sun.org.apache.bcel.internal.classfile.AnnotationEntry; |
|
import com.sun.org.apache.bcel.internal.classfile.Annotations; |
|
import com.sun.org.apache.bcel.internal.classfile.Attribute; |
|
import com.sun.org.apache.bcel.internal.classfile.Code; |
|
import com.sun.org.apache.bcel.internal.classfile.CodeException; |
|
import com.sun.org.apache.bcel.internal.classfile.ExceptionTable; |
|
import com.sun.org.apache.bcel.internal.classfile.LineNumber; |
|
import com.sun.org.apache.bcel.internal.classfile.LineNumberTable; |
|
import com.sun.org.apache.bcel.internal.classfile.LocalVariable; |
|
import com.sun.org.apache.bcel.internal.classfile.LocalVariableTable; |
|
import com.sun.org.apache.bcel.internal.classfile.LocalVariableTypeTable; |
|
import com.sun.org.apache.bcel.internal.classfile.Method; |
|
import com.sun.org.apache.bcel.internal.classfile.ParameterAnnotationEntry; |
|
import com.sun.org.apache.bcel.internal.classfile.ParameterAnnotations; |
|
import com.sun.org.apache.bcel.internal.classfile.RuntimeVisibleParameterAnnotations; |
|
import com.sun.org.apache.bcel.internal.classfile.Utility; |
|
import com.sun.org.apache.bcel.internal.util.BCELComparator; |
|
import java.util.ArrayList; |
|
import java.util.Arrays; |
|
import java.util.Comparator; |
|
import java.util.HashMap; |
|
import java.util.List; |
|
import java.util.Map; |
|
import java.util.Stack; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class MethodGen extends FieldGenOrMethodGen { |
|
|
|
private String class_name; |
|
private Type[] arg_types; |
|
private String[] arg_names; |
|
private int max_locals; |
|
private int max_stack; |
|
private InstructionList il; |
|
private boolean strip_attributes; |
|
private final List<LocalVariableGen> variable_vec = new ArrayList<>(); |
|
private final List<LocalVariableGen> type_vec = new ArrayList<>(); |
|
private final List<LineNumberGen> line_number_vec = new ArrayList<>(); |
|
private final List<CodeExceptionGen> exception_vec = new ArrayList<>(); |
|
private final List<String> throws_vec = new ArrayList<>(); |
|
private final List<Attribute> code_attrs_vec = new ArrayList<>(); |
|
|
|
private List<AnnotationEntryGen>[] param_annotations; |
|
private boolean hasParameterAnnotations = false; |
|
private boolean haveUnpackedParameterAnnotations = false; |
|
|
|
private static BCELComparator bcelComparator = new BCELComparator() { |
|
|
|
@Override |
|
public boolean equals(final Object o1, final Object o2) { |
|
final MethodGen THIS = (MethodGen) o1; |
|
final MethodGen THAT = (MethodGen) o2; |
|
return THIS.getName().equals(THAT.getName()) |
|
&& THIS.getSignature().equals(THAT.getSignature()); |
|
} |
|
|
|
@Override |
|
public int hashCode(final Object o) { |
|
final MethodGen THIS = (MethodGen) o; |
|
return THIS.getSignature().hashCode() ^ THIS.getName().hashCode(); |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public MethodGen(final int access_flags, final Type return_type, final Type[] arg_types, String[] arg_names, |
|
final String method_name, final String class_name, final InstructionList il, final ConstantPoolGen cp) { |
|
super(access_flags); |
|
setType(return_type); |
|
setArgumentTypes(arg_types); |
|
setArgumentNames(arg_names); |
|
setName(method_name); |
|
setClassName(class_name); |
|
setInstructionList(il); |
|
setConstantPool(cp); |
|
final boolean abstract_ = isAbstract() || isNative(); |
|
InstructionHandle start = null; |
|
InstructionHandle end = null; |
|
if (!abstract_) { |
|
start = il.getStart(); |
|
end = il.getEnd(); |
|
|
|
*/ |
|
if (!isStatic() && (class_name != null)) { |
|
addLocalVariable("this", ObjectType.getInstance(class_name), start, end); |
|
} |
|
} |
|
if (arg_types != null) { |
|
final int size = arg_types.length; |
|
for (final Type arg_type : arg_types) { |
|
if (Type.VOID == arg_type) { |
|
throw new ClassGenException("'void' is an illegal argument type for a method"); |
|
} |
|
} |
|
if (arg_names != null) { |
|
if (size != arg_names.length) { |
|
throw new ClassGenException("Mismatch in argument array lengths: " + size |
|
+ " vs. " + arg_names.length); |
|
} |
|
} else { |
|
arg_names = new String[size]; |
|
for (int i = 0; i < size; i++) { |
|
arg_names[i] = "arg" + i; |
|
} |
|
setArgumentNames(arg_names); |
|
} |
|
if (!abstract_) { |
|
for (int i = 0; i < size; i++) { |
|
addLocalVariable(arg_names[i], arg_types[i], start, end); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public MethodGen(final Method m, final String class_name, final ConstantPoolGen cp) { |
|
this(m.getAccessFlags(), Type.getReturnType(m.getSignature()), Type.getArgumentTypes(m |
|
.getSignature()), null , m.getName(), class_name, |
|
((m.getAccessFlags() & (Const.ACC_ABSTRACT | Const.ACC_NATIVE)) == 0) |
|
? new InstructionList(m.getCode().getCode()) |
|
: null, cp); |
|
final Attribute[] attributes = m.getAttributes(); |
|
for (final Attribute attribute : attributes) { |
|
Attribute a = attribute; |
|
if (a instanceof Code) { |
|
final Code c = (Code) a; |
|
setMaxStack(c.getMaxStack()); |
|
setMaxLocals(c.getMaxLocals()); |
|
final CodeException[] ces = c.getExceptionTable(); |
|
if (ces != null) { |
|
for (final CodeException ce : ces) { |
|
final int type = ce.getCatchType(); |
|
ObjectType c_type = null; |
|
if (type > 0) { |
|
final String cen = m.getConstantPool().getConstantString(type, |
|
Const.CONSTANT_Class); |
|
c_type = ObjectType.getInstance(cen); |
|
} |
|
final int end_pc = ce.getEndPC(); |
|
final int length = m.getCode().getCode().length; |
|
InstructionHandle end; |
|
if (length == end_pc) { |
|
end = il.getEnd(); |
|
} else { |
|
end = il.findHandle(end_pc); |
|
end = end.getPrev(); |
|
} |
|
addExceptionHandler(il.findHandle(ce.getStartPC()), end, il.findHandle(ce |
|
.getHandlerPC()), c_type); |
|
} |
|
} |
|
final Attribute[] c_attributes = c.getAttributes(); |
|
for (final Attribute c_attribute : c_attributes) { |
|
a = c_attribute; |
|
if (a instanceof LineNumberTable) { |
|
final LineNumber[] ln = ((LineNumberTable) a).getLineNumberTable(); |
|
for (final LineNumber l : ln) { |
|
final InstructionHandle ih = il.findHandle(l.getStartPC()); |
|
if (ih != null) { |
|
addLineNumber(ih, l.getLineNumber()); |
|
} |
|
} |
|
} else if (a instanceof LocalVariableTable) { |
|
final LocalVariable[] lv = ((LocalVariableTable) a).getLocalVariableTable(); |
|
removeLocalVariables(); |
|
repairHandles(lv, false); |
|
} else if (a instanceof LocalVariableTypeTable) { |
|
LocalVariable[] lv = ((LocalVariableTypeTable) a).getLocalVariableTypeTable(); |
|
removeLocalVariableTypes(); |
|
repairHandles(lv, true); |
|
} else { |
|
addCodeAttribute(a); |
|
} |
|
} |
|
} else if (a instanceof ExceptionTable) { |
|
final String[] names = ((ExceptionTable) a).getExceptionNames(); |
|
for (final String name2 : names) { |
|
addException(name2); |
|
} |
|
} else if (a instanceof Annotations) { |
|
final Annotations runtimeAnnotations = (Annotations) a; |
|
final AnnotationEntry[] aes = runtimeAnnotations.getAnnotationEntries(); |
|
for (final AnnotationEntry element : aes) { |
|
addAnnotationEntry(new AnnotationEntryGen(element, cp, false)); |
|
} |
|
} else { |
|
addAttribute(a); |
|
} |
|
} |
|
} |
|
|
|
private void repairHandles(final LocalVariable[] lv, boolean isLVT) { |
|
for (int k = 0; k < lv.length; k++) { |
|
LocalVariable l = lv[k]; |
|
InstructionHandle start = il.findHandle(l.getStartPC()); |
|
InstructionHandle end = il.findHandle(l.getStartPC() + l.getLength()); |
|
|
|
if (null == start) { |
|
start = il.getStart(); |
|
} |
|
if (null == end) { |
|
end = il.getEnd(); |
|
} |
|
if (isLVT) { |
|
addLocalVariableType(l.getName(), Type.getType(l.getSignature()), |
|
l.getIndex(), start, end); |
|
} else { |
|
addLocalVariable(l.getName(), Type.getType(l.getSignature()), |
|
l.getIndex(), start, end); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public LocalVariableGen addLocalVariable(final String name, final Type type, final int slot, |
|
final InstructionHandle start, final InstructionHandle end) { |
|
|
|
final byte t = type.getType(); |
|
if (t != Const.T_ADDRESS) { |
|
final int add = type.getSize(); |
|
if (slot + add > max_locals) { |
|
max_locals = slot + add; |
|
} |
|
final LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end); |
|
int i; |
|
if ((i = variable_vec.indexOf(l)) >= 0) { |
|
variable_vec.set(i, l); |
|
} else { |
|
variable_vec.add(l); |
|
} |
|
return l; |
|
} |
|
throw new IllegalArgumentException("Can not use " + type |
|
+ " as type for local variable"); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public LocalVariableGen addLocalVariable(final String name, final Type type, |
|
final InstructionHandle start, final InstructionHandle end) { |
|
return addLocalVariable(name, type, max_locals, start, end); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public void removeLocalVariable(final LocalVariableGen l) { |
|
variable_vec.remove(l); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void removeLocalVariables() { |
|
variable_vec.clear(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public LocalVariableGen[] getLocalVariables() { |
|
return getLocalVariableOrTypes(false); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private LocalVariableGen[] getLocalVariableTypes() { |
|
return getLocalVariableOrTypes(true); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private LocalVariableGen[] getLocalVariableOrTypes(boolean isLVT) { |
|
int size = (isLVT) ? type_vec.size() : variable_vec.size(); |
|
LocalVariableGen[] lg = new LocalVariableGen[size]; |
|
if (isLVT) { |
|
type_vec.toArray(lg); |
|
} else { |
|
variable_vec.toArray(lg); |
|
} |
|
|
|
for (int i = 0; i < size; i++) { |
|
if (lg[i].getStart() == null) { |
|
lg[i].setStart(il.getStart()); |
|
} |
|
|
|
if (lg[i].getEnd() == null) { |
|
lg[i].setEnd(il.getEnd()); |
|
} |
|
} |
|
|
|
if (size > 1) { |
|
Arrays.sort(lg, new Comparator<LocalVariableGen>() { |
|
@Override |
|
public int compare(final LocalVariableGen o1, final LocalVariableGen o2) { |
|
return o1.getIndex() - o2.getIndex(); |
|
} |
|
}); |
|
} |
|
|
|
return lg; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public LocalVariableTable getLocalVariableTable(final ConstantPoolGen cp) { |
|
final LocalVariableGen[] lg = getLocalVariables(); |
|
final int size = lg.length; |
|
final LocalVariable[] lv = new LocalVariable[size]; |
|
for (int i = 0; i < size; i++) { |
|
lv[i] = lg[i].getLocalVariable(cp); |
|
} |
|
return new LocalVariableTable(cp.addUtf8("LocalVariableTable"), 2 + lv.length * 10, lv, cp |
|
.getConstantPool()); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public LocalVariableTypeTable getLocalVariableTypeTable(ConstantPoolGen cp) { |
|
LocalVariableGen[] lg = getLocalVariableTypes(); |
|
int size = lg.length; |
|
LocalVariable[] lv = new LocalVariable[size]; |
|
|
|
for (int i = 0; i < size; i++) { |
|
lv[i] = lg[i].getLocalVariable(cp); |
|
} |
|
|
|
return new LocalVariableTypeTable(cp.addUtf8("LocalVariableTypeTable"), |
|
2 + lv.length * 10, lv, cp.getConstantPool()); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private LocalVariableGen addLocalVariableType(String name, Type type, int slot, |
|
InstructionHandle start, |
|
InstructionHandle end) { |
|
byte t = type.getType(); |
|
|
|
if (t != Const.T_ADDRESS) { |
|
int add = type.getSize(); |
|
|
|
if (slot + add > max_locals) { |
|
max_locals = slot + add; |
|
} |
|
|
|
LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end); |
|
int i; |
|
|
|
if ((i = type_vec.indexOf(l)) >= 0) |
|
{ |
|
type_vec.set(i, l); |
|
} else { |
|
type_vec.add(l); |
|
} |
|
|
|
return l; |
|
} else { |
|
throw new IllegalArgumentException("Can not use " + type |
|
+ " as type for local variable"); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private void removeLocalVariableTypes() { |
|
type_vec.clear(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public LineNumberGen addLineNumber(final InstructionHandle ih, final int src_line) { |
|
final LineNumberGen l = new LineNumberGen(ih, src_line); |
|
line_number_vec.add(l); |
|
return l; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void removeLineNumber(final LineNumberGen l) { |
|
line_number_vec.remove(l); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void removeLineNumbers() { |
|
line_number_vec.clear(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public LineNumberGen[] getLineNumbers() { |
|
final LineNumberGen[] lg = new LineNumberGen[line_number_vec.size()]; |
|
line_number_vec.toArray(lg); |
|
return lg; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public LineNumberTable getLineNumberTable(final ConstantPoolGen cp) { |
|
final int size = line_number_vec.size(); |
|
final LineNumber[] ln = new LineNumber[size]; |
|
for (int i = 0; i < size; i++) { |
|
ln[i] = line_number_vec.get(i).getLineNumber(); |
|
} |
|
return new LineNumberTable(cp.addUtf8("LineNumberTable"), 2 + ln.length * 4, ln, cp |
|
.getConstantPool()); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public CodeExceptionGen addExceptionHandler(final InstructionHandle start_pc, |
|
final InstructionHandle end_pc, final InstructionHandle handler_pc, final ObjectType catch_type) { |
|
if ((start_pc == null) || (end_pc == null) || (handler_pc == null)) { |
|
throw new ClassGenException("Exception handler target is null instruction"); |
|
} |
|
final CodeExceptionGen c = new CodeExceptionGen(start_pc, end_pc, handler_pc, catch_type); |
|
exception_vec.add(c); |
|
return c; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void removeExceptionHandler(final CodeExceptionGen c) { |
|
exception_vec.remove(c); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void removeExceptionHandlers() { |
|
exception_vec.clear(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public CodeExceptionGen[] getExceptionHandlers() { |
|
final CodeExceptionGen[] cg = new CodeExceptionGen[exception_vec.size()]; |
|
exception_vec.toArray(cg); |
|
return cg; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private CodeException[] getCodeExceptions() { |
|
final int size = exception_vec.size(); |
|
final CodeException[] c_exc = new CodeException[size]; |
|
for (int i = 0; i < size; i++) { |
|
final CodeExceptionGen c = exception_vec.get(i); |
|
c_exc[i] = c.getCodeException(super.getConstantPool()); |
|
} |
|
return c_exc; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void addException(final String class_name) { |
|
throws_vec.add(class_name); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void removeException(final String c) { |
|
throws_vec.remove(c); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void removeExceptions() { |
|
throws_vec.clear(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public String[] getExceptions() { |
|
final String[] e = new String[throws_vec.size()]; |
|
throws_vec.toArray(e); |
|
return e; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private ExceptionTable getExceptionTable(final ConstantPoolGen cp) { |
|
final int size = throws_vec.size(); |
|
final int[] ex = new int[size]; |
|
for (int i = 0; i < size; i++) { |
|
ex[i] = cp.addClass(throws_vec.get(i)); |
|
} |
|
return new ExceptionTable(cp.addUtf8("Exceptions"), 2 + 2 * size, ex, cp.getConstantPool()); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void addCodeAttribute(final Attribute a) { |
|
code_attrs_vec.add(a); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void removeCodeAttribute(final Attribute a) { |
|
code_attrs_vec.remove(a); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void removeCodeAttributes() { |
|
code_attrs_vec.clear(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public Attribute[] getCodeAttributes() { |
|
final Attribute[] attributes = new Attribute[code_attrs_vec.size()]; |
|
code_attrs_vec.toArray(attributes); |
|
return attributes; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void addAnnotationsAsAttribute(final ConstantPoolGen cp) { |
|
final Attribute[] attrs = AnnotationEntryGen.getAnnotationAttributes(cp, super.getAnnotationEntries()); |
|
for (final Attribute attr : attrs) { |
|
addAttribute(attr); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void addParameterAnnotationsAsAttribute(final ConstantPoolGen cp) { |
|
if (!hasParameterAnnotations) { |
|
return; |
|
} |
|
final Attribute[] attrs = AnnotationEntryGen.getParameterAnnotationAttributes(cp, param_annotations); |
|
if (attrs != null) { |
|
for (final Attribute attr : attrs) { |
|
addAttribute(attr); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Method getMethod() { |
|
final String signature = getSignature(); |
|
final ConstantPoolGen _cp = super.getConstantPool(); |
|
final int name_index = _cp.addUtf8(super.getName()); |
|
final int signature_index = _cp.addUtf8(signature); |
|
|
|
*/ |
|
byte[] byte_code = null; |
|
if (il != null) { |
|
byte_code = il.getByteCode(); |
|
} |
|
LineNumberTable lnt = null; |
|
LocalVariableTable lvt = null; |
|
LocalVariableTypeTable lvtt = null; |
|
|
|
|
|
|
|
*/ |
|
if ((variable_vec.size() > 0) && !strip_attributes) { |
|
addCodeAttribute(lvt = getLocalVariableTable(_cp)); |
|
} |
|
|
|
if ((type_vec.size() > 0) && !strip_attributes) { |
|
addCodeAttribute(lvtt = getLocalVariableTypeTable(_cp)); |
|
} |
|
|
|
if ((line_number_vec.size() > 0) && !strip_attributes) { |
|
addCodeAttribute(lnt = getLineNumberTable(_cp)); |
|
} |
|
final Attribute[] code_attrs = getCodeAttributes(); |
|
|
|
*/ |
|
int attrs_len = 0; |
|
for (final Attribute code_attr : code_attrs) { |
|
attrs_len += code_attr.getLength() + 6; |
|
} |
|
final CodeException[] c_exc = getCodeExceptions(); |
|
final int exc_len = c_exc.length * 8; |
|
Code code = null; |
|
if ((il != null) && !isAbstract() && !isNative()) { |
|
|
|
final Attribute[] attributes = getAttributes(); |
|
for (final Attribute a : attributes) { |
|
if (a instanceof Code) { |
|
removeAttribute(a); |
|
} |
|
} |
|
code = new Code(_cp.addUtf8("Code"), 8 + byte_code.length + |
|
2 + exc_len + |
|
2 + attrs_len, |
|
max_stack, max_locals, byte_code, c_exc, code_attrs, _cp.getConstantPool()); |
|
addAttribute(code); |
|
} |
|
addAnnotationsAsAttribute(_cp); |
|
addParameterAnnotationsAsAttribute(_cp); |
|
ExceptionTable et = null; |
|
if (throws_vec.size() > 0) { |
|
addAttribute(et = getExceptionTable(_cp)); |
|
// Add `Exceptions' if there are "throws" clauses |
|
} |
|
final Method m = new Method(super.getAccessFlags(), name_index, signature_index, getAttributes(), _cp |
|
.getConstantPool()); |
|
|
|
if (lvt != null) { |
|
removeCodeAttribute(lvt); |
|
} |
|
if (lvtt != null) { |
|
removeCodeAttribute(lvtt); |
|
} |
|
if (lnt != null) { |
|
removeCodeAttribute(lnt); |
|
} |
|
if (code != null) { |
|
removeAttribute(code); |
|
} |
|
if (et != null) { |
|
removeAttribute(et); |
|
} |
|
return m; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void removeNOPs() { |
|
if (il != null) { |
|
InstructionHandle next; |
|
|
|
*/ |
|
for (InstructionHandle ih = il.getStart(); ih != null; ih = next) { |
|
next = ih.getNext(); |
|
if ((next != null) && (ih.getInstruction() instanceof NOP)) { |
|
try { |
|
il.delete(ih); |
|
} catch (final TargetLostException e) { |
|
for (final InstructionHandle target : e.getTargets()) { |
|
for (final InstructionTargeter targeter : target.getTargeters()) { |
|
targeter.updateTarget(target, next); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void setMaxLocals(final int m) { |
|
max_locals = m; |
|
} |
|
|
|
public int getMaxLocals() { |
|
return max_locals; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void setMaxStack(final int m) { |
|
max_stack = m; |
|
} |
|
|
|
public int getMaxStack() { |
|
return max_stack; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public String getClassName() { |
|
return class_name; |
|
} |
|
|
|
public void setClassName(final String class_name) { |
|
this.class_name = class_name; |
|
} |
|
|
|
public void setReturnType(final Type return_type) { |
|
setType(return_type); |
|
} |
|
|
|
public Type getReturnType() { |
|
return getType(); |
|
} |
|
|
|
public void setArgumentTypes(final Type[] arg_types) { |
|
this.arg_types = arg_types; |
|
} |
|
|
|
public Type[] getArgumentTypes() { |
|
return arg_types.clone(); |
|
} |
|
|
|
public void setArgumentType(final int i, final Type type) { |
|
arg_types[i] = type; |
|
} |
|
|
|
public Type getArgumentType(final int i) { |
|
return arg_types[i]; |
|
} |
|
|
|
public void setArgumentNames(final String[] arg_names) { |
|
this.arg_names = arg_names; |
|
} |
|
|
|
public String[] getArgumentNames() { |
|
return arg_names.clone(); |
|
} |
|
|
|
public void setArgumentName(final int i, final String name) { |
|
arg_names[i] = name; |
|
} |
|
|
|
public String getArgumentName(final int i) { |
|
return arg_names[i]; |
|
} |
|
|
|
public InstructionList getInstructionList() { |
|
return il; |
|
} |
|
|
|
public void setInstructionList(final InstructionList il) { |
|
this.il = il; |
|
} |
|
|
|
@Override |
|
public String getSignature() { |
|
return Type.getMethodSignature(super.getType(), arg_types); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void setMaxStack() { |
|
if (il != null) { |
|
max_stack = getMaxStack(super.getConstantPool(), il, getExceptionHandlers()); |
|
} else { |
|
max_stack = 0; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void setMaxLocals() { |
|
if (il != null) { |
|
int max = isStatic() ? 0 : 1; |
|
if (arg_types != null) { |
|
for (final Type arg_type : arg_types) { |
|
max += arg_type.getSize(); |
|
} |
|
} |
|
for (InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) { |
|
final Instruction ins = ih.getInstruction(); |
|
if ((ins instanceof LocalVariableInstruction) || (ins instanceof RET) |
|
|| (ins instanceof IINC)) { |
|
final int index = ((IndexedInstruction) ins).getIndex() |
|
+ ((TypedInstruction) ins).getType(super.getConstantPool()).getSize(); |
|
if (index > max) { |
|
max = index; |
|
} |
|
} |
|
} |
|
max_locals = max; |
|
} else { |
|
max_locals = 0; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public void stripAttributes(final boolean flag) { |
|
strip_attributes = flag; |
|
} |
|
|
|
static final class BranchTarget { |
|
|
|
final InstructionHandle target; |
|
final int stackDepth; |
|
|
|
BranchTarget(final InstructionHandle target, final int stackDepth) { |
|
this.target = target; |
|
this.stackDepth = stackDepth; |
|
} |
|
} |
|
|
|
static final class BranchStack { |
|
|
|
private final Stack<BranchTarget> branchTargets = new Stack<>(); |
|
private final Map<InstructionHandle, BranchTarget> visitedTargets = new HashMap<>(); |
|
|
|
public void push(final InstructionHandle target, final int stackDepth) { |
|
if (visited(target)) { |
|
return; |
|
} |
|
branchTargets.push(visit(target, stackDepth)); |
|
} |
|
|
|
public BranchTarget pop() { |
|
if (!branchTargets.empty()) { |
|
final BranchTarget bt = branchTargets.pop(); |
|
return bt; |
|
} |
|
return null; |
|
} |
|
|
|
private BranchTarget visit(final InstructionHandle target, final int stackDepth) { |
|
final BranchTarget bt = new BranchTarget(target, stackDepth); |
|
visitedTargets.put(target, bt); |
|
return bt; |
|
} |
|
|
|
private boolean visited(final InstructionHandle target) { |
|
return visitedTargets.get(target) != null; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static int getMaxStack(final ConstantPoolGen cp, final InstructionList il, |
|
final CodeExceptionGen[] et) { |
|
final BranchStack branchTargets = new BranchStack(); |
|
|
|
|
|
|
|
|
|
*/ |
|
for (final CodeExceptionGen element : et) { |
|
final InstructionHandle handler_pc = element.getHandlerPC(); |
|
if (handler_pc != null) { |
|
branchTargets.push(handler_pc, 1); |
|
} |
|
} |
|
int stackDepth = 0; |
|
int maxStackDepth = 0; |
|
InstructionHandle ih = il.getStart(); |
|
while (ih != null) { |
|
final Instruction instruction = ih.getInstruction(); |
|
final short opcode = instruction.getOpcode(); |
|
final int delta = instruction.produceStack(cp) - instruction.consumeStack(cp); |
|
stackDepth += delta; |
|
if (stackDepth > maxStackDepth) { |
|
maxStackDepth = stackDepth; |
|
} |
|
|
|
if (instruction instanceof BranchInstruction) { |
|
final BranchInstruction branch = (BranchInstruction) instruction; |
|
if (instruction instanceof Select) { |
|
|
|
final Select select = (Select) branch; |
|
final InstructionHandle[] targets = select.getTargets(); |
|
for (final InstructionHandle target : targets) { |
|
branchTargets.push(target, stackDepth); |
|
} |
|
|
|
ih = null; |
|
} else if (!(branch instanceof IfInstruction)) { |
|
// if an instruction that comes back to following PC, |
|
|
|
if (opcode == Const.JSR || opcode == Const.JSR_W) { |
|
branchTargets.push(ih.getNext(), stackDepth - 1); |
|
} |
|
ih = null; |
|
} |
|
// for all branches, the target of the branch is pushed on the branch stack. |
|
// conditional branches have a fall through case, selects don't, and |
|
|
|
branchTargets.push(branch.getTarget(), stackDepth); |
|
} else { |
|
|
|
if (opcode == Const.ATHROW || opcode == Const.RET |
|
|| (opcode >= Const.IRETURN && opcode <= Const.RETURN)) { |
|
ih = null; |
|
} |
|
} |
|
|
|
if (ih != null) { |
|
ih = ih.getNext(); |
|
} |
|
|
|
if (ih == null) { |
|
final BranchTarget bt = branchTargets.pop(); |
|
if (bt != null) { |
|
ih = bt.target; |
|
stackDepth = bt.stackDepth; |
|
} |
|
} |
|
} |
|
return maxStackDepth; |
|
} |
|
|
|
private List<MethodObserver> observers; |
|
|
|
|
|
|
|
*/ |
|
public void addObserver(final MethodObserver o) { |
|
if (observers == null) { |
|
observers = new ArrayList<>(); |
|
} |
|
observers.add(o); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void removeObserver(final MethodObserver o) { |
|
if (observers != null) { |
|
observers.remove(o); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void update() { |
|
if (observers != null) { |
|
for (final MethodObserver observer : observers) { |
|
observer.notify(this); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public final String toString() { |
|
final String access = Utility.accessToString(super.getAccessFlags()); |
|
String signature = Type.getMethodSignature(super.getType(), arg_types); |
|
signature = Utility.methodSignatureToString(signature, super.getName(), access, true, |
|
getLocalVariableTable(super.getConstantPool())); |
|
final StringBuilder buf = new StringBuilder(signature); |
|
for (final Attribute a : getAttributes()) { |
|
if (!((a instanceof Code) || (a instanceof ExceptionTable))) { |
|
buf.append(" [").append(a).append("]"); |
|
} |
|
} |
|
|
|
if (throws_vec.size() > 0) { |
|
for (final String throwsDescriptor : throws_vec) { |
|
buf.append("\n\t\tthrows ").append(throwsDescriptor); |
|
} |
|
} |
|
return buf.toString(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public MethodGen copy(final String class_name, final ConstantPoolGen cp) { |
|
final Method m = ((MethodGen) clone()).getMethod(); |
|
final MethodGen mg = new MethodGen(m, class_name, super.getConstantPool()); |
|
if (super.getConstantPool() != cp) { |
|
mg.setConstantPool(cp); |
|
mg.getInstructionList().replaceConstantPool(super.getConstantPool(), cp); |
|
} |
|
return mg; |
|
} |
|
|
|
//J5TODO: Should param_annotations be an array of arrays? Rather than an array of lists, this |
|
// is more likely to suggest to the caller it is readonly (which a List does not). |
|
|
|
|
|
|
|
|
|
*/ |
|
public List<AnnotationEntryGen> getAnnotationsOnParameter(final int i) { |
|
ensureExistingParameterAnnotationsUnpacked(); |
|
if (!hasParameterAnnotations || i > arg_types.length) { |
|
return null; |
|
} |
|
return param_annotations[i]; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void ensureExistingParameterAnnotationsUnpacked() { |
|
if (haveUnpackedParameterAnnotations) { |
|
return; |
|
} |
|
|
|
final Attribute[] attrs = getAttributes(); |
|
ParameterAnnotations paramAnnVisAttr = null; |
|
ParameterAnnotations paramAnnInvisAttr = null; |
|
for (final Attribute attribute : attrs) { |
|
if (attribute instanceof ParameterAnnotations) { |
|
|
|
if (!hasParameterAnnotations) { |
|
@SuppressWarnings({"rawtypes", "unchecked"}) |
|
final List<AnnotationEntryGen>[] parmList = new List[arg_types.length]; |
|
param_annotations = parmList; |
|
for (int j = 0; j < arg_types.length; j++) { |
|
param_annotations[j] = new ArrayList<>(); |
|
} |
|
} |
|
hasParameterAnnotations = true; |
|
final ParameterAnnotations rpa = (ParameterAnnotations) attribute; |
|
if (rpa instanceof RuntimeVisibleParameterAnnotations) { |
|
paramAnnVisAttr = rpa; |
|
} else { |
|
paramAnnInvisAttr = rpa; |
|
} |
|
for (int j = 0; j < arg_types.length; j++) { |
|
|
|
final ParameterAnnotationEntry immutableArray = rpa |
|
.getParameterAnnotationEntries()[j]; |
|
|
|
final List<AnnotationEntryGen> mutable |
|
= makeMutableVersion(immutableArray.getAnnotationEntries()); |
|
|
|
param_annotations[j].addAll(mutable); |
|
} |
|
} |
|
} |
|
if (paramAnnVisAttr != null) { |
|
removeAttribute(paramAnnVisAttr); |
|
} |
|
if (paramAnnInvisAttr != null) { |
|
removeAttribute(paramAnnInvisAttr); |
|
} |
|
haveUnpackedParameterAnnotations = true; |
|
} |
|
|
|
private List<AnnotationEntryGen> makeMutableVersion(final AnnotationEntry[] mutableArray) { |
|
final List<AnnotationEntryGen> result = new ArrayList<>(); |
|
for (final AnnotationEntry element : mutableArray) { |
|
result.add(new AnnotationEntryGen(element, getConstantPool(), |
|
false)); |
|
} |
|
return result; |
|
} |
|
|
|
public void addParameterAnnotation(final int parameterIndex, |
|
final AnnotationEntryGen annotation) { |
|
ensureExistingParameterAnnotationsUnpacked(); |
|
if (!hasParameterAnnotations) { |
|
@SuppressWarnings({"rawtypes", "unchecked"}) |
|
final List<AnnotationEntryGen>[] parmList = new List[arg_types.length]; |
|
param_annotations = parmList; |
|
hasParameterAnnotations = true; |
|
} |
|
final List<AnnotationEntryGen> existingAnnotations = param_annotations[parameterIndex]; |
|
if (existingAnnotations != null) { |
|
existingAnnotations.add(annotation); |
|
} else { |
|
final List<AnnotationEntryGen> l = new ArrayList<>(); |
|
l.add(annotation); |
|
param_annotations[parameterIndex] = l; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static BCELComparator getComparator() { |
|
return bcelComparator; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static void setComparator(final BCELComparator comparator) { |
|
bcelComparator = comparator; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public boolean equals(final Object obj) { |
|
return bcelComparator.equals(this, obj); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public int hashCode() { |
|
return bcelComparator.hashCode(this); |
|
} |
|
} |