/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * 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/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.runtime; import org.jikesrvm.ArchitectureSpecific.VM_CodeArray; import org.jikesrvm.ArchitectureSpecific.VM_MachineReflection; import org.jikesrvm.VM; import org.jikesrvm.VM_Constants; import org.jikesrvm.classloader.VM_Class; import org.jikesrvm.classloader.VM_Method; import org.jikesrvm.classloader.VM_TypeReference; import org.jikesrvm.compilers.common.VM_CompiledMethod; import org.jikesrvm.scheduler.VM_Processor; import org.vmmagic.pragma.NoInline; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.WordArray; /** * Arch-independent portion of reflective method invoker. */ public class VM_Reflection implements VM_Constants { /** * 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() */ public static Object invoke(VM_Method method, Object thisArg, Object[] otherArgs) { return invoke(method, thisArg, otherArgs, false); } public static Object invoke(VM_Method method, Object thisArg, Object[] otherArgs, boolean isNonvirtual) { boolean forSubArch = VM_Magic.runningOnSubArch(); // the class must be initialized before we can invoke a method // VM_Class klass = method.getDeclaringClass(); if (!klass.isInitialized(forSubArch)) { VM_Runtime.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. // VM_TypeReference returnType = method.getReturnType(); boolean returnIsPrimitive = returnType.isPrimitiveType(); // decide how to pass parameters // int triple = VM_MachineReflection.countParameters(method); int gprs = triple & REFLECTION_GPRS_MASK; WordArray GPRs = WordArray.create(gprs); int fprs = (triple >> REFLECTION_GPRS_BITS) & 0x1F; double[] FPRs = new double[fprs]; byte[] FPRmeta = new byte[fprs]; int spillCount = triple >> (REFLECTION_GPRS_BITS + REFLECTION_FPRS_BITS); WordArray Spills = WordArray.create(spillCount); 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((long) 0)); unwrapFloat(wrapFloat((float) 0)); unwrapDouble(wrapDouble((double) 0)); firstUse = false; } // choose actual method to be called // VM_Method targetMethod; if (method.isStatic() || method.isObjectInitializer() || isNonvirtual) { targetMethod = method; } else { int tibIndex = method.getOffset().toInt() >>> LOG_BYTES_IN_ADDRESS; targetMethod = VM_Magic.getObjectType(thisArg).asClass().getVirtualMethods()[tibIndex - TIB_FIRST_VIRTUAL_METHOD_INDEX]; } // 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(forSubArch); VM_CompiledMethod cm = targetMethod.getCurrentCompiledMethod(forSubArch); while (cm == null) { targetMethod.compile(forSubArch); cm = targetMethod.getCurrentCompiledMethod(forSubArch); } VM_Processor.getCurrentProcessor().disableThreadSwitching("Packaging parameters for reflection"); VM_CodeArray code = (VM_CodeArray) cm.getEntryCodeArray(); VM_MachineReflection.packageParameters(method, thisArg, otherArgs, GPRs, FPRs, FPRmeta, Spills); // critical: no threadswitch/GCpoints between here and the invoke of code! // We may have references hidden in the GPRs and Spills arrays!!! VM_Processor.getCurrentProcessor().enableThreadSwitching(); if (!returnIsPrimitive) { return VM_Magic.invokeMethodReturningObject(code, GPRs, FPRs, FPRmeta, Spills); } if (returnType.isVoidType()) { VM_Magic.invokeMethodReturningVoid(code, GPRs, FPRs, FPRmeta, Spills); return null; } if (returnType.isBooleanType()) { int x = VM_Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills); return x == 1; } if (returnType.isByteType()) { int x = VM_Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills); return (byte) x; } if (returnType.isShortType()) { int x = VM_Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills); return (short) x; } if (returnType.isCharType()) { int x = VM_Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills); return (char) x; } if (returnType.isIntType()) { return VM_Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills); } if (returnType.isLongType()) { return VM_Magic.invokeMethodReturningLong(code, GPRs, FPRs, FPRmeta, Spills); } if (returnType.isFloatType()) { return VM_Magic.invokeMethodReturningFloat(code, GPRs, FPRs, FPRmeta, Spills); } if (returnType.isDoubleType()) { return VM_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 VM_Magic.objectAsAddress(o); } private static boolean firstUse = true; }