/** * Find or create an interface method signature for the given method reference. * * @param ref A reference to a supposed interface method * @return the interface method signature */ public static synchronized InterfaceMethodSignature findOrCreate(MemberReference ref) { InterfaceMethodSignature key = new InterfaceMethodSignature(ref.getName(), ref.getDescriptor(), nextId + 1); InterfaceMethodSignature val = dictionary.get(key); if (val != null) return val; nextId++; dictionary.add(key); return key; }
/** Find the value for an annotation */ private Object getElementValue(String name, Class<?> valueType) { for (AnnotationMember evp : elementValuePairs) { String evpFieldName = evp.getName().toString(); if (name.equals(evpFieldName)) { return evp.getValue(); } } MethodReference methRef = MemberReference.findOrCreate( type, Atom.findOrCreateAsciiAtom(name), Atom.findOrCreateAsciiAtom("()" + TypeReference.findOrCreate(valueType).getName())) .asMethodReference(); try { return methRef.resolve().getAnnotationDefault(); } catch (Throwable t) { return NO_VALUE; } }
/** * Read the pair from the input stream and create object * * @param constantPool the constant pool for the class being read * @param input stream to read from * @param classLoader the class loader being used to load this annotation * @return a newly created annotation member */ static AnnotationMember readAnnotationMember( TypeReference type, int[] constantPool, DataInputStream input, ClassLoader classLoader) throws IOException, ClassNotFoundException { // Read name of pair int elemNameIndex = input.readUnsignedShort(); Atom name = RVMClass.getUtf(constantPool, elemNameIndex); MethodReference meth; Object value; if (type.isResolved()) { meth = type.resolve().asClass().findDeclaredMethod(name).getMemberRef().asMethodReference(); value = RVMAnnotation.readValue(meth.getReturnType(), constantPool, input, classLoader); } else { value = RVMAnnotation.readValue(null, constantPool, input, classLoader); meth = MemberReference.findOrCreate( type, name, Atom.findOrCreateAsciiAtom( "()" + TypeReference.findOrCreate(value.getClass()).getName())) .asMethodReference(); } return new AnnotationMember(meth, value); }
/** * Create a method for reflectively invoking this method * * @param reflectionClass the class this method will belong to * @param constantPool for the class * @param memRef the member reference corresponding to this method * @return the created method */ RVMMethod createReflectionMethod( TypeReference reflectionClass, int[] constantPool, MethodReference memRef) { TypeReference[] parameters = getParameterTypes(); int numParams = parameters.length; byte[] bytecodes; boolean interfaceCall = false; int curBC = 0; if (!isStatic()) { if (!getDeclaringClass().isInterface()) { // virtual call bytecodes = new byte[8 * numParams + 8]; } else { // interface call bytecodes = new byte[8 * numParams + 10]; interfaceCall = true; } bytecodes[curBC] = JBC_aload_1; curBC++; } else { // static call bytecodes = new byte[8 * numParams + 7]; } for (int i = 0; i < numParams; i++) { if (parameters[i].isVoidType()) { bytecodes[curBC] = bytecodes[curBC + 1] = bytecodes[curBC + 2] = bytecodes[curBC + 3] = bytecodes[curBC + 4] = bytecodes[curBC + 5] = bytecodes[curBC + 6] = bytecodes[curBC + 7] = (byte) JBC_nop; continue; } bytecodes[curBC] = (byte) JBC_aload_2; bytecodes[curBC + 1] = (byte) JBC_sipush; bytecodes[curBC + 2] = (byte) (i >>> 8); bytecodes[curBC + 3] = (byte) i; bytecodes[curBC + 4] = (byte) JBC_aaload; if (!parameters[i].isPrimitiveType()) { bytecodes[curBC + 5] = (byte) JBC_checkcast; if (VM.VerifyAssertions) VM._assert(parameters[i].getId() != 0); constantPool[i + 1] = ClassFileReader.packCPEntry(CP_CLASS, parameters[i].getId()); bytecodes[curBC + 6] = (byte) ((i + 1) >>> 8); bytecodes[curBC + 7] = (byte) (i + 1); } else if (parameters[i].isWordLikeType()) { bytecodes[curBC + 5] = bytecodes[curBC + 6] = bytecodes[curBC + 7] = (byte) JBC_nop; } else { bytecodes[curBC + 5] = (byte) JBC_invokestatic; MemberReference unboxMethod; if (parameters[i].isBooleanType()) { unboxMethod = MethodReference.findOrCreate( baseReflectionClass, Atom.findOrCreateUnicodeAtom("unboxAsBoolean"), Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;)Z")); } else if (parameters[i].isByteType()) { unboxMethod = MethodReference.findOrCreate( baseReflectionClass, Atom.findOrCreateUnicodeAtom("unboxAsByte"), Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;)B")); } else if (parameters[i].isShortType()) { unboxMethod = MethodReference.findOrCreate( baseReflectionClass, Atom.findOrCreateUnicodeAtom("unboxAsShort"), Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;)S")); } else if (parameters[i].isCharType()) { unboxMethod = MethodReference.findOrCreate( baseReflectionClass, Atom.findOrCreateUnicodeAtom("unboxAsChar"), Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;)C")); } else if (parameters[i].isIntType()) { unboxMethod = MethodReference.findOrCreate( baseReflectionClass, Atom.findOrCreateUnicodeAtom("unboxAsInt"), Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;)I")); } else if (parameters[i].isLongType()) { unboxMethod = MethodReference.findOrCreate( baseReflectionClass, Atom.findOrCreateUnicodeAtom("unboxAsLong"), Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;)J")); } else if (parameters[i].isFloatType()) { unboxMethod = MethodReference.findOrCreate( baseReflectionClass, Atom.findOrCreateUnicodeAtom("unboxAsFloat"), Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;)F")); } else { if (VM.VerifyAssertions) VM._assert(parameters[i].isDoubleType()); unboxMethod = MethodReference.findOrCreate( baseReflectionClass, Atom.findOrCreateUnicodeAtom("unboxAsDouble"), Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;)D")); } constantPool[i + 1] = ClassFileReader.packCPEntry(CP_MEMBER, unboxMethod.getId()); bytecodes[curBC + 6] = (byte) ((i + 1) >>> 8); bytecodes[curBC + 7] = (byte) (i + 1); } curBC += 8; } if (isStatic()) { bytecodes[curBC] = (byte) JBC_invokestatic; } else if (isObjectInitializer() || isPrivate()) { bytecodes[curBC] = (byte) JBC_invokespecial; } else if (interfaceCall) { bytecodes[curBC] = (byte) JBC_invokeinterface; } else { bytecodes[curBC] = (byte) JBC_invokevirtual; } constantPool[numParams + 1] = ClassFileReader.packCPEntry(CP_MEMBER, getId()); bytecodes[curBC + 1] = (byte) ((numParams + 1) >>> 8); bytecodes[curBC + 2] = (byte) (numParams + 1); if (interfaceCall) { // invokeinterface bytecodes are historically longer than others curBC += 2; } TypeReference returnType = getReturnType(); if (!returnType.isPrimitiveType() || returnType.isWordLikeType()) { bytecodes[curBC + 3] = (byte) JBC_nop; bytecodes[curBC + 4] = (byte) JBC_nop; bytecodes[curBC + 5] = (byte) JBC_nop; } else if (returnType.isVoidType()) { bytecodes[curBC + 3] = (byte) JBC_aconst_null; bytecodes[curBC + 4] = (byte) JBC_nop; bytecodes[curBC + 5] = (byte) JBC_nop; } else { MemberReference boxMethod; if (returnType.isBooleanType()) { boxMethod = MethodReference.findOrCreate( baseReflectionClass, Atom.findOrCreateUnicodeAtom("boxAsBoolean"), Atom.findOrCreateUnicodeAtom("(Z)Ljava/lang/Object;")); } else if (returnType.isByteType()) { boxMethod = MethodReference.findOrCreate( baseReflectionClass, Atom.findOrCreateUnicodeAtom("boxAsByte"), Atom.findOrCreateUnicodeAtom("(B)Ljava/lang/Object;")); } else if (returnType.isShortType()) { boxMethod = MethodReference.findOrCreate( baseReflectionClass, Atom.findOrCreateUnicodeAtom("boxAsShort"), Atom.findOrCreateUnicodeAtom("(S)Ljava/lang/Object;")); } else if (returnType.isCharType()) { boxMethod = MethodReference.findOrCreate( baseReflectionClass, Atom.findOrCreateUnicodeAtom("boxAsChar"), Atom.findOrCreateUnicodeAtom("(C)Ljava/lang/Object;")); } else if (returnType.isIntType()) { boxMethod = MethodReference.findOrCreate( baseReflectionClass, Atom.findOrCreateUnicodeAtom("boxAsInt"), Atom.findOrCreateUnicodeAtom("(I)Ljava/lang/Object;")); } else if (returnType.isLongType()) { boxMethod = MethodReference.findOrCreate( baseReflectionClass, Atom.findOrCreateUnicodeAtom("boxAsLong"), Atom.findOrCreateUnicodeAtom("(J)Ljava/lang/Object;")); } else if (returnType.isFloatType()) { boxMethod = MethodReference.findOrCreate( baseReflectionClass, Atom.findOrCreateUnicodeAtom("boxAsFloat"), Atom.findOrCreateUnicodeAtom("(F)Ljava/lang/Object;")); } else { if (VM.VerifyAssertions) VM._assert(returnType.isDoubleType()); boxMethod = MethodReference.findOrCreate( baseReflectionClass, Atom.findOrCreateUnicodeAtom("boxAsDouble"), Atom.findOrCreateUnicodeAtom("(D)Ljava/lang/Object;")); } constantPool[numParams + 2] = ClassFileReader.packCPEntry(CP_MEMBER, boxMethod.getId()); bytecodes[curBC + 3] = (byte) JBC_invokestatic; bytecodes[curBC + 4] = (byte) ((numParams + 2) >>> 8); bytecodes[curBC + 5] = (byte) (numParams + 2); } bytecodes[curBC + 6] = (byte) JBC_areturn; return new NormalMethod( reflectionClass, memRef, (short) (ACC_PUBLIC | ACC_FINAL | ACC_SYNTHETIC), null, (short) 3, (short) (getParameterWords() + 2), bytecodes, null, null, null, constantPool, null, null, null, null); }
/** * Called from {@link ClassFileReader#readClass(TypeReference,DataInputStream)} to create an * instance of a RVMMethod by reading the relevant data from the argument bytecode stream. * * @param declaringClass the TypeReference of the class being loaded * @param constantPool the constantPool of the RVMClass object that's being constructed * @param memRef the canonical memberReference for this member. * @param modifiers modifiers associated with this member. * @param input the DataInputStream to read the method's attributes from */ static RVMMethod readMethod( TypeReference declaringClass, int[] constantPool, MemberReference memRef, short modifiers, DataInputStream input) throws IOException { short tmp_localWords = 0; short tmp_operandWords = 0; byte[] tmp_bytecodes = null; ExceptionHandlerMap tmp_exceptionHandlerMap = null; TypeReference[] tmp_exceptionTypes = null; int[] tmp_lineNumberMap = null; LocalVariableTable tmp_localVariableTable = null; Atom tmp_signature = null; RVMAnnotation[] annotations = null; RVMAnnotation[][] parameterAnnotations = null; Object tmp_annotationDefault = null; // Read the attributes for (int i = 0, n = input.readUnsignedShort(); i < n; i++) { Atom attName = ClassFileReader.getUtf(constantPool, input.readUnsignedShort()); int attLength = input.readInt(); // Only bother to interpret non-boring Method attributes if (attName == RVMClassLoader.codeAttributeName) { tmp_operandWords = input.readShort(); tmp_localWords = input.readShort(); tmp_bytecodes = new byte[input.readInt()]; input.readFully(tmp_bytecodes); tmp_exceptionHandlerMap = ExceptionHandlerMap.readExceptionHandlerMap(input, constantPool); // Read the attributes portion of the code attribute for (int j = 0, n2 = input.readUnsignedShort(); j < n2; j++) { attName = ClassFileReader.getUtf(constantPool, input.readUnsignedShort()); attLength = input.readInt(); if (attName == RVMClassLoader.lineNumberTableAttributeName) { int cnt = input.readUnsignedShort(); if (cnt != 0) { tmp_lineNumberMap = new int[cnt]; for (int k = 0; k < cnt; k++) { int startPC = input.readUnsignedShort(); int lineNumber = input.readUnsignedShort(); tmp_lineNumberMap[k] = (lineNumber << BITS_IN_SHORT) | startPC; } } } else if (attName == RVMClassLoader.localVariableTableAttributeName) { tmp_localVariableTable = LocalVariableTable.readLocalVariableTable(input, constantPool); } else { // All other entries in the attribute portion of the code attribute are boring. int skippedAmount = input.skipBytes(attLength); if (skippedAmount != attLength) { throw new IOException("Unexpected short skip"); } } } } else if (attName == RVMClassLoader.exceptionsAttributeName) { int cnt = input.readUnsignedShort(); if (cnt != 0) { tmp_exceptionTypes = new TypeReference[cnt]; for (int j = 0, m = tmp_exceptionTypes.length; j < m; ++j) { tmp_exceptionTypes[j] = ClassFileReader.getTypeRef(constantPool, input.readUnsignedShort()); } } } else if (attName == RVMClassLoader.syntheticAttributeName) { modifiers |= ACC_SYNTHETIC; } else if (attName == RVMClassLoader.signatureAttributeName) { tmp_signature = ClassFileReader.getUtf(constantPool, input.readUnsignedShort()); } else if (attName == RVMClassLoader.runtimeVisibleAnnotationsAttributeName) { annotations = AnnotatedElement.readAnnotations(constantPool, input, declaringClass.getClassLoader()); } else if (attName == RVMClassLoader.runtimeVisibleParameterAnnotationsAttributeName) { int numParameters = input.readByte() & 0xFF; parameterAnnotations = new RVMAnnotation[numParameters][]; for (int a = 0; a < numParameters; ++a) { parameterAnnotations[a] = AnnotatedElement.readAnnotations( constantPool, input, declaringClass.getClassLoader()); } } else if (attName == RVMClassLoader.annotationDefaultAttributeName) { try { tmp_annotationDefault = RVMAnnotation.readValue( memRef.asMethodReference().getReturnType(), constantPool, input, declaringClass.getClassLoader()); } catch (ClassNotFoundException e) { throw new Error(e); } } else { // all other method attributes are boring int skippedAmount = input.skipBytes(attLength); if (skippedAmount != attLength) { throw new IOException("Unexpected short skip"); } } } RVMMethod method; if ((modifiers & ACC_NATIVE) != 0) { method = new NativeMethod( declaringClass, memRef, modifiers, tmp_exceptionTypes, tmp_signature, annotations, parameterAnnotations, tmp_annotationDefault); } else if ((modifiers & ACC_ABSTRACT) != 0) { method = new AbstractMethod( declaringClass, memRef, modifiers, tmp_exceptionTypes, tmp_signature, annotations, parameterAnnotations, tmp_annotationDefault); } else { method = new NormalMethod( declaringClass, memRef, modifiers, tmp_exceptionTypes, tmp_localWords, tmp_operandWords, tmp_bytecodes, tmp_exceptionHandlerMap, tmp_lineNumberMap, tmp_localVariableTable, constantPool, tmp_signature, annotations, parameterAnnotations, tmp_annotationDefault); } return method; }