/** Get the code array that corresponds to the entry point (prologue) for the method. */ public final synchronized CodeArray getCurrentEntryCodeArray() { RVMClass declaringClass = getDeclaringClass(); if (VM.VerifyAssertions) VM._assert(declaringClass.isResolved()); if (isCompiled()) { return currentCompiledMethod.getEntryCodeArray(); } else if (!VM.writingBootImage || isNative()) { if (!isStatic() && !isObjectInitializer() && !isPrivate()) { // A non-private virtual method. if (declaringClass.isJavaLangObjectType() || declaringClass.getSuperClass().findVirtualMethod(getName(), getDescriptor()) == null) { // The root method of a virtual method family can use the lazy method invoker directly. return Entrypoints.lazyMethodInvokerMethod.getCurrentEntryCodeArray(); } else { // All other virtual methods in the family must use unique stubs to // ensure correct operation of the method test (guarded inlining of virtual calls). // It is TIBs job to marshall between the actual trampoline and this marker. return LazyCompilationTrampoline.instructions; } } else { // We'll never do a method test against this method. // Therefore we can use the lazy method invoker directly. return Entrypoints.lazyMethodInvokerMethod.getCurrentEntryCodeArray(); } } else { compile(); return currentCompiledMethod.getEntryCodeArray(); } }
/** Are two annotations equal? */ private boolean annotationEquals(Annotation a, Annotation b) { if (a == b) { return true; } else if (a.getClass() != b.getClass()) { return false; } else { RVMClass annotationInterface = type.resolve().asClass(); RVMMethod[] annotationMethods = annotationInterface.getDeclaredMethods(); AnnotationFactory afB = (AnnotationFactory) Proxy.getInvocationHandler(b); try { for (RVMMethod method : annotationMethods) { String name = method.getName().toUnicodeString(); Object objA = getElementValue(name, method.getReturnType().resolve().getClassForType()); Object objB = afB.getValue(name, method.getReturnType().resolve().getClassForType()); if (!objA.getClass().isArray()) { if (!objA.equals(objB)) { return false; } } else { if (!Arrays.equals((Object[]) objA, (Object[]) objB)) { return false; } } } } catch (java.io.UTFDataFormatException e) { throw new Error(e); } return true; } }
/** * Create an instance of this type of annotation with the values given in the members * * @return the created annotation */ private Annotation createValue() { // Find the annotation then find its implementing class final RVMClass annotationInterface = type.resolve().asClass(); annotationInterface.resolve(); Class<?> interfaceClass = annotationInterface.getClassForType(); ClassLoader classLoader = interfaceClass.getClassLoader(); if (classLoader == null) { classLoader = BootstrapClassLoader.getBootstrapClassLoader(); } return (Annotation) Proxy.newProxyInstance(classLoader, new Class[] {interfaceClass}, new AnnotationFactory()); }
/** Get an instance of an object capable of reflectively invoking this method */ @RuntimePure @SuppressWarnings("unchecked") public synchronized ReflectionBase getInvoker() { if (!VM.runningVM) { return null; } ReflectionBase invoker; if (invokeMethods != null) { synchronized (RVMMethod.class) { invoker = invokeMethods.get(this); } } else { invoker = null; } if (invoker == null) { Class<ReflectionBase> reflectionClass = (Class<ReflectionBase>) RVMClass.createReflectionClass(this); if (reflectionClass != null) { try { invoker = reflectionClass.newInstance(); } catch (Throwable e) { throw new Error(e); } } else { invoker = ReflectionBase.nullInvoker; } if (invokeMethods != null) { synchronized (RVMMethod.class) { invokeMethods.put(this, invoker); } } } return invoker; }
/** * Return a string representation of the annotation of the form "@type(name1=val1, ...nameN=valN)" */ public String toString() { RVMClass annotationInterface = type.resolve().asClass(); RVMMethod[] annotationMethods = annotationInterface.getDeclaredMethods(); String result = "@" + type.resolve().getClassForType().getName() + "("; try { for (int i = 0; i < annotationMethods.length; i++) { String name = annotationMethods[i].getName().toUnicodeString(); Object value = getElementValue(name, annotationMethods[i].getReturnType().resolve().getClassForType()); result += elementString(name, value); if (i < (annotationMethods.length - 1)) { result += ", "; } } } catch (java.io.UTFDataFormatException e) { throw new Error(e); } result += ")"; return result; }
/** Hash code for annotation value */ private int annotationHashCode() { RVMClass annotationInterface = type.resolve().asClass(); RVMMethod[] annotationMethods = annotationInterface.getDeclaredMethods(); String typeString = type.toString(); int result = typeString.substring(1, typeString.length() - 1).hashCode(); try { for (RVMMethod method : annotationMethods) { String name = method.getName().toUnicodeString(); Object value = getElementValue(name, method.getReturnType().resolve().getClassForType()); int part_result = name.hashCode() * 127; if (value.getClass().isArray()) { if (value instanceof Object[]) { part_result ^= Arrays.hashCode((Object[]) value); } else if (value instanceof boolean[]) { part_result ^= Arrays.hashCode((boolean[]) value); } else if (value instanceof byte[]) { part_result ^= Arrays.hashCode((byte[]) value); } else if (value instanceof char[]) { part_result ^= Arrays.hashCode((char[]) value); } else if (value instanceof short[]) { part_result ^= Arrays.hashCode((short[]) value); } else if (value instanceof int[]) { part_result ^= Arrays.hashCode((int[]) value); } else if (value instanceof long[]) { part_result ^= Arrays.hashCode((long[]) value); } else if (value instanceof float[]) { part_result ^= Arrays.hashCode((float[]) value); } else if (value instanceof double[]) { part_result ^= Arrays.hashCode((double[]) value); } } else { part_result ^= value.hashCode(); } result += part_result; } } catch (java.io.UTFDataFormatException e) { throw new Error(e); } return result; }
/** * 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); }
/** * Read an annotation attribute from the class file * * @param constantPool from constant pool being loaded * @param input the data being read */ static RVMAnnotation readAnnotation( int[] constantPool, DataInputStream input, ClassLoader classLoader) throws IOException, ClassNotFoundException { TypeReference type; // Read type int typeIndex = input.readUnsignedShort(); type = TypeReference.findOrCreate(classLoader, RVMClass.getUtf(constantPool, typeIndex)); // Read values int numAnnotationMembers = input.readUnsignedShort(); AnnotationMember[] elementValuePairs = new AnnotationMember[numAnnotationMembers]; for (int i = 0; i < numAnnotationMembers; i++) { elementValuePairs[i] = AnnotationMember.readAnnotationMember(type, constantPool, input, classLoader); } // Arrays.sort(elementValuePairs); RVMAnnotation result = new RVMAnnotation(type, elementValuePairs); RVMAnnotation unique = uniqueMap.get(result); if (unique != null) { return unique; } else { uniqueMap.put(result, result); return result; } }
private static <T> Object readValue( TypeReference type, int[] constantPool, DataInputStream input, ClassLoader classLoader, byte elementValue_tag) throws IOException, ClassNotFoundException { // decode Object value; switch (elementValue_tag) { case 'B': { if (VM.VerifyAssertions) VM._assert(type == null || type == TypeReference.Byte); Offset offset = RVMClass.getLiteralOffset(constantPool, input.readUnsignedShort()); value = (byte) Statics.getSlotContentsAsInt(offset); break; } case 'C': { if (VM.VerifyAssertions) VM._assert(type == null || type == TypeReference.Char); Offset offset = RVMClass.getLiteralOffset(constantPool, input.readUnsignedShort()); value = (char) Statics.getSlotContentsAsInt(offset); break; } case 'D': { if (VM.VerifyAssertions) VM._assert(type == null || type == TypeReference.Double); Offset offset = RVMClass.getLiteralOffset(constantPool, input.readUnsignedShort()); long longValue = Statics.getSlotContentsAsLong(offset); value = Double.longBitsToDouble(longValue); break; } case 'F': { if (VM.VerifyAssertions) VM._assert(type == null || type == TypeReference.Float); Offset offset = RVMClass.getLiteralOffset(constantPool, input.readUnsignedShort()); int intValue = Statics.getSlotContentsAsInt(offset); value = Float.intBitsToFloat(intValue); break; } case 'I': { if (VM.VerifyAssertions) VM._assert(type == null || type == TypeReference.Int); Offset offset = RVMClass.getLiteralOffset(constantPool, input.readUnsignedShort()); value = Statics.getSlotContentsAsInt(offset); break; } case 'J': { if (VM.VerifyAssertions) VM._assert(type == null || type == TypeReference.Long); Offset offset = RVMClass.getLiteralOffset(constantPool, input.readUnsignedShort()); value = Statics.getSlotContentsAsLong(offset); break; } case 'S': { if (VM.VerifyAssertions) VM._assert(type == null || type == TypeReference.Short); Offset offset = RVMClass.getLiteralOffset(constantPool, input.readUnsignedShort()); value = (short) Statics.getSlotContentsAsInt(offset); break; } case 'Z': { if (VM.VerifyAssertions) VM._assert(type == null || type == TypeReference.Boolean); Offset offset = RVMClass.getLiteralOffset(constantPool, input.readUnsignedShort()); value = Statics.getSlotContentsAsInt(offset) == 1; break; } case 's': { if (VM.VerifyAssertions) VM._assert(type == null || type == TypeReference.JavaLangString); value = RVMClass.getUtf(constantPool, input.readUnsignedShort()).toString(); break; } case 'e': { int typeNameIndex = input.readUnsignedShort(); @SuppressWarnings("unchecked") Class enumType = TypeReference.findOrCreate(classLoader, RVMClass.getUtf(constantPool, typeNameIndex)) .resolve() .getClassForType(); int constNameIndex = input.readUnsignedShort(); //noinspection unchecked value = Enum.valueOf(enumType, RVMClass.getUtf(constantPool, constNameIndex).toString()); break; } case 'c': { if (VM.VerifyAssertions) VM._assert(type == null || type == TypeReference.JavaLangClass); int classInfoIndex = input.readUnsignedShort(); // Value should be a class but resolving the class at this point could cause infinite // recursion in class loading TypeReference unresolvedValue = TypeReference.findOrCreate( classLoader, RVMClass.getUtf(constantPool, classInfoIndex)); if (unresolvedValue.peekType() != null) { value = unresolvedValue.peekType().getClassForType(); } else { value = unresolvedValue; } break; } case '@': value = RVMAnnotation.readAnnotation(constantPool, input, classLoader); break; case '[': { int numValues = input.readUnsignedShort(); if (numValues == 0) { if (type != null) { value = Array.newInstance(type.resolve().getClassForType(), 0); } else { value = new Object[0]; } } else { byte innerElementValue_tag = input.readByte(); TypeReference innerType = type == null ? null : type.getArrayElementType(); switch (innerElementValue_tag) { case 'B': { byte[] array = new byte[numValues]; array[0] = (Byte) readValue( innerType, constantPool, input, classLoader, innerElementValue_tag); for (int i = 1; i < numValues; i++) { array[i] = (Byte) readValue(innerType, constantPool, input, classLoader); } value = array; break; } case 'C': { char[] array = new char[numValues]; array[0] = (Character) readValue( innerType, constantPool, input, classLoader, innerElementValue_tag); for (int i = 1; i < numValues; i++) { array[i] = (Character) readValue(innerType, constantPool, input, classLoader); } value = array; break; } case 'D': { double[] array = new double[numValues]; array[0] = (Double) readValue( innerType, constantPool, input, classLoader, innerElementValue_tag); for (int i = 1; i < numValues; i++) { array[i] = (Double) readValue(innerType, constantPool, input, classLoader); } value = array; break; } case 'F': { float[] array = new float[numValues]; array[0] = (Float) readValue( innerType, constantPool, input, classLoader, innerElementValue_tag); for (int i = 1; i < numValues; i++) { array[i] = (Float) readValue(innerType, constantPool, input, classLoader); } value = array; break; } case 'I': { int[] array = new int[numValues]; array[0] = (Integer) readValue( innerType, constantPool, input, classLoader, innerElementValue_tag); for (int i = 1; i < numValues; i++) { array[i] = (Integer) readValue(innerType, constantPool, input, classLoader); } value = array; break; } case 'J': { long[] array = new long[numValues]; array[0] = (Long) readValue( innerType, constantPool, input, classLoader, innerElementValue_tag); for (int i = 1; i < numValues; i++) { array[i] = (Long) readValue(innerType, constantPool, input, classLoader); } value = array; break; } case 'S': { short[] array = new short[numValues]; array[0] = (Short) readValue( innerType, constantPool, input, classLoader, innerElementValue_tag); for (int i = 1; i < numValues; i++) { array[i] = (Short) readValue( innerType, constantPool, input, classLoader, innerElementValue_tag); } value = array; break; } case 'Z': { boolean[] array = new boolean[numValues]; array[0] = (Boolean) readValue( innerType, constantPool, input, classLoader, innerElementValue_tag); for (int i = 1; i < numValues; i++) { array[i] = (Boolean) readValue(innerType, constantPool, input, classLoader); } value = array; break; } case 's': case '@': case 'e': case '[': { Object value1 = readValue(innerType, constantPool, input, classLoader, innerElementValue_tag); value = Array.newInstance(value1.getClass(), numValues); Array.set(value, 0, value1); for (int i = 1; i < numValues; i++) { Array.set(value, i, readValue(innerType, constantPool, input, classLoader)); } break; } case 'c': { Object value1 = readValue(innerType, constantPool, input, classLoader, innerElementValue_tag); Object[] values = new Object[numValues]; values[0] = value1; boolean allClasses = value1 instanceof Class; for (int i = 1; i < numValues; i++) { values[i] = readValue(innerType, constantPool, input, classLoader); if (allClasses && !(values[i] instanceof Class)) { allClasses = false; } } if (allClasses == true) { Class<?>[] newValues = new Class[numValues]; for (int i = 0; i < numValues; i++) { newValues[i] = (Class<?>) values[i]; } value = newValues; } else { value = values; } break; } default: throw new ClassFormatError( "Unknown element_value tag '" + (char) innerElementValue_tag + "'"); } } break; } default: throw new ClassFormatError("Unknown element_value tag '" + (char) elementValue_tag + "'"); } return value; }