/jikesrvm/rvm/src/org/jikesrvm/runtime/Reflection.java
Java | 303 lines | 188 code | 46 blank | 69 comment | 48 complexity | d2237d2cb734b6596c2a84c315f484d0 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0, BSD-3-Clause
- /*
- * This file is part of the Jikes RVM project (http://jikesrvm.org).
- *
- * This file is licensed to You under the Eclipse Public License (EPL);
- * You may not use this file except in compliance with the License. You
- * may obtain a copy of the License at
- *
- * http://www.opensource.org/licenses/eclipse-1.0.php
- *
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership.
- */
- package org.jikesrvm.runtime;
- import org.jikesrvm.ArchitectureSpecific.CodeArray;
- import org.jikesrvm.ArchitectureSpecific.MachineReflection;
- import org.jikesrvm.VM;
- import org.jikesrvm.Constants;
- import org.jikesrvm.classloader.RVMClass;
- import org.jikesrvm.classloader.RVMMethod;
- import org.jikesrvm.classloader.TypeReference;
- import org.jikesrvm.compilers.common.CompiledMethod;
- import org.jikesrvm.scheduler.RVMThread;
- import org.vmmagic.pragma.Inline;
- import org.vmmagic.pragma.NoInline;
- import org.vmmagic.unboxed.Address;
- import org.vmmagic.unboxed.WordArray;
- import static org.jikesrvm.Configuration.BuildForSSE2Full;
- /**
- * Arch-independent portion of reflective method invoker.
- */
- public class Reflection implements Constants {
- /** Perform reflection using bytecodes (true) or out-of-line machine code (false) */
- public static boolean bytecodeReflection = false;
- /**
- * Cache the reflective method invoker in JavaLangReflect? If this is true and
- * bytecodeReflection is false, then bytecode reflection will only be used for
- * java.lang.reflect objects.
- */
- public static boolean cacheInvokerInJavaLangReflect = true;
- /**
- * Does the reflective method scheme need to check the arguments are valid?
- * Bytecode reflection doesn't need arguments checking as they are checking as
- * they are unwrapped
- */
- @Inline
- public static boolean needsCheckArgs(ReflectionBase invoker) {
- // Only need to check the arguments when the user may be packaging them and
- // not using the bytecode based invoker (that checks them when they are unpacked)
- return !bytecodeReflection && !cacheInvokerInJavaLangReflect;
- }
- /**
- * Call a method.
- * @param method method to be called
- * @param thisArg "this" argument (ignored if method is static)
- * @param otherArgs remaining arguments
- *
- * isNonvirtual flag is false if the method of the real class of this
- * object is to be invoked; true if a method of a superclass may be invoked
- * @return return value (wrapped if primitive)
- * See also: java/lang/reflect/Method.invoke()
- */
- @Inline
- public static Object invoke(RVMMethod method, ReflectionBase invoker,
- Object thisArg, Object[] otherArgs,
- boolean isNonvirtual) {
- // NB bytecode reflection doesn't care about isNonvirtual
- if (!bytecodeReflection && !cacheInvokerInJavaLangReflect) {
- return outOfLineInvoke(method, thisArg, otherArgs, isNonvirtual);
- } else if (!bytecodeReflection && cacheInvokerInJavaLangReflect) {
- if (invoker != null) {
- return invoker.invoke(method, thisArg, otherArgs);
- } else {
- return outOfLineInvoke(method, thisArg, otherArgs, isNonvirtual);
- }
- } else if (bytecodeReflection && !cacheInvokerInJavaLangReflect) {
- if (VM.VerifyAssertions) VM._assert(invoker == null);
- return method.getInvoker().invoke(method, thisArg, otherArgs);
- } else {
- // Even if we always generate an invoker this test is still necessary for
- // invokers that should have been created in the boot image
- if (invoker != null) {
- return invoker.invoke(method, thisArg, otherArgs);
- } else {
- return method.getInvoker().invoke(method, thisArg, otherArgs);
- }
- }
- }
- private static final WordArray emptyWordArray = WordArray.create(0);
- private static final double[] emptyDoubleArray = new double[0];
- private static final byte[] emptyByteArray = new byte[0];
- private static Object outOfLineInvoke(RVMMethod method, Object thisArg, Object[] otherArgs, boolean isNonvirtual) {
- // the class must be initialized before we can invoke a method
- //
- RVMClass klass = method.getDeclaringClass();
- if (!klass.isInitialized()) {
- RuntimeEntrypoints.initializeClassForDynamicLink(klass);
- }
- // remember return type
- // Determine primitive type-ness early to avoid call (possible yield)
- // later while refs are possibly being held in int arrays.
- //
- TypeReference returnType = method.getReturnType();
- boolean returnIsPrimitive = returnType.isPrimitiveType();
- // decide how to pass parameters
- //
- int triple = MachineReflection.countParameters(method);
- int gprs = triple & REFLECTION_GPRS_MASK;
- WordArray GPRs = (gprs > 0) ? WordArray.create(gprs) : emptyWordArray;
- int fprs = (triple >> REFLECTION_GPRS_BITS) & 0x1F;
- double[] FPRs = (fprs > 0) ? new double[fprs] : emptyDoubleArray;
- byte[] FPRmeta;
- if (BuildForSSE2Full) {
- FPRmeta = (fprs > 0) ? new byte[fprs] : emptyByteArray;
- } else {
- FPRmeta = null;
- }
- int spillCount = triple >> (REFLECTION_GPRS_BITS + REFLECTION_FPRS_BITS);
- WordArray Spills = (spillCount > 0) ? WordArray.create(spillCount) : emptyWordArray;
- if (firstUse) {
- // force dynamic link sites in unwrappers to get resolved,
- // before disabling gc.
- // this is a bit silly, but I can't think of another way to do it [--DL]
- unwrapBoolean(wrapBoolean(0));
- unwrapByte(wrapByte((byte) 0));
- unwrapChar(wrapChar((char) 0));
- unwrapShort(wrapShort((short) 0));
- unwrapInt(wrapInt(0));
- unwrapLong(wrapLong(0));
- unwrapFloat(wrapFloat(0));
- unwrapDouble(wrapDouble(0));
- firstUse = false;
- }
- // choose actual method to be called
- //
- RVMMethod targetMethod;
- if (isNonvirtual || method.isStatic() || method.isObjectInitializer()) {
- targetMethod = method;
- } else {
- RVMClass C = Magic.getObjectType(thisArg).asClass();
- if (!method.getDeclaringClass().isInterface()) {
- int tibIndex = method.getOffset().toInt() >>> LOG_BYTES_IN_ADDRESS;
- targetMethod = C.getVirtualMethods()[tibIndex - TIB_FIRST_VIRTUAL_METHOD_INDEX];
- } else {
- RVMClass I = method.getDeclaringClass();
- if (!RuntimeEntrypoints.isAssignableWith(I, C))
- throw new IncompatibleClassChangeError();
- targetMethod = C.findVirtualMethod(method.getName(), method.getDescriptor());
- if (targetMethod == null)
- throw new IncompatibleClassChangeError();
- }
- }
- // getCurrentCompiledMethod is synchronized but Unpreemptible.
- // Therefore there are no possible yieldpoints from the time
- // the compiledMethod is loaded in getCurrentCompiledMethod
- // to when we disable GC below.
- // We can't allow any yieldpoints between these points because of the way in which
- // we GC compiled code. Once a method is marked as obsolete, if it is not
- // executing on the stack of some thread, then the process of collecting the
- // code and meta-data might be initiated.
- targetMethod.compile();
- CompiledMethod cm = targetMethod.getCurrentCompiledMethod();
- while (cm == null) {
- targetMethod.compile();
- cm = targetMethod.getCurrentCompiledMethod();
- }
- RVMThread.getCurrentThread().disableYieldpoints();
- CodeArray code = cm.getEntryCodeArray();
- MachineReflection.packageParameters(method, thisArg, otherArgs, GPRs, FPRs, FPRmeta, Spills);
- // critical: no yieldpoints/GCpoints between here and the invoke of code!
- // We may have references hidden in the GPRs and Spills arrays!!!
- RVMThread.getCurrentThread().enableYieldpoints();
- if (!returnIsPrimitive) {
- return Magic.invokeMethodReturningObject(code, GPRs, FPRs, FPRmeta, Spills);
- }
- if (returnType.isVoidType()) {
- Magic.invokeMethodReturningVoid(code, GPRs, FPRs, FPRmeta, Spills);
- return null;
- }
- if (returnType.isBooleanType()) {
- int x = Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills);
- return x == 1;
- }
- if (returnType.isByteType()) {
- int x = Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills);
- return (byte) x;
- }
- if (returnType.isShortType()) {
- int x = Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills);
- return (short) x;
- }
- if (returnType.isCharType()) {
- int x = Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills);
- return (char) x;
- }
- if (returnType.isIntType()) {
- return Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills);
- }
- if (returnType.isLongType()) {
- return Magic.invokeMethodReturningLong(code, GPRs, FPRs, FPRmeta, Spills);
- }
- if (returnType.isFloatType()) {
- return Magic.invokeMethodReturningFloat(code, GPRs, FPRs, FPRmeta, Spills);
- }
- if (returnType.isDoubleType()) {
- return Magic.invokeMethodReturningDouble(code, GPRs, FPRs, FPRmeta, Spills);
- }
- if (VM.VerifyAssertions) VM._assert(NOT_REACHED);
- return null;
- }
- // Method parameter wrappers.
- //
- @NoInline
- public static Object wrapBoolean(int b) { return b == 1; }
- @NoInline
- public static Object wrapByte(byte b) { return b; }
- @NoInline
- public static Object wrapChar(char c) { return c; }
- @NoInline
- public static Object wrapShort(short s) { return s; }
- @NoInline
- public static Object wrapInt(int i) { return i; }
- @NoInline
- public static Object wrapLong(long l) { return l; }
- @NoInline
- public static Object wrapFloat(float f) { return f; }
- @NoInline
- public static Object wrapDouble(double d) { return d; }
- // Method parameter unwrappers.
- //
- @NoInline
- public static int unwrapBooleanAsInt(Object o) {
- if (unwrapBoolean(o)) {
- return 1;
- } else {
- return 0;
- }
- }
- @NoInline
- public static boolean unwrapBoolean(Object o) { return (Boolean) o; }
- @NoInline
- public static byte unwrapByte(Object o) { return (Byte) o; }
- @NoInline
- public static char unwrapChar(Object o) { return (Character) o; }
- @NoInline
- public static short unwrapShort(Object o) { return (Short) o; }
- @NoInline
- public static int unwrapInt(Object o) { return (Integer) o; }
- @NoInline
- public static long unwrapLong(Object o) { return (Long) o; }
- @NoInline
- public static float unwrapFloat(Object o) { return (Float) o; }
- @NoInline
- public static double unwrapDouble(Object o) { return (Double) o; }
- @NoInline
- public static Address unwrapObject(Object o) { return Magic.objectAsAddress(o); }
- private static boolean firstUse = true;
- }