|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.reflect; |
|
|
|
import java.security.AccessController; |
|
import java.security.PrivilegedAction; |
|
|
|
/** Generator for sun.reflect.MethodAccessor and |
|
sun.reflect.ConstructorAccessor objects using bytecodes to |
|
implement reflection. A java.lang.reflect.Method or |
|
java.lang.reflect.Constructor object can delegate its invoke or |
|
newInstance method to an accessor using native code or to one |
|
generated by this class. (Methods and Constructors were merged |
|
together in this class to ensure maximum code sharing.) */ |
|
|
|
class MethodAccessorGenerator extends AccessorGenerator { |
|
|
|
private static final short NUM_BASE_CPOOL_ENTRIES = (short) 12; |
|
|
|
private static final short NUM_METHODS = (short) 2; |
|
|
|
private static final short NUM_SERIALIZATION_CPOOL_ENTRIES = (short) 2; |
|
|
|
private static volatile int methodSymnum = 0; |
|
private static volatile int constructorSymnum = 0; |
|
private static volatile int serializationConstructorSymnum = 0; |
|
|
|
private Class<?> declaringClass; |
|
private Class<?>[] parameterTypes; |
|
private Class<?> returnType; |
|
private boolean isConstructor; |
|
private boolean forSerialization; |
|
|
|
private short targetMethodRef; |
|
private short invokeIdx; |
|
private short invokeDescriptorIdx; |
|
// Constant pool index of CONSTANT_Class_info for first |
|
|
|
private short nonPrimitiveParametersBaseIdx; |
|
|
|
MethodAccessorGenerator() { |
|
} |
|
|
|
|
|
public MethodAccessor generateMethod(Class<?> declaringClass, |
|
String name, |
|
Class<?>[] parameterTypes, |
|
Class<?> returnType, |
|
Class<?>[] checkedExceptions, |
|
int modifiers) |
|
{ |
|
return (MethodAccessor) generate(declaringClass, |
|
name, |
|
parameterTypes, |
|
returnType, |
|
checkedExceptions, |
|
modifiers, |
|
false, |
|
false, |
|
null); |
|
} |
|
|
|
|
|
public ConstructorAccessor generateConstructor(Class<?> declaringClass, |
|
Class<?>[] parameterTypes, |
|
Class<?>[] checkedExceptions, |
|
int modifiers) |
|
{ |
|
return (ConstructorAccessor) generate(declaringClass, |
|
"<init>", |
|
parameterTypes, |
|
Void.TYPE, |
|
checkedExceptions, |
|
modifiers, |
|
true, |
|
false, |
|
null); |
|
} |
|
|
|
|
|
public SerializationConstructorAccessorImpl |
|
generateSerializationConstructor(Class<?> declaringClass, |
|
Class<?>[] parameterTypes, |
|
Class<?>[] checkedExceptions, |
|
int modifiers, |
|
Class<?> targetConstructorClass) |
|
{ |
|
return (SerializationConstructorAccessorImpl) |
|
generate(declaringClass, |
|
"<init>", |
|
parameterTypes, |
|
Void.TYPE, |
|
checkedExceptions, |
|
modifiers, |
|
true, |
|
true, |
|
targetConstructorClass); |
|
} |
|
|
|
|
|
private MagicAccessorImpl generate(final Class<?> declaringClass, |
|
String name, |
|
Class<?>[] parameterTypes, |
|
Class<?> returnType, |
|
Class<?>[] checkedExceptions, |
|
int modifiers, |
|
boolean isConstructor, |
|
boolean forSerialization, |
|
Class<?> serializationTargetClass) |
|
{ |
|
ByteVector vec = ByteVectorFactory.create(); |
|
asm = new ClassFileAssembler(vec); |
|
this.declaringClass = declaringClass; |
|
this.parameterTypes = parameterTypes; |
|
this.returnType = returnType; |
|
this.modifiers = modifiers; |
|
this.isConstructor = isConstructor; |
|
this.forSerialization = forSerialization; |
|
|
|
asm.emitMagicAndVersion(); |
|
|
|
// Constant pool entries: |
|
// ( * = Boxing information: optional) |
|
// (+ = Shared entries provided by AccessorGenerator) |
|
// (^ = Only present if generating SerializationConstructorAccessor) |
|
// [UTF-8] [This class's name] |
|
// [CONSTANT_Class_info] for above |
|
// [UTF-8] "sun/reflect/{MethodAccessorImpl,ConstructorAccessorImpl,SerializationConstructorAccessorImpl}" |
|
// [CONSTANT_Class_info] for above |
|
// [UTF-8] [Target class's name] |
|
// [CONSTANT_Class_info] for above |
|
// ^ [UTF-8] [Serialization: Class's name in which to invoke constructor] |
|
// ^ [CONSTANT_Class_info] for above |
|
// [UTF-8] target method or constructor name |
|
// [UTF-8] target method or constructor signature |
|
// [CONSTANT_NameAndType_info] for above |
|
// [CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info] for target method |
|
// [UTF-8] "invoke" or "newInstance" |
|
// [UTF-8] invoke or newInstance descriptor |
|
// [UTF-8] descriptor for type of non-primitive parameter 1 |
|
// [CONSTANT_Class_info] for type of non-primitive parameter 1 |
|
// ... |
|
// [UTF-8] descriptor for type of non-primitive parameter n |
|
// [CONSTANT_Class_info] for type of non-primitive parameter n |
|
// + [UTF-8] "java/lang/Exception" |
|
// + [CONSTANT_Class_info] for above |
|
// + [UTF-8] "java/lang/ClassCastException" |
|
// + [CONSTANT_Class_info] for above |
|
// + [UTF-8] "java/lang/NullPointerException" |
|
// + [CONSTANT_Class_info] for above |
|
// + [UTF-8] "java/lang/IllegalArgumentException" |
|
// + [CONSTANT_Class_info] for above |
|
// + [UTF-8] "java/lang/InvocationTargetException" |
|
// + [CONSTANT_Class_info] for above |
|
// + [UTF-8] "<init>" |
|
// + [UTF-8] "()V" |
|
// + [CONSTANT_NameAndType_info] for above |
|
// + [CONSTANT_Methodref_info] for NullPointerException's constructor |
|
// + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor |
|
// + [UTF-8] "(Ljava/lang/String;)V" |
|
// + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/String;)V" |
|
// + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor taking a String |
|
// + [UTF-8] "(Ljava/lang/Throwable;)V" |
|
// + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/Throwable;)V" |
|
// + [CONSTANT_Methodref_info] for InvocationTargetException's constructor |
|
// + [CONSTANT_Methodref_info] for "super()" |
|
// + [UTF-8] "java/lang/Object" |
|
// + [CONSTANT_Class_info] for above |
|
// + [UTF-8] "toString" |
|
// + [UTF-8] "()Ljava/lang/String;" |
|
// + [CONSTANT_NameAndType_info] for "toString()Ljava/lang/String;" |
|
// + [CONSTANT_Methodref_info] for Object's toString method |
|
// + [UTF-8] "Code" |
|
// + [UTF-8] "Exceptions" |
|
// * [UTF-8] "java/lang/Boolean" |
|
// * [CONSTANT_Class_info] for above |
|
// * [UTF-8] "(Z)V" |
|
// * [CONSTANT_NameAndType_info] for above |
|
// * [CONSTANT_Methodref_info] for above |
|
// * [UTF-8] "booleanValue" |
|
// * [UTF-8] "()Z" |
|
// * [CONSTANT_NameAndType_info] for above |
|
// * [CONSTANT_Methodref_info] for above |
|
// * [UTF-8] "java/lang/Byte" |
|
// * [CONSTANT_Class_info] for above |
|
// * [UTF-8] "(B)V" |
|
// * [CONSTANT_NameAndType_info] for above |
|
// * [CONSTANT_Methodref_info] for above |
|
// * [UTF-8] "byteValue" |
|
// * [UTF-8] "()B" |
|
// * [CONSTANT_NameAndType_info] for above |
|
// * [CONSTANT_Methodref_info] for above |
|
// * [UTF-8] "java/lang/Character" |
|
// * [CONSTANT_Class_info] for above |
|
// * [UTF-8] "(C)V" |
|
// * [CONSTANT_NameAndType_info] for above |
|
// * [CONSTANT_Methodref_info] for above |
|
// * [UTF-8] "charValue" |
|
// * [UTF-8] "()C" |
|
// * [CONSTANT_NameAndType_info] for above |
|
// * [CONSTANT_Methodref_info] for above |
|
// * [UTF-8] "java/lang/Double" |
|
// * [CONSTANT_Class_info] for above |
|
// * [UTF-8] "(D)V" |
|
// * [CONSTANT_NameAndType_info] for above |
|
// * [CONSTANT_Methodref_info] for above |
|
// * [UTF-8] "doubleValue" |
|
// * [UTF-8] "()D" |
|
// * [CONSTANT_NameAndType_info] for above |
|
// * [CONSTANT_Methodref_info] for above |
|
// * [UTF-8] "java/lang/Float" |
|
// * [CONSTANT_Class_info] for above |
|
// * [UTF-8] "(F)V" |
|
// * [CONSTANT_NameAndType_info] for above |
|
// * [CONSTANT_Methodref_info] for above |
|
// * [UTF-8] "floatValue" |
|
// * [UTF-8] "()F" |
|
// * [CONSTANT_NameAndType_info] for above |
|
// * [CONSTANT_Methodref_info] for above |
|
// * [UTF-8] "java/lang/Integer" |
|
// * [CONSTANT_Class_info] for above |
|
// * [UTF-8] "(I)V" |
|
// * [CONSTANT_NameAndType_info] for above |
|
// * [CONSTANT_Methodref_info] for above |
|
// * [UTF-8] "intValue" |
|
// * [UTF-8] "()I" |
|
// * [CONSTANT_NameAndType_info] for above |
|
// * [CONSTANT_Methodref_info] for above |
|
// * [UTF-8] "java/lang/Long" |
|
// * [CONSTANT_Class_info] for above |
|
// * [UTF-8] "(J)V" |
|
// * [CONSTANT_NameAndType_info] for above |
|
// * [CONSTANT_Methodref_info] for above |
|
// * [UTF-8] "longValue" |
|
// * [UTF-8] "()J" |
|
// * [CONSTANT_NameAndType_info] for above |
|
// * [CONSTANT_Methodref_info] for above |
|
// * [UTF-8] "java/lang/Short" |
|
// * [CONSTANT_Class_info] for above |
|
// * [UTF-8] "(S)V" |
|
// * [CONSTANT_NameAndType_info] for above |
|
// * [CONSTANT_Methodref_info] for above |
|
// * [UTF-8] "shortValue" |
|
// * [UTF-8] "()S" |
|
// * [CONSTANT_NameAndType_info] for above |
|
// * [CONSTANT_Methodref_info] for above |
|
|
|
short numCPEntries = NUM_BASE_CPOOL_ENTRIES + NUM_COMMON_CPOOL_ENTRIES; |
|
boolean usesPrimitives = usesPrimitiveTypes(); |
|
if (usesPrimitives) { |
|
numCPEntries += NUM_BOXING_CPOOL_ENTRIES; |
|
} |
|
if (forSerialization) { |
|
numCPEntries += NUM_SERIALIZATION_CPOOL_ENTRIES; |
|
} |
|
|
|
// Add in variable-length number of entries to be able to describe |
|
|
|
numCPEntries += (short) (2 * numNonPrimitiveParameterTypes()); |
|
|
|
asm.emitShort(add(numCPEntries, S1)); |
|
|
|
final String generatedName = generateName(isConstructor, forSerialization); |
|
asm.emitConstantPoolUTF8(generatedName); |
|
asm.emitConstantPoolClass(asm.cpi()); |
|
thisClass = asm.cpi(); |
|
if (isConstructor) { |
|
if (forSerialization) { |
|
asm.emitConstantPoolUTF8 |
|
("sun/reflect/SerializationConstructorAccessorImpl"); |
|
} else { |
|
asm.emitConstantPoolUTF8("sun/reflect/ConstructorAccessorImpl"); |
|
} |
|
} else { |
|
asm.emitConstantPoolUTF8("sun/reflect/MethodAccessorImpl"); |
|
} |
|
asm.emitConstantPoolClass(asm.cpi()); |
|
superClass = asm.cpi(); |
|
asm.emitConstantPoolUTF8(getClassName(declaringClass, false)); |
|
asm.emitConstantPoolClass(asm.cpi()); |
|
targetClass = asm.cpi(); |
|
short serializationTargetClassIdx = (short) 0; |
|
if (forSerialization) { |
|
asm.emitConstantPoolUTF8(getClassName(serializationTargetClass, false)); |
|
asm.emitConstantPoolClass(asm.cpi()); |
|
serializationTargetClassIdx = asm.cpi(); |
|
} |
|
asm.emitConstantPoolUTF8(name); |
|
asm.emitConstantPoolUTF8(buildInternalSignature()); |
|
asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); |
|
if (isInterface()) { |
|
asm.emitConstantPoolInterfaceMethodref(targetClass, asm.cpi()); |
|
} else { |
|
if (forSerialization) { |
|
asm.emitConstantPoolMethodref(serializationTargetClassIdx, asm.cpi()); |
|
} else { |
|
asm.emitConstantPoolMethodref(targetClass, asm.cpi()); |
|
} |
|
} |
|
targetMethodRef = asm.cpi(); |
|
if (isConstructor) { |
|
asm.emitConstantPoolUTF8("newInstance"); |
|
} else { |
|
asm.emitConstantPoolUTF8("invoke"); |
|
} |
|
invokeIdx = asm.cpi(); |
|
if (isConstructor) { |
|
asm.emitConstantPoolUTF8("([Ljava/lang/Object;)Ljava/lang/Object;"); |
|
} else { |
|
asm.emitConstantPoolUTF8 |
|
("(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); |
|
} |
|
invokeDescriptorIdx = asm.cpi(); |
|
|
|
|
|
nonPrimitiveParametersBaseIdx = add(asm.cpi(), S2); |
|
for (int i = 0; i < parameterTypes.length; i++) { |
|
Class<?> c = parameterTypes[i]; |
|
if (!isPrimitive(c)) { |
|
asm.emitConstantPoolUTF8(getClassName(c, false)); |
|
asm.emitConstantPoolClass(asm.cpi()); |
|
} |
|
} |
|
|
|
|
|
emitCommonConstantPoolEntries(); |
|
|
|
|
|
if (usesPrimitives) { |
|
emitBoxingContantPoolEntries(); |
|
} |
|
|
|
if (asm.cpi() != numCPEntries) { |
|
throw new InternalError("Adjust this code (cpi = " + asm.cpi() + |
|
", numCPEntries = " + numCPEntries + ")"); |
|
} |
|
|
|
|
|
asm.emitShort(ACC_PUBLIC); |
|
|
|
|
|
asm.emitShort(thisClass); |
|
|
|
|
|
asm.emitShort(superClass); |
|
|
|
|
|
asm.emitShort(S0); |
|
|
|
|
|
asm.emitShort(S0); |
|
|
|
|
|
asm.emitShort(NUM_METHODS); |
|
|
|
emitConstructor(); |
|
emitInvoke(); |
|
|
|
|
|
asm.emitShort(S0); |
|
|
|
|
|
vec.trim(); |
|
final byte[] bytes = vec.getData(); |
|
// Note: the class loader is the only thing that really matters |
|
// here -- it's important to get the generated code into the |
|
// same namespace as the target class. Since the generated code |
|
// is privileged anyway, the protection domain probably doesn't |
|
|
|
return AccessController.doPrivileged( |
|
new PrivilegedAction<MagicAccessorImpl>() { |
|
public MagicAccessorImpl run() { |
|
try { |
|
return (MagicAccessorImpl) |
|
ClassDefiner.defineClass |
|
(generatedName, |
|
bytes, |
|
0, |
|
bytes.length, |
|
declaringClass.getClassLoader()).newInstance(); |
|
} catch (InstantiationException | IllegalAccessException e) { |
|
throw new InternalError(e); |
|
} |
|
} |
|
}); |
|
} |
|
|
|
|
|
private void emitInvoke() { |
|
// NOTE that this code will only handle 65535 parameters since we |
|
// use the sipush instruction to get the array index on the |
|
|
|
if (parameterTypes.length > 65535) { |
|
throw new InternalError("Can't handle more than 65535 parameters"); |
|
} |
|
|
|
|
|
ClassFileAssembler cb = new ClassFileAssembler(); |
|
if (isConstructor) { |
|
|
|
cb.setMaxLocals(2); |
|
} else { |
|
|
|
cb.setMaxLocals(3); |
|
} |
|
|
|
short illegalArgStartPC = 0; |
|
|
|
if (isConstructor) { |
|
// Instantiate target class before continuing |
|
// new <target class type> |
|
|
|
cb.opc_new(targetClass); |
|
cb.opc_dup(); |
|
} else { |
|
|
|
if (isPrimitive(returnType)) { |
|
// new <boxing type for primitive type> |
|
// dup |
|
// ... (see below:) |
|
// invokespecial <constructor for boxing type for primitive type> |
|
|
|
cb.opc_new(indexForPrimitiveType(returnType)); |
|
cb.opc_dup(); |
|
} |
|
|
|
// Get target object on operand stack if necessary. |
|
|
|
// We need to do an explicit null check here; we won't see |
|
// NullPointerExceptions from the invoke bytecode, since it's |
|
|
|
if (!isStatic()) { |
|
// aload_1 |
|
// ifnonnull <checkcast label> |
|
// new <NullPointerException> |
|
// dup |
|
// invokespecial <NullPointerException ctor> |
|
// athrow |
|
// <checkcast label:> |
|
// aload_1 |
|
|
|
cb.opc_aload_1(); |
|
Label l = new Label(); |
|
cb.opc_ifnonnull(l); |
|
cb.opc_new(nullPointerClass); |
|
cb.opc_dup(); |
|
cb.opc_invokespecial(nullPointerCtorIdx, 0, 0); |
|
cb.opc_athrow(); |
|
l.bind(); |
|
illegalArgStartPC = cb.getLength(); |
|
cb.opc_aload_1(); |
|
cb.opc_checkcast(targetClass); |
|
} |
|
} |
|
|
|
// Have to check length of incoming array and throw |
|
// IllegalArgumentException if not correct. A concession to the |
|
// JCK (isn't clearly specified in the spec): we allow null in the |
|
// case where the argument list is zero length. |
|
// if no-arg: |
|
// aload_2 | aload_1 (Method | Constructor) |
|
// ifnull <success label> |
|
// aload_2 | aload_1 |
|
// arraylength |
|
// sipush <num parameter types> |
|
// if_icmpeq <success label> |
|
// new <IllegalArgumentException> |
|
// dup |
|
// invokespecial <IllegalArgumentException ctor> |
|
// athrow |
|
|
|
Label successLabel = new Label(); |
|
if (parameterTypes.length == 0) { |
|
if (isConstructor) { |
|
cb.opc_aload_1(); |
|
} else { |
|
cb.opc_aload_2(); |
|
} |
|
cb.opc_ifnull(successLabel); |
|
} |
|
if (isConstructor) { |
|
cb.opc_aload_1(); |
|
} else { |
|
cb.opc_aload_2(); |
|
} |
|
cb.opc_arraylength(); |
|
cb.opc_sipush((short) parameterTypes.length); |
|
cb.opc_if_icmpeq(successLabel); |
|
cb.opc_new(illegalArgumentClass); |
|
cb.opc_dup(); |
|
cb.opc_invokespecial(illegalArgumentCtorIdx, 0, 0); |
|
cb.opc_athrow(); |
|
successLabel.bind(); |
|
|
|
// Iterate through incoming actual parameters, ensuring that each |
|
// is compatible with the formal parameter type, and pushing the |
|
// actual on the operand stack (unboxing and widening if necessary). |
|
|
|
short paramTypeCPIdx = nonPrimitiveParametersBaseIdx; |
|
Label nextParamLabel = null; |
|
byte count = 1; |
|
|
|
for (int i = 0; i < parameterTypes.length; i++) { |
|
Class<?> paramType = parameterTypes[i]; |
|
count += (byte) typeSizeInStackSlots(paramType); |
|
if (nextParamLabel != null) { |
|
nextParamLabel.bind(); |
|
nextParamLabel = null; |
|
} |
|
// aload_2 | aload_1 |
|
// sipush <index> |
|
|
|
if (isConstructor) { |
|
cb.opc_aload_1(); |
|
} else { |
|
cb.opc_aload_2(); |
|
} |
|
cb.opc_sipush((short) i); |
|
cb.opc_aaload(); |
|
if (isPrimitive(paramType)) { |
|
// Unboxing code. |
|
// Put parameter into temporary local variable |
|
|
|
if (isConstructor) { |
|
cb.opc_astore_2(); |
|
} else { |
|
cb.opc_astore_3(); |
|
} |
|
|
|
// repeat for all possible widening conversions: |
|
// aload_3 | aload_2 |
|
// instanceof <primitive boxing type> |
|
// ifeq <next unboxing label> |
|
// aload_3 | aload_2 |
|
// checkcast <primitive boxing type> // Note: this is "redundant", |
|
// // but necessary for the verifier |
|
// invokevirtual <unboxing method> |
|
// <widening conversion bytecode, if necessary> |
|
// goto <next parameter label> |
|
// <next unboxing label:> ... |
|
// last unboxing label: |
|
// new <IllegalArgumentException> |
|
// dup |
|
// invokespecial <IllegalArgumentException ctor> |
|
// athrow |
|
|
|
Label l = null; |
|
nextParamLabel = new Label(); |
|
|
|
for (int j = 0; j < primitiveTypes.length; j++) { |
|
Class<?> c = primitiveTypes[j]; |
|
if (canWidenTo(c, paramType)) { |
|
if (l != null) { |
|
l.bind(); |
|
} |
|
|
|
if (isConstructor) { |
|
cb.opc_aload_2(); |
|
} else { |
|
cb.opc_aload_3(); |
|
} |
|
cb.opc_instanceof(indexForPrimitiveType(c)); |
|
l = new Label(); |
|
cb.opc_ifeq(l); |
|
if (isConstructor) { |
|
cb.opc_aload_2(); |
|
} else { |
|
cb.opc_aload_3(); |
|
} |
|
cb.opc_checkcast(indexForPrimitiveType(c)); |
|
cb.opc_invokevirtual(unboxingMethodForPrimitiveType(c), |
|
0, |
|
typeSizeInStackSlots(c)); |
|
emitWideningBytecodeForPrimitiveConversion(cb, |
|
c, |
|
paramType); |
|
cb.opc_goto(nextParamLabel); |
|
} |
|
} |
|
|
|
if (l == null) { |
|
throw new InternalError |
|
("Must have found at least identity conversion"); |
|
} |
|
|
|
// Fell through; given object is null or invalid. According to |
|
// the spec, we can throw IllegalArgumentException for both of |
|
// these cases. |
|
|
|
l.bind(); |
|
cb.opc_new(illegalArgumentClass); |
|
cb.opc_dup(); |
|
cb.opc_invokespecial(illegalArgumentCtorIdx, 0, 0); |
|
cb.opc_athrow(); |
|
} else { |
|
|
|
cb.opc_checkcast(paramTypeCPIdx); |
|
paramTypeCPIdx = add(paramTypeCPIdx, S2); |
|
// Fall through to next argument |
|
} |
|
} |
|
|
|
if (nextParamLabel != null) { |
|
nextParamLabel.bind(); |
|
} |
|
|
|
short invokeStartPC = cb.getLength(); |
|
|
|
|
|
if (isConstructor) { |
|
cb.opc_invokespecial(targetMethodRef, count, 0); |
|
} else { |
|
if (isStatic()) { |
|
cb.opc_invokestatic(targetMethodRef, |
|
count, |
|
typeSizeInStackSlots(returnType)); |
|
} else { |
|
if (isInterface()) { |
|
if (isPrivate()) { |
|
cb.opc_invokespecial(targetMethodRef, count, 0); |
|
} else { |
|
cb.opc_invokeinterface(targetMethodRef, |
|
count, |
|
count, |
|
typeSizeInStackSlots(returnType)); |
|
} |
|
} else { |
|
cb.opc_invokevirtual(targetMethodRef, |
|
count, |
|
typeSizeInStackSlots(returnType)); |
|
} |
|
} |
|
} |
|
|
|
short invokeEndPC = cb.getLength(); |
|
|
|
if (!isConstructor) { |
|
|
|
if (isPrimitive(returnType)) { |
|
cb.opc_invokespecial(ctorIndexForPrimitiveType(returnType), |
|
typeSizeInStackSlots(returnType), |
|
0); |
|
} else if (returnType == Void.TYPE) { |
|
cb.opc_aconst_null(); |
|
} |
|
} |
|
cb.opc_areturn(); |
|
|
|
// We generate two exception handlers; one which is responsible |
|
// for catching ClassCastException and NullPointerException and |
|
// throwing IllegalArgumentException, and the other which catches |
|
// all java/lang/Throwable objects thrown from the target method |
|
// and wraps them in InvocationTargetExceptions. |
|
|
|
short classCastHandler = cb.getLength(); |
|
|
|
|
|
cb.setStack(1); |
|
cb.opc_invokespecial(toStringIdx, 0, 1); |
|
cb.opc_new(illegalArgumentClass); |
|
cb.opc_dup_x1(); |
|
cb.opc_swap(); |
|
cb.opc_invokespecial(illegalArgumentStringCtorIdx, 1, 0); |
|
cb.opc_athrow(); |
|
|
|
short invocationTargetHandler = cb.getLength(); |
|
|
|
|
|
cb.setStack(1); |
|
cb.opc_new(invocationTargetClass); |
|
cb.opc_dup_x1(); |
|
cb.opc_swap(); |
|
cb.opc_invokespecial(invocationTargetCtorIdx, 1, 0); |
|
cb.opc_athrow(); |
|
|
|
// Generate exception table. We cover the entire code sequence |
|
// with an exception handler which catches ClassCastException and |
|
// converts it into an IllegalArgumentException. |
|
|
|
ClassFileAssembler exc = new ClassFileAssembler(); |
|
|
|
exc.emitShort(illegalArgStartPC); |
|
exc.emitShort(invokeStartPC); |
|
exc.emitShort(classCastHandler); |
|
exc.emitShort(classCastClass); |
|
|
|
exc.emitShort(illegalArgStartPC); |
|
exc.emitShort(invokeStartPC); |
|
exc.emitShort(classCastHandler); |
|
exc.emitShort(nullPointerClass); |
|
|
|
exc.emitShort(invokeStartPC); |
|
exc.emitShort(invokeEndPC); |
|
exc.emitShort(invocationTargetHandler); |
|
exc.emitShort(throwableClass); |
|
|
|
emitMethod(invokeIdx, cb.getMaxLocals(), cb, exc, |
|
new short[] { invocationTargetClass }); |
|
} |
|
|
|
private boolean usesPrimitiveTypes() { |
|
// We need to emit boxing/unboxing constant pool information if |
|
// the method takes a primitive type for any of its parameters or |
|
|
|
if (returnType.isPrimitive()) { |
|
return true; |
|
} |
|
for (int i = 0; i < parameterTypes.length; i++) { |
|
if (parameterTypes[i].isPrimitive()) { |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
private int numNonPrimitiveParameterTypes() { |
|
int num = 0; |
|
for (int i = 0; i < parameterTypes.length; i++) { |
|
if (!parameterTypes[i].isPrimitive()) { |
|
++num; |
|
} |
|
} |
|
return num; |
|
} |
|
|
|
private boolean isInterface() { |
|
return declaringClass.isInterface(); |
|
} |
|
|
|
private String buildInternalSignature() { |
|
StringBuffer buf = new StringBuffer(); |
|
buf.append("("); |
|
for (int i = 0; i < parameterTypes.length; i++) { |
|
buf.append(getClassName(parameterTypes[i], true)); |
|
} |
|
buf.append(")"); |
|
buf.append(getClassName(returnType, true)); |
|
return buf.toString(); |
|
} |
|
|
|
private static synchronized String generateName(boolean isConstructor, |
|
boolean forSerialization) |
|
{ |
|
if (isConstructor) { |
|
if (forSerialization) { |
|
int num = ++serializationConstructorSymnum; |
|
return "sun/reflect/GeneratedSerializationConstructorAccessor" + num; |
|
} else { |
|
int num = ++constructorSymnum; |
|
return "sun/reflect/GeneratedConstructorAccessor" + num; |
|
} |
|
} else { |
|
int num = ++methodSymnum; |
|
return "sun/reflect/GeneratedMethodAccessor" + num; |
|
} |
|
} |
|
} |