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.jni.ia32; 014 015import java.lang.reflect.Constructor; 016 017import org.jikesrvm.VM; 018import org.jikesrvm.classloader.MemberReference; 019import org.jikesrvm.classloader.MethodReference; 020import org.jikesrvm.classloader.RVMMethod; 021import org.jikesrvm.classloader.TypeReference; 022 023import static org.jikesrvm.ia32.BaselineConstants.WORDSIZE; 024 025import org.jikesrvm.jni.JNIEnvironment; 026import org.jikesrvm.jni.JNIGenericHelpers; 027import org.jikesrvm.runtime.Magic; 028import org.jikesrvm.runtime.SysCall; 029import org.jikesrvm.scheduler.RVMThread; 030import org.vmmagic.pragma.NoInline; 031import org.vmmagic.pragma.NoOptCompile; 032import org.vmmagic.unboxed.Address; 033 034/** 035 * Platform dependent utility functions called from JNIFunctions 036 * (cannot be placed in JNIFunctions because methods 037 * there are specially compiled to be called from native). 038 * 039 * @see org.jikesrvm.jni.JNIFunctions 040 */ 041public abstract class JNIHelpers extends JNIGenericHelpers { 042 043 /** 044 * Common code shared by the JNI functions NewObjectA, NewObjectV, NewObject 045 * (object creation) 046 * @param cls class whose constructor is to be invoked 047 * @param methodID the method ID for a constructor 048 * @param argAddress where to find the arguments for the constructor 049 * @param isJvalue {@code true} if parameters are passed as a jvalue array 050 * @param isDotDotStyle {@code true} if the method uses varargs 051 * @return a new object created by the specified constructor 052 * @throws Exception when the reflective invocation of the constructor fails 053 */ 054 public static Object invokeInitializer(Class<?> cls, int methodID, Address argAddress, boolean isJvalue, 055 boolean isDotDotStyle) throws Exception { 056 // get the parameter list as Java class 057 MemberReference mr = MemberReference.getMemberRef(methodID); 058 TypeReference tr = java.lang.JikesRVMSupport.getTypeForClass(cls).getTypeRef(); 059 MethodReference methodRef = MemberReference.findOrCreate(tr, mr.getName(), mr.getDescriptor()).asMethodReference(); 060 RVMMethod mth = methodRef.resolve(); 061 062 Constructor<?> constMethod = java.lang.reflect.JikesRVMSupport.createConstructor(mth); 063 if (!mth.isPublic()) { 064 constMethod.setAccessible(true); 065 } 066 067 // Package the parameters for the constructor 068 Address varargAddress; 069 if (isDotDotStyle) { 070 // flag is false because this JNI function has 3 args before the var args 071 varargAddress = getVarArgAddress(false); 072 } else { 073 varargAddress = argAddress; 074 } 075 076 Object[] argObjs; 077 if (isJvalue) { 078 argObjs = packageParametersFromJValuePtr(methodRef, argAddress); 079 } else { 080 argObjs = packageParameterFromVarArg(methodRef, varargAddress); 081 } 082 083 // construct the new object 084 return constMethod.newInstance(argObjs); 085 } 086 087 /** 088 * Common code shared by the JNI functions CallStatic<type>Method 089 * (static method invocation) 090 * @param methodID the method ID 091 * @param expectReturnType the return type of the method to be invoked 092 * @return an object that may be the return object or a wrapper for the primitive return value 093 * @throws Exception if the return type doesn't match the expected return type 094 */ 095 @NoInline 096 @NoOptCompile 097 // expect a certain stack frame structure 098 public static Object invokeWithDotDotVarArg(int methodID, TypeReference expectReturnType) throws Exception { 099 MethodReference mr = MemberReference.getMethodRef(methodID); 100 Address varargAddress = getVarArgAddress(false); 101 Object[] argObjectArray = packageParameterFromVarArg(mr, varargAddress); 102 return callMethod(null, mr, argObjectArray, expectReturnType, true); 103 } 104 105 /** 106 * Common code shared by the JNI functions Call<type>Method 107 * (virtual method invocation) 108 * @param obj the object instance 109 * @param methodID the method ID 110 * @param expectReturnType the return type for checking purpose 111 * @param skip4Args true if the calling JNI Function takes 4 args before the vararg 112 * false if the calling JNI Function takes 3 args before the vararg 113 * @return an object that may be the return object or a wrapper for the primitive return value 114 * @throws Exception if the return type doesn't match the expected return type 115 */ 116 @NoInline 117 @NoOptCompile 118 // expect a certain stack frame structure 119 public static Object invokeWithDotDotVarArg(Object obj, int methodID, TypeReference expectReturnType, 120 boolean skip4Args) throws Exception { 121 MethodReference mr = MemberReference.getMethodRef(methodID); 122 Address varargAddress = getVarArgAddress(skip4Args); 123 Object[] argObjectArray = packageParameterFromVarArg(mr, varargAddress); 124 return callMethod(obj, mr, argObjectArray, expectReturnType, skip4Args); 125 } 126 127 /** 128 * This method supports var args passed from C.<p> 129 * 130 * In the Linux Intel C convention, the caller places the args immediately above the 131 * saved return address, starting with the first arg. <br> 132 * 133 * For the JNI functions that takes var args, their prolog code will save the 134 * var arg in the glue frame because the values in the register may be lost by 135 * subsequent calls. <br> 136 * 137 * This method copies the var arg values that were saved earlier in glue frame into 138 * the spill area of the original caller, thereby doing the work that the callee 139 * normally performs in the AIX C convention. <br> 140 * 141 * NOTE: This method contains internal stack pointer. 142 * For now we assume that the stack will not be relocatable while native code is running 143 * because native code can hold an address into the stack, so this code is OK, 144 * but this is an issue to be resolved later. <br> 145 * 146 * NOTE: this method assumes that it is immediately above the 147 * invokeWithDotDotVarArg frame, the JNI frame, the glue frame and 148 * the C caller frame in the respective order. 149 * Therefore, this method will not work if called from anywhere else. 150 * 151 * <pre> 152 * low address 153 * 154 * | fp | <- JNIEnvironment.getVarArgAddress 155 * | mid | 156 * | | 157 * | | 158 * |------| 159 * | fp | <- JNIEnvironment.invokeWithDotDotVarArg frame 160 * | mid | 161 * | ... | 162 * | | 163 * | | 164 * |------| 165 * | fp | <- JNI method frame 166 * | mid | 167 * | ... | 168 * | arg 0| args copied by JNI prolog (3 for static, nonvirtual, 169 * | arg 1| or 4 for virtual) 170 * | arg 2| 171 * | | 172 * | | 173 * |------| 174 * | fp | <- Native C caller frame 175 * |return| 176 * | arg 0| 177 * | arg 1| 178 * | arg 2| 179 * | arg 3| 180 * | arg 4| 181 * | arg 5| 182 * | arg 6| 183 * | arg 7| 184 * | arg 8| 185 * | arg 9| 186 * | | 187 * | | 188 * | | 189 * 190 * 191 * high address 192 * </pre> 193 * 194 * @param skip4Args if true, the calling JNI function has 4 args before the vararg 195 * if false, the calling JNI function has 3 args before the vararg 196 * @return the starting address of the vararg in the caller stack frame 197 */ 198 @NoInline 199 private static Address getVarArgAddress(boolean skip4Args) { 200 Address fp = Magic.getFramePointer(); 201 fp = fp.loadAddress(); 202 fp = fp.loadAddress(); 203 return (fp.plus(2 * WORDSIZE + (skip4Args ? 4 * WORDSIZE : 3 * WORDSIZE))); 204 } 205 206 /** 207 * Common code shared by the JNI functions CallStatic<type>MethodV 208 * @param methodID the method ID 209 * @param argAddress a raw address for the variable argument list 210 * @param expectReturnType the return type of the method to be invoked 211 * @return an object that may be the return object or a wrapper for the primitive return value 212 * @throws Exception if the return type doesn't match the expected return type 213 */ 214 public static Object invokeWithVarArg(int methodID, Address argAddress, TypeReference expectReturnType) 215 throws Exception { 216 MethodReference mr = MemberReference.getMethodRef(methodID); 217 Object[] argObjectArray = packageParameterFromVarArg(mr, argAddress); 218 return callMethod(null, mr, argObjectArray, expectReturnType, true); 219 } 220 221 /** 222 * Common code shared by the JNI functions Call<type>MethodV 223 * @param obj the object instance 224 * @param methodID the method ID 225 * @param argAddress a raw address for the variable argument list 226 * @param expectReturnType the return type for checking purpose 227 * @param skip4Args received from the JNI function, passed on to Reflection.invoke() 228 * @return an object that may be the return object or a wrapper for the primitive return value 229 * @throws Exception if the return type doesn't match the expected return type 230 */ 231 public static Object invokeWithVarArg(Object obj, int methodID, Address argAddress, TypeReference expectReturnType, 232 boolean skip4Args) throws Exception { 233 MethodReference mr = MemberReference.getMethodRef(methodID); 234 Object[] argObjectArray = packageParameterFromVarArg(mr, argAddress); 235 return callMethod(obj, mr, argObjectArray, expectReturnType, skip4Args); 236 } 237 238 /** 239 * Repackage the arguments passed as a variable argument list into an array of Object, 240 * used by the JNI functions CallStatic<type>MethodV 241 * @param targetMethod The target {@link RVMMethod} 242 * @param argAddress an address into the C space for the array of jvalue unions; 243 * each element is 2-word and holds the argument of the appropriate type 244 * @return an Object array holding the arguments wrapped at Objects 245 */ 246 static Object[] packageParameterFromVarArg(MethodReference targetMethod, Address argAddress) { 247 TypeReference[] argTypes = targetMethod.getParameterTypes(); 248 int argCount = argTypes.length; 249 Object[] argObjectArray = new Object[argCount]; 250 Address vaListCopy = SysCall.sysCall.sysVaCopy(argAddress); 251 JNIEnvironment env = RVMThread.getCurrentThread().getJNIEnv(); 252 253 for (int i = 0; i < argCount; i++) { 254 // convert and wrap the argument according to the expected type 255 if (argTypes[i].isReferenceType()) { 256 argObjectArray[i] = env.getJNIRef(SysCall.sysCall.sysVaArgJobject(vaListCopy)); 257 } else if (argTypes[i].isIntType()) { 258 argObjectArray[i] = SysCall.sysCall.sysVaArgJint(vaListCopy); 259 } else if (argTypes[i].isLongType()) { 260 argObjectArray[i] = SysCall.sysCall.sysVaArgJlong(vaListCopy); 261 } else if (argTypes[i].isBooleanType()) { 262 argObjectArray[i] = SysCall.sysCall.sysVaArgJboolean(vaListCopy); 263 } else if (argTypes[i].isByteType()) { 264 argObjectArray[i] = SysCall.sysCall.sysVaArgJbyte(vaListCopy); 265 } else if (argTypes[i].isCharType()) { 266 argObjectArray[i] = SysCall.sysCall.sysVaArgJchar(vaListCopy); 267 } else if (argTypes[i].isShortType()) { 268 argObjectArray[i] = SysCall.sysCall.sysVaArgJshort(vaListCopy); 269 } else if (argTypes[i].isFloatType()) { 270 argObjectArray[i] = SysCall.sysCall.sysVaArgJfloat(vaListCopy); 271 } else { 272 if (VM.VerifyAssertions) VM._assert(argTypes[i].isDoubleType()); 273 argObjectArray[i] = SysCall.sysCall.sysVaArgJdouble(vaListCopy); 274 } 275 } 276 SysCall.sysCall.sysVaEnd(vaListCopy); 277 return argObjectArray; 278 } 279}