PageRenderTime 53ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/jikesrvm/rvm/src/org/jikesrvm/runtime/Reflection.java

https://github.com/midlorollin/cs398
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
  1. /*
  2. * This file is part of the Jikes RVM project (http://jikesrvm.org).
  3. *
  4. * This file is licensed to You under the Eclipse Public License (EPL);
  5. * You may not use this file except in compliance with the License. You
  6. * may obtain a copy of the License at
  7. *
  8. * http://www.opensource.org/licenses/eclipse-1.0.php
  9. *
  10. * See the COPYRIGHT.txt file distributed with this work for information
  11. * regarding copyright ownership.
  12. */
  13. package org.jikesrvm.runtime;
  14. import org.jikesrvm.ArchitectureSpecific.CodeArray;
  15. import org.jikesrvm.ArchitectureSpecific.MachineReflection;
  16. import org.jikesrvm.VM;
  17. import org.jikesrvm.Constants;
  18. import org.jikesrvm.classloader.RVMClass;
  19. import org.jikesrvm.classloader.RVMMethod;
  20. import org.jikesrvm.classloader.TypeReference;
  21. import org.jikesrvm.compilers.common.CompiledMethod;
  22. import org.jikesrvm.scheduler.RVMThread;
  23. import org.vmmagic.pragma.Inline;
  24. import org.vmmagic.pragma.NoInline;
  25. import org.vmmagic.unboxed.Address;
  26. import org.vmmagic.unboxed.WordArray;
  27. import static org.jikesrvm.Configuration.BuildForSSE2Full;
  28. /**
  29. * Arch-independent portion of reflective method invoker.
  30. */
  31. public class Reflection implements Constants {
  32. /** Perform reflection using bytecodes (true) or out-of-line machine code (false) */
  33. public static boolean bytecodeReflection = false;
  34. /**
  35. * Cache the reflective method invoker in JavaLangReflect? If this is true and
  36. * bytecodeReflection is false, then bytecode reflection will only be used for
  37. * java.lang.reflect objects.
  38. */
  39. public static boolean cacheInvokerInJavaLangReflect = true;
  40. /**
  41. * Does the reflective method scheme need to check the arguments are valid?
  42. * Bytecode reflection doesn't need arguments checking as they are checking as
  43. * they are unwrapped
  44. */
  45. @Inline
  46. public static boolean needsCheckArgs(ReflectionBase invoker) {
  47. // Only need to check the arguments when the user may be packaging them and
  48. // not using the bytecode based invoker (that checks them when they are unpacked)
  49. return !bytecodeReflection && !cacheInvokerInJavaLangReflect;
  50. }
  51. /**
  52. * Call a method.
  53. * @param method method to be called
  54. * @param thisArg "this" argument (ignored if method is static)
  55. * @param otherArgs remaining arguments
  56. *
  57. * isNonvirtual flag is false if the method of the real class of this
  58. * object is to be invoked; true if a method of a superclass may be invoked
  59. * @return return value (wrapped if primitive)
  60. * See also: java/lang/reflect/Method.invoke()
  61. */
  62. @Inline
  63. public static Object invoke(RVMMethod method, ReflectionBase invoker,
  64. Object thisArg, Object[] otherArgs,
  65. boolean isNonvirtual) {
  66. // NB bytecode reflection doesn't care about isNonvirtual
  67. if (!bytecodeReflection && !cacheInvokerInJavaLangReflect) {
  68. return outOfLineInvoke(method, thisArg, otherArgs, isNonvirtual);
  69. } else if (!bytecodeReflection && cacheInvokerInJavaLangReflect) {
  70. if (invoker != null) {
  71. return invoker.invoke(method, thisArg, otherArgs);
  72. } else {
  73. return outOfLineInvoke(method, thisArg, otherArgs, isNonvirtual);
  74. }
  75. } else if (bytecodeReflection && !cacheInvokerInJavaLangReflect) {
  76. if (VM.VerifyAssertions) VM._assert(invoker == null);
  77. return method.getInvoker().invoke(method, thisArg, otherArgs);
  78. } else {
  79. // Even if we always generate an invoker this test is still necessary for
  80. // invokers that should have been created in the boot image
  81. if (invoker != null) {
  82. return invoker.invoke(method, thisArg, otherArgs);
  83. } else {
  84. return method.getInvoker().invoke(method, thisArg, otherArgs);
  85. }
  86. }
  87. }
  88. private static final WordArray emptyWordArray = WordArray.create(0);
  89. private static final double[] emptyDoubleArray = new double[0];
  90. private static final byte[] emptyByteArray = new byte[0];
  91. private static Object outOfLineInvoke(RVMMethod method, Object thisArg, Object[] otherArgs, boolean isNonvirtual) {
  92. // the class must be initialized before we can invoke a method
  93. //
  94. RVMClass klass = method.getDeclaringClass();
  95. if (!klass.isInitialized()) {
  96. RuntimeEntrypoints.initializeClassForDynamicLink(klass);
  97. }
  98. // remember return type
  99. // Determine primitive type-ness early to avoid call (possible yield)
  100. // later while refs are possibly being held in int arrays.
  101. //
  102. TypeReference returnType = method.getReturnType();
  103. boolean returnIsPrimitive = returnType.isPrimitiveType();
  104. // decide how to pass parameters
  105. //
  106. int triple = MachineReflection.countParameters(method);
  107. int gprs = triple & REFLECTION_GPRS_MASK;
  108. WordArray GPRs = (gprs > 0) ? WordArray.create(gprs) : emptyWordArray;
  109. int fprs = (triple >> REFLECTION_GPRS_BITS) & 0x1F;
  110. double[] FPRs = (fprs > 0) ? new double[fprs] : emptyDoubleArray;
  111. byte[] FPRmeta;
  112. if (BuildForSSE2Full) {
  113. FPRmeta = (fprs > 0) ? new byte[fprs] : emptyByteArray;
  114. } else {
  115. FPRmeta = null;
  116. }
  117. int spillCount = triple >> (REFLECTION_GPRS_BITS + REFLECTION_FPRS_BITS);
  118. WordArray Spills = (spillCount > 0) ? WordArray.create(spillCount) : emptyWordArray;
  119. if (firstUse) {
  120. // force dynamic link sites in unwrappers to get resolved,
  121. // before disabling gc.
  122. // this is a bit silly, but I can't think of another way to do it [--DL]
  123. unwrapBoolean(wrapBoolean(0));
  124. unwrapByte(wrapByte((byte) 0));
  125. unwrapChar(wrapChar((char) 0));
  126. unwrapShort(wrapShort((short) 0));
  127. unwrapInt(wrapInt(0));
  128. unwrapLong(wrapLong(0));
  129. unwrapFloat(wrapFloat(0));
  130. unwrapDouble(wrapDouble(0));
  131. firstUse = false;
  132. }
  133. // choose actual method to be called
  134. //
  135. RVMMethod targetMethod;
  136. if (isNonvirtual || method.isStatic() || method.isObjectInitializer()) {
  137. targetMethod = method;
  138. } else {
  139. RVMClass C = Magic.getObjectType(thisArg).asClass();
  140. if (!method.getDeclaringClass().isInterface()) {
  141. int tibIndex = method.getOffset().toInt() >>> LOG_BYTES_IN_ADDRESS;
  142. targetMethod = C.getVirtualMethods()[tibIndex - TIB_FIRST_VIRTUAL_METHOD_INDEX];
  143. } else {
  144. RVMClass I = method.getDeclaringClass();
  145. if (!RuntimeEntrypoints.isAssignableWith(I, C))
  146. throw new IncompatibleClassChangeError();
  147. targetMethod = C.findVirtualMethod(method.getName(), method.getDescriptor());
  148. if (targetMethod == null)
  149. throw new IncompatibleClassChangeError();
  150. }
  151. }
  152. // getCurrentCompiledMethod is synchronized but Unpreemptible.
  153. // Therefore there are no possible yieldpoints from the time
  154. // the compiledMethod is loaded in getCurrentCompiledMethod
  155. // to when we disable GC below.
  156. // We can't allow any yieldpoints between these points because of the way in which
  157. // we GC compiled code. Once a method is marked as obsolete, if it is not
  158. // executing on the stack of some thread, then the process of collecting the
  159. // code and meta-data might be initiated.
  160. targetMethod.compile();
  161. CompiledMethod cm = targetMethod.getCurrentCompiledMethod();
  162. while (cm == null) {
  163. targetMethod.compile();
  164. cm = targetMethod.getCurrentCompiledMethod();
  165. }
  166. RVMThread.getCurrentThread().disableYieldpoints();
  167. CodeArray code = cm.getEntryCodeArray();
  168. MachineReflection.packageParameters(method, thisArg, otherArgs, GPRs, FPRs, FPRmeta, Spills);
  169. // critical: no yieldpoints/GCpoints between here and the invoke of code!
  170. // We may have references hidden in the GPRs and Spills arrays!!!
  171. RVMThread.getCurrentThread().enableYieldpoints();
  172. if (!returnIsPrimitive) {
  173. return Magic.invokeMethodReturningObject(code, GPRs, FPRs, FPRmeta, Spills);
  174. }
  175. if (returnType.isVoidType()) {
  176. Magic.invokeMethodReturningVoid(code, GPRs, FPRs, FPRmeta, Spills);
  177. return null;
  178. }
  179. if (returnType.isBooleanType()) {
  180. int x = Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills);
  181. return x == 1;
  182. }
  183. if (returnType.isByteType()) {
  184. int x = Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills);
  185. return (byte) x;
  186. }
  187. if (returnType.isShortType()) {
  188. int x = Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills);
  189. return (short) x;
  190. }
  191. if (returnType.isCharType()) {
  192. int x = Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills);
  193. return (char) x;
  194. }
  195. if (returnType.isIntType()) {
  196. return Magic.invokeMethodReturningInt(code, GPRs, FPRs, FPRmeta, Spills);
  197. }
  198. if (returnType.isLongType()) {
  199. return Magic.invokeMethodReturningLong(code, GPRs, FPRs, FPRmeta, Spills);
  200. }
  201. if (returnType.isFloatType()) {
  202. return Magic.invokeMethodReturningFloat(code, GPRs, FPRs, FPRmeta, Spills);
  203. }
  204. if (returnType.isDoubleType()) {
  205. return Magic.invokeMethodReturningDouble(code, GPRs, FPRs, FPRmeta, Spills);
  206. }
  207. if (VM.VerifyAssertions) VM._assert(NOT_REACHED);
  208. return null;
  209. }
  210. // Method parameter wrappers.
  211. //
  212. @NoInline
  213. public static Object wrapBoolean(int b) { return b == 1; }
  214. @NoInline
  215. public static Object wrapByte(byte b) { return b; }
  216. @NoInline
  217. public static Object wrapChar(char c) { return c; }
  218. @NoInline
  219. public static Object wrapShort(short s) { return s; }
  220. @NoInline
  221. public static Object wrapInt(int i) { return i; }
  222. @NoInline
  223. public static Object wrapLong(long l) { return l; }
  224. @NoInline
  225. public static Object wrapFloat(float f) { return f; }
  226. @NoInline
  227. public static Object wrapDouble(double d) { return d; }
  228. // Method parameter unwrappers.
  229. //
  230. @NoInline
  231. public static int unwrapBooleanAsInt(Object o) {
  232. if (unwrapBoolean(o)) {
  233. return 1;
  234. } else {
  235. return 0;
  236. }
  237. }
  238. @NoInline
  239. public static boolean unwrapBoolean(Object o) { return (Boolean) o; }
  240. @NoInline
  241. public static byte unwrapByte(Object o) { return (Byte) o; }
  242. @NoInline
  243. public static char unwrapChar(Object o) { return (Character) o; }
  244. @NoInline
  245. public static short unwrapShort(Object o) { return (Short) o; }
  246. @NoInline
  247. public static int unwrapInt(Object o) { return (Integer) o; }
  248. @NoInline
  249. public static long unwrapLong(Object o) { return (Long) o; }
  250. @NoInline
  251. public static float unwrapFloat(Object o) { return (Float) o; }
  252. @NoInline
  253. public static double unwrapDouble(Object o) { return (Double) o; }
  254. @NoInline
  255. public static Address unwrapObject(Object o) { return Magic.objectAsAddress(o); }
  256. private static boolean firstUse = true;
  257. }