001/* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013package org.jikesrvm.runtime; 014 015import static org.jikesrvm.Configuration.BuildForSSE2Full; 016import static org.jikesrvm.VM.NOT_REACHED; 017import static org.jikesrvm.objectmodel.TIBLayoutConstants.TIB_FIRST_VIRTUAL_METHOD_INDEX; 018import static org.jikesrvm.runtime.UnboxedSizeConstants.LOG_BYTES_IN_ADDRESS; 019 020import org.jikesrvm.VM; 021import org.jikesrvm.classloader.RVMClass; 022import org.jikesrvm.classloader.RVMMethod; 023import org.jikesrvm.classloader.TypeReference; 024import org.jikesrvm.compilers.common.CodeArray; 025import org.jikesrvm.compilers.common.CompiledMethod; 026import org.jikesrvm.scheduler.RVMThread; 027import org.vmmagic.pragma.Inline; 028import org.vmmagic.pragma.NoInline; 029import org.vmmagic.unboxed.Address; 030import org.vmmagic.unboxed.WordArray; 031 032/** 033 * Arch-independent portion of reflective method invoker. 034 */ 035public class Reflection { 036 037 /** Perform reflection using bytecodes (true) or out-of-line machine code (false) */ 038 public static boolean bytecodeReflection = false; 039 /** 040 * Cache the reflective method invoker in JavaLangReflect? If this is true and 041 * bytecodeReflection is false, then bytecode reflection will only be used for 042 * java.lang.reflect objects. 043 */ 044 public static boolean cacheInvokerInJavaLangReflect = true; 045 /* 046 * Reflection uses an integer return from a function which logically 047 * returns a triple. The values are packed in the integer return value 048 * by the following masks. 049 */ 050 public static final int REFLECTION_GPRS_BITS = 5; 051 public static final int REFLECTION_GPRS_MASK = (1 << REFLECTION_GPRS_BITS) - 1; 052 public static final int REFLECTION_FPRS_BITS = 5; 053 public static final int REFLECTION_FPRS_MASK = (1 << REFLECTION_FPRS_BITS) - 1; 054 055 /** 056 * Does the reflective method scheme need to check the arguments are valid? 057 * Bytecode reflection doesn't need arguments checking as they are checking as 058 * they are unwrapped 059 * 060 * @param invoker the invoker to use for the reflective invokation 061 * @return whether the reflective method scheme needs to to be check 062 * the arguments for validity 063 */ 064 @Inline 065 public static boolean needsCheckArgs(ReflectionBase invoker) { 066 // Only need to check the arguments when the user may be packaging them and 067 // not using the bytecode based invoker (that checks them when they are unpacked) 068 return !bytecodeReflection && !cacheInvokerInJavaLangReflect; 069 } 070 /** 071 * Call a method. 072 * @param method method to be called 073 * @param invoker the invoker to use for the invocation, may be {@code null} in 074 * certain cases 075 * @param thisArg "this" argument (ignored if method is static) 076 * @param otherArgs remaining arguments 077 * @param isNonvirtual flag is {@code false} if the method of the real class of this 078 * object is to be invoked; {@code true} if a method of a superclass may be invoked 079 * @return return value (wrapped if primitive) 080 * See also: java/lang/reflect/Method.invoke() 081 */ 082 @Inline 083 public static Object invoke(RVMMethod method, ReflectionBase invoker, 084 Object thisArg, Object[] otherArgs, 085 boolean isNonvirtual) { 086 // NB bytecode reflection doesn't care about isNonvirtual 087 if (!bytecodeReflection && !cacheInvokerInJavaLangReflect) { 088 return outOfLineInvoke(method, thisArg, otherArgs, isNonvirtual); 089 } else if (!bytecodeReflection && cacheInvokerInJavaLangReflect) { 090 if (invoker != null) { 091 return invoker.invoke(method, thisArg, otherArgs); 092 } else { 093 return outOfLineInvoke(method, thisArg, otherArgs, isNonvirtual); 094 } 095 } else if (bytecodeReflection && !cacheInvokerInJavaLangReflect) { 096 if (VM.VerifyAssertions) VM._assert(invoker == null); 097 return method.getInvoker().invoke(method, thisArg, otherArgs); 098 } else { 099 // Even if we always generate an invoker this test is still necessary for 100 // invokers that should have been created in the boot image 101 if (invoker != null) { 102 return invoker.invoke(method, thisArg, otherArgs); 103 } else { 104 return method.getInvoker().invoke(method, thisArg, otherArgs); 105 } 106 } 107 } 108 109 private static final WordArray emptyWordArray = WordArray.create(0); 110 private static final double[] emptyDoubleArray = new double[0]; 111 private static final byte[] emptyByteArray = new byte[0]; 112 113 private static Object outOfLineInvoke(RVMMethod method, Object thisArg, Object[] otherArgs, boolean isNonvirtual) { 114 115 // the class must be initialized before we can invoke a method 116 // 117 RVMClass klass = method.getDeclaringClass(); 118 if (!klass.isInitialized()) { 119 RuntimeEntrypoints.initializeClassForDynamicLink(klass); 120 } 121 122 // remember return type 123 // Determine primitive type-ness early to avoid call (possible yield) 124 // later while refs are possibly being held in int arrays. 125 // 126 TypeReference returnType = method.getReturnType(); 127 boolean returnIsPrimitive = returnType.isPrimitiveType(); 128 129 // decide how to pass parameters 130 // 131 int triple = 0; 132 if (VM.BuildForIA32) { 133 triple = org.jikesrvm.ia32.MachineReflection.countParameters(method); 134 } else { 135 if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC); 136 triple = org.jikesrvm.ppc.MachineReflection.countParameters(method); 137 } 138 int gprs = triple & REFLECTION_GPRS_MASK; 139 WordArray GPRs = (gprs > 0) ? WordArray.create(gprs) : emptyWordArray; 140 int fprs = (triple >> REFLECTION_GPRS_BITS) & 0x1F; 141 double[] FPRs = (fprs > 0) ? new double[fprs] : emptyDoubleArray; 142 byte[] FPRmeta; 143 if (BuildForSSE2Full) { 144 FPRmeta = (fprs > 0) ? new byte[fprs] : emptyByteArray; 145 } else { 146 FPRmeta = null; 147 } 148 149 int spillCount = triple >> (REFLECTION_GPRS_BITS + REFLECTION_FPRS_BITS); 150 151 WordArray Spills = (spillCount > 0) ? WordArray.create(spillCount) : emptyWordArray; 152 153 if (firstUse) { 154 // force dynamic link sites in unwrappers to get resolved, 155 // before disabling gc. 156 // this is a bit silly, but I can't think of another way to do it [--DL] 157 unwrapBoolean(wrapBoolean(0)); 158 unwrapByte(wrapByte((byte) 0)); 159 unwrapChar(wrapChar((char) 0)); 160 unwrapShort(wrapShort((short) 0)); 161 unwrapInt(wrapInt(0)); 162 unwrapLong(wrapLong(0)); 163 unwrapFloat(wrapFloat(0)); 164 unwrapDouble(wrapDouble(0)); 165 firstUse = false; 166 } 167 168 // choose actual method to be called 169 // 170 RVMMethod targetMethod; 171 if (isNonvirtual || method.isStatic() || method.isObjectInitializer()) { 172 targetMethod = method; 173 } else { 174 RVMClass C = Magic.getObjectType(thisArg).asClass(); 175 if (!method.getDeclaringClass().isInterface()) { 176 int tibIndex = method.getOffset().toInt() >>> LOG_BYTES_IN_ADDRESS; 177 targetMethod = C.getVirtualMethods()[tibIndex - TIB_FIRST_VIRTUAL_METHOD_INDEX]; 178 } else { 179 RVMClass I = method.getDeclaringClass(); 180 if (!RuntimeEntrypoints.isAssignableWith(I, C)) 181 throw new IncompatibleClassChangeError(); 182 targetMethod = C.findVirtualMethod(method.getName(), method.getDescriptor()); 183 if (targetMethod == null) 184 throw new IncompatibleClassChangeError(); 185 } 186 } 187 188 // getCurrentCompiledMethod is synchronized but Unpreemptible. 189 // Therefore there are no possible yieldpoints from the time 190 // the compiledMethod is loaded in getCurrentCompiledMethod 191 // to when we disable GC below. 192 // We can't allow any yieldpoints between these points because of the way in which 193 // we GC compiled code. Once a method is marked as obsolete, if it is not 194 // executing on the stack of some thread, then the process of collecting the 195 // code and meta-data might be initiated. 196 targetMethod.compile(); 197 CompiledMethod cm = targetMethod.getCurrentCompiledMethod(); 198 while (cm == null) { 199 targetMethod.compile(); 200 cm = targetMethod.getCurrentCompiledMethod(); 201 } 202 203 RVMThread.getCurrentThread().disableYieldpoints(); 204 205 CodeArray code = cm.getEntryCodeArray(); 206 if (VM.BuildForIA32) { 207 org.jikesrvm.ia32.MachineReflection.packageParameters(method, thisArg, otherArgs, GPRs, FPRs, FPRmeta, Spills); 208 } else { 209 if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC); 210 org.jikesrvm.ppc.MachineReflection.packageParameters(method, thisArg, otherArgs, GPRs, FPRs, FPRmeta, Spills); 211 } 212 213 // critical: no yieldpoints/GCpoints between here and the invoke of code! 214 // We may have references hidden in the GPRs and Spills arrays!!! 215 RVMThread.getCurrentThread().enableYieldpoints(); 216 217 if (!returnIsPrimitive) { 218 return Magic.invokeMethodReturningObject(code, GPRs, FPRs, FPRmeta, Spills); 219 } 220 221 if (returnType.isVoidType()) { 222 Magic.invokeMethodReturningVoid(code, GPRs, FPRs, FPRmeta, Spills); 223 return null; 224 } 225 226 if (returnType.isBooleanType()) { 227 int x = Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills); 228 return x == 1; 229 } 230 231 if (returnType.isByteType()) { 232 int x = Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills); 233 return (byte) x; 234 } 235 236 if (returnType.isShortType()) { 237 int x = Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills); 238 return (short) x; 239 } 240 241 if (returnType.isCharType()) { 242 int x = Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills); 243 return (char) x; 244 } 245 246 if (returnType.isIntType()) { 247 return Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills); 248 } 249 250 if (returnType.isLongType()) { 251 return Magic.invokeMethodReturningLong(code, GPRs, FPRs, FPRmeta, Spills); 252 } 253 254 if (returnType.isFloatType()) { 255 return Magic.invokeMethodReturningFloat(code, GPRs, FPRs, FPRmeta, Spills); 256 } 257 258 if (returnType.isDoubleType()) { 259 return Magic.invokeMethodReturningDouble(code, GPRs, FPRs, FPRmeta, Spills); 260 } 261 262 if (VM.VerifyAssertions) VM._assert(NOT_REACHED); 263 return null; 264 } 265 266 // Method parameter wrappers. 267 // 268 @NoInline 269 public static Object wrapBoolean(int b) { 270 return b == 1; 271 } 272 273 @NoInline 274 public static Object wrapByte(byte b) { 275 return b; 276 } 277 278 @NoInline 279 public static Object wrapChar(char c) { 280 return c; 281 } 282 283 @NoInline 284 public static Object wrapShort(short s) { 285 return s; 286 } 287 288 @NoInline 289 public static Object wrapInt(int i) { 290 return i; 291 } 292 293 @NoInline 294 public static Object wrapLong(long l) { 295 return l; 296 } 297 298 @NoInline 299 public static Object wrapFloat(float f) { 300 return f; 301 } 302 303 @NoInline 304 public static Object wrapDouble(double d) { 305 return d; 306 } 307 308 // Method parameter unwrappers. 309 // 310 @NoInline 311 public static int unwrapBooleanAsInt(Object o) { 312 if (unwrapBoolean(o)) { 313 return 1; 314 } else { 315 return 0; 316 } 317 } 318 319 @NoInline 320 public static boolean unwrapBoolean(Object o) { 321 return (Boolean) o; 322 } 323 324 @NoInline 325 public static byte unwrapByte(Object o) { 326 return (Byte) o; 327 } 328 329 @NoInline 330 public static char unwrapChar(Object o) { 331 return (Character) o; 332 } 333 334 @NoInline 335 public static short unwrapShort(Object o) { 336 return (Short) o; 337 } 338 339 @NoInline 340 public static int unwrapInt(Object o) { 341 return (Integer) o; 342 } 343 344 @NoInline 345 public static long unwrapLong(Object o) { 346 return (Long) o; 347 } 348 349 @NoInline 350 public static float unwrapFloat(Object o) { 351 return (Float) o; 352 } 353 354 @NoInline 355 public static double unwrapDouble(Object o) { 356 return (Double) o; 357 } 358 359 @NoInline 360 public static Address unwrapObject(Object o) { 361 return Magic.objectAsAddress(o); 362 } 363 364 private static boolean firstUse = true; 365}