/*
* 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.jni.ppc;
import static org.jikesrvm.jni.ppc.JNIStackframeLayoutConstants.JNI_GLUE_FRAME_SIZE;
import static org.jikesrvm.jni.ppc.JNIStackframeLayoutConstants.NATIVE_FRAME_HEADER_SIZE;
import static org.jikesrvm.jni.ppc.JNIStackframeLayoutConstants.VARARG_AREA_OFFSET;
import static org.jikesrvm.ppc.RegisterConstants.LAST_OS_PARAMETER_FPR;
import static org.jikesrvm.ppc.RegisterConstants.LAST_OS_PARAMETER_GPR;
import static org.jikesrvm.ppc.StackframeLayoutConstants.STACKFRAME_HEADER_SIZE;
import static org.jikesrvm.runtime.JavaSizeConstants.BITS_IN_INT;
import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_DOUBLE;
import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_INT;
import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS;
import java.lang.reflect.Constructor;
import org.jikesrvm.VM;
import org.jikesrvm.architecture.StackFrameLayout;
import org.jikesrvm.classloader.MemberReference;
import org.jikesrvm.classloader.MethodReference;
import org.jikesrvm.classloader.RVMMethod;
import org.jikesrvm.classloader.TypeReference;
import org.jikesrvm.jni.JNIEnvironment;
import org.jikesrvm.jni.JNIGenericHelpers;
import org.jikesrvm.runtime.Magic;
import org.jikesrvm.runtime.Reflection;
import org.jikesrvm.scheduler.RVMThread;
import org.vmmagic.pragma.NoInline;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.Offset;
import org.vmmagic.unboxed.Word;
/**
* Platform dependent utility functions called from JNIFunctions
* (cannot be placed in JNIFunctions because methods
* there are specially compiled to be called from native).
*
* @see org.jikesrvm.jni.JNIFunctions
*/
public abstract class JNIHelpers extends JNIGenericHelpers {
/**
* Common code shared by the JNI functions NewObjectA, NewObjectV, NewObject
* (object creation)
* @param methodID the method ID for a constructor
* @return a new object created by the specified constructor
*/
public static Object invokeInitializer(Class<?> cls, int methodID, Address argAddress, boolean isJvalue,
boolean isDotDotStyle) throws Exception {
// get the parameter list as Java class
MemberReference mr = MemberReference.getMemberRef(methodID);
TypeReference tr = java.lang.JikesRVMSupport.getTypeForClass(cls).getTypeRef();
MethodReference methodRef = MemberReference.findOrCreate(tr, mr.getName(), mr.getDescriptor()).asMethodReference();
RVMMethod mth = methodRef.resolve();
Constructor<?> constMethod = java.lang.reflect.JikesRVMSupport.createConstructor(mth);
if (!mth.isPublic()) {
constMethod.setAccessible(true);
}
Object[] argObjs;
if (isJvalue) {
argObjs = packageParametersFromJValuePtr(methodRef, argAddress);
} else if (isDotDotStyle) {
// dot dot var arg
if (VM.BuildForPower64ELF_ABI) {
Address varargAddress = pushVarArgToSpillArea(methodID, false);
argObjs = packageParameterFromVarArg(methodRef, varargAddress);
} else {
if (VM.VerifyAssertions) VM._assert(VM.BuildForSVR4ABI);
// pass in the frame pointer of glue stack frames
// stack frame looks as following:
// this method ->
//
// architecture.JNIHelpers.method -->
//
// native to java method ->
//
// glue frame ->
//
// native C method ->
Address gluefp = Magic.getCallerFramePointer(Magic.getCallerFramePointer(
Magic.getCallerFramePointer(Magic.getFramePointer())));
argObjs = packageParameterFromDotArgSVR4(methodRef, gluefp, false);
}
} else {
// mormal var arg
if (VM.BuildForPower64ELF_ABI) {
argObjs = packageParameterFromVarArg(methodRef, argAddress);
} else {
if (VM.VerifyAssertions) VM._assert(VM.BuildForSVR4ABI);
argObjs = packageParameterFromVarArgSVR4(methodRef, argAddress);
}
}
// construct the new object
return constMethod.newInstance(argObjs);
}
/**
* Common code shared by the JNI functions CallStatic<type>Method
* (static method invocation)
* @param methodID the method ID
* @param expectReturnType the return type of the method to be invoked
* @return an object that may be the return object or a wrapper for the primitive return value
*/
@NoInline
public static Object invokeWithDotDotVarArg(int methodID, TypeReference expectReturnType) throws Exception {
MethodReference mr = MemberReference.getMethodRef(methodID);
if (VM.BuildForPower64ELF_ABI) {
Address varargAddress = pushVarArgToSpillArea(methodID, false);
Object[] argObjectArray = packageParameterFromVarArg(mr, varargAddress);
return callMethod(null, mr, argObjectArray, expectReturnType, true);
} else {
if (VM.VerifyAssertions) VM._assert(VM.BuildForSVR4ABI);
Address glueFP = Magic.getCallerFramePointer(Magic.getCallerFramePointer(Magic.getCallerFramePointer(Magic.getFramePointer())));
Object[] argObjectArray = packageParameterFromDotArgSVR4(mr, glueFP, false);
return callMethod(null, mr, argObjectArray, expectReturnType, true);
}
}
/**
* Common code shared by the JNI functions Call<type>Method
* (virtual method invocation)
* @param obj the object instance
* @param methodID the method ID
* @param expectReturnType the return type for checking purpose
* @param skip4Args true if the calling JNI Function takes 4 args before the vararg
* false if the calling JNI Function takes 3 args before the vararg
* @return an object that may be the return object or a wrapper for the primitive return value
*/
@NoInline
public static Object invokeWithDotDotVarArg(Object obj, int methodID, TypeReference expectReturnType,
boolean skip4Args) throws Exception {
MethodReference mr = MemberReference.getMethodRef(methodID);
if (VM.BuildForPower64ELF_ABI) {
Address varargAddress = pushVarArgToSpillArea(methodID, skip4Args);
Object[] argObjectArray = packageParameterFromVarArg(mr, varargAddress);
return callMethod(obj, mr, argObjectArray, expectReturnType, skip4Args);
} else {
if (VM.VerifyAssertions) VM._assert(VM.BuildForSVR4ABI);
Address glueFP = Magic.getCallerFramePointer(Magic.getCallerFramePointer(Magic.getCallerFramePointer(Magic.getFramePointer())));
Object[] argObjectArray = packageParameterFromDotArgSVR4(mr, glueFP, skip4Args);
return callMethod(obj, mr, argObjectArray, expectReturnType, skip4Args);
}
}
/**
* This method supports var args passed from C.<p>
*
* TODO update for AIX removal
*
* In the AIX C convention, the caller keeps the first 8 words in registers and
* the rest in the spill area in the caller frame. The callee will push the values
* in registers out to the spill area of the caller frame and use the beginning
* address of this spill area as the var arg address.<p>
*
* For the JNI functions that takes var args, their prolog code will save the
* var arg in the glue frame because the values in the register may be lost by
* subsequent calls.<p>
*
* This method copies the var arg values that were saved earlier in glue frame into
* the spill area of the original caller, thereby doing the work that the callee
* normally performs in the AIX C convention..<p>
*
* NOTE: this method assumes that it is immediately above the
* invokeWithDotDotVarArg frame, the JNI frame, the glue frame and
* the C caller frame in the respective order.
* Therefore, this method will not work if called from anywhere else
* <pre>
*
* | fp | <- JNIEnvironment.pushVarArgToSpillArea
* | mid |
* | xxx |
* | |
* | |
* |------|
* | fp | <- JNIEnvironment.invokeWithDotDotVarArg frame
* | mid |
* | xxx |
* | |
* | |
* | |
* |------|
* | fp | <- JNI method frame
* | mid |
* | xxx |
* | |
* | |
* | |
* |------|
* | fp | <- glue frame
* | mid |
* + xxx +
* | r3 | volatile save area
* | r4 |
* | r5 |
* | r6 | vararg GPR[6-10]save area <- VARARG_AREA_OFFSET
* | r7 |
* | r8 |
* | r9 |
* | r10 |
* | fpr1 | vararg FPR[1-3] save area (also used as volatile FPR[1-6] save area)
* | fpr2 |
* | fpr3 |
* | fpr4 |
* | fpr5 |
* + fpr6 +
* | r13 | nonvolatile GPR[13-31] save area
* | ... |
* + r31 +
* | fpr14| nonvolatile FPR[14-31] save area
* | ... |
* | fpr31|
* |topjav| offset to preceding Java to C glue frame
* |------|
* | fp | <- Native C caller frame
* | cr |
* | lr |
* | resv |
* | resv |
* + toc +
* | 0 | spill area initially not filled
* | 1 | to be filled by this method
* | 2 |
* | 3 |
* | 4 |
* | 5 |
* | 6 |
* | 7 |
* | 8 | spill area already filled by caller
* | 9 |
* | |
* | |
* | |
* </pre>
*
* @param methodID a MemberReference id
* @param skip4Args if true, the calling JNI function has 4 args before the vararg
* if false, the calling JNI function has 3 args before the vararg
* @return the starting address of the vararg in the caller stack frame
*/
@NoInline
private static Address pushVarArgToSpillArea(int methodID, boolean skip4Args) throws Exception {
if (!(VM.BuildForPower64ELF_ABI || VM.BuildForSVR4ABI)) {
if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
return Address.zero();
}
int glueFrameSize = JNI_GLUE_FRAME_SIZE;
// get the FP for this stack frame and traverse 3 frames to get to the glue frame
Address gluefp =
Magic.getFramePointer().plus(StackFrameLayout.getStackFramePointerOffset()).loadAddress(); // *.ppc.JNIHelpers.invoke*
gluefp = gluefp.plus(StackFrameLayout.getStackFramePointerOffset()).loadAddress(); // architecture.JNIHelpers.invoke*
gluefp = gluefp.plus(StackFrameLayout.getStackFramePointerOffset()).loadAddress(); // JNIFunctions
gluefp = gluefp.plus(StackFrameLayout.getStackFramePointerOffset()).loadAddress(); // glue frame
// compute the offset into the area where the vararg GPR[6-10] and FPR[1-3] are saved
// skipping the args which are not part of the arguments for the target method
// For Call<type>Method functions and NewObject, skip 3 args
// For CallNonvirtual<type>Method functions, skip 4 args
Offset varargGPROffset = Offset.fromIntSignExtend(VARARG_AREA_OFFSET + (skip4Args ? BYTES_IN_ADDRESS : 0));
Offset varargFPROffset = varargGPROffset.plus(5 * BYTES_IN_ADDRESS);
// compute the offset into the spill area of the native caller frame,
// skipping the args which are not part of the arguments for the target method
// For Call<type>Method functions, skip 3 args
// For CallNonvirtual<type>Method functions, skip 4 args
Offset spillAreaLimit = Offset.fromIntSignExtend(glueFrameSize + NATIVE_FRAME_HEADER_SIZE + 8 * BYTES_IN_ADDRESS);
Offset spillAreaOffset =
Offset.fromIntSignExtend(glueFrameSize +
NATIVE_FRAME_HEADER_SIZE +
(skip4Args ? 4 * BYTES_IN_ADDRESS : 3 * BYTES_IN_ADDRESS));
// address to return pointing to the var arg list
Address varargAddress = gluefp.plus(spillAreaOffset);
// VM.sysWrite("pushVarArgToSpillArea: var arg at " +
// Services.intAsHexString(varargAddress) + "\n");
RVMMethod targetMethod = MemberReference.getMethodRef(methodID).resolve();
TypeReference[] argTypes = targetMethod.getParameterTypes();
int argCount = argTypes.length;
for (int i = 0; i < argCount && spillAreaOffset.sLT(spillAreaLimit); i++) {
Word hiword, loword;
if (argTypes[i].isFloatingPointType()) {
// move 2 words from the vararg FPR save area into the spill area of the caller
hiword = gluefp.loadWord(varargFPROffset);
varargFPROffset = varargFPROffset.plus(BYTES_IN_ADDRESS);
if (VM.BuildFor32Addr) {
loword = gluefp.loadWord(varargFPROffset);
varargFPROffset = varargFPROffset.plus(BYTES_IN_ADDRESS);
}
gluefp.store(hiword, spillAreaOffset);
spillAreaOffset = spillAreaOffset.plus(BYTES_IN_ADDRESS);
if (VM.BuildFor32Addr) {
gluefp.store(loword, spillAreaOffset);
spillAreaOffset = spillAreaOffset.plus(BYTES_IN_ADDRESS);
}
} else if (argTypes[i].isLongType()) {
// move 2 words from the vararg GPR save area into the spill area of the caller
hiword = gluefp.loadWord(varargGPROffset);
varargGPROffset = varargGPROffset.plus(BYTES_IN_ADDRESS);
gluefp.store(hiword, spillAreaOffset);
spillAreaOffset = spillAreaOffset.plus(BYTES_IN_ADDRESS);
// this covers the case when the long value straddles the spill boundary
if (VM.BuildFor32Addr && spillAreaOffset.sLT(spillAreaLimit)) {
loword = gluefp.loadWord(varargGPROffset);
varargGPROffset = varargGPROffset.plus(BYTES_IN_ADDRESS);
gluefp.store(loword, spillAreaOffset);
spillAreaOffset = spillAreaOffset.plus(BYTES_IN_ADDRESS);
}
} else {
hiword = gluefp.loadWord(varargGPROffset);
varargGPROffset = varargGPROffset.plus(BYTES_IN_ADDRESS);
gluefp.store(hiword, spillAreaOffset);
spillAreaOffset = spillAreaOffset.plus(BYTES_IN_ADDRESS);
}
}
// At this point, all the vararg values should be in the spill area in the caller frame
// return the address of the beginning of the vararg to use in invoking the target method
return varargAddress;
}
/**
* Common code shared by the JNI functions CallStatic<type>MethodV
* @param methodID the method ID
* @param argAddress a raw address for the variable argument list
* @return an object that may be the return object or a wrapper for the primitive return value
*/
public static Object invokeWithVarArg(int methodID, Address argAddress, TypeReference expectReturnType)
throws Exception {
MethodReference mr = MemberReference.getMethodRef(methodID);
if (VM.BuildForPower64ELF_ABI) {
Object[] argObjectArray = packageParameterFromVarArg(mr, argAddress);
return callMethod(null, mr, argObjectArray, expectReturnType, true);
} else {
if (VM.VerifyAssertions) VM._assert(VM.BuildForSVR4ABI);
Object[] argObjectArray = packageParameterFromVarArgSVR4(mr, argAddress);
return callMethod(null, mr, argObjectArray, expectReturnType, true);
}
}
/**
* Common code shared by the JNI functions Call<type>MethodV
* @param obj the object instance
* @param methodID the method ID
* @param argAddress a raw address for the variable argument list
* @param expectReturnType the return type for checking purpose
* @param skip4Args received from the JNI function, passed on to Reflection.invoke()
* @return an object that may be the return object or a wrapper for the primitive return value
*/
public static Object invokeWithVarArg(Object obj, int methodID, Address argAddress, TypeReference expectReturnType,
boolean skip4Args) throws Exception {
MethodReference mr = MemberReference.getMethodRef(methodID);
if (VM.BuildForPower64ELF_ABI) {
Object[] argObjectArray = packageParameterFromVarArg(mr, argAddress);
return callMethod(obj, mr, argObjectArray, expectReturnType, skip4Args);
} else {
if (VM.VerifyAssertions) VM._assert(VM.BuildForSVR4ABI);
Object[] argObjectArray = packageParameterFromVarArgSVR4(mr, argAddress);
return callMethod(obj, mr, argObjectArray, expectReturnType, skip4Args);
}
}
/* The method reads out parameters from registers saved in native->java glue stack frame (glueFP)
* and the spill area of native stack frame (caller of glueFP).
*
* NOTE: assuming the stack frame won't get moved, (see pushVarArgToSpillArea)
* the row address glueFP can be replaced by offset to the stack.
*
* @param targetMethod, the call target
* @param glueFP, the glue stack frame pointer
*/
static Object[] packageParameterFromDotArgSVR4(MethodReference targetMethod, Address glueFP, boolean skip4Args) {
if (!VM.BuildForSVR4ABI) {
if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
return null;
}
// native method's stack frame
Address nativeFP = Magic.getCallerFramePointer(glueFP);
TypeReference[] argTypes = targetMethod.getParameterTypes();
int argCount = argTypes.length;
Object[] argObjectArray = new Object[argCount];
JNIEnvironment env = RVMThread.getCurrentThread().getJNIEnv();
// GPR r3 - r10 and FPR f1 - f8 are saved in glue stack frame
Address regsavearea = glueFP.plus(STACKFRAME_HEADER_SIZE);
// spill area offset
Address overflowarea = nativeFP.plus(NATIVE_FRAME_HEADER_SIZE);
//overflowarea is aligned to 8 bytes
if (VM.VerifyAssertions) VM._assert(overflowarea.toWord().and(Word.fromIntZeroExtend(0x07)).isZero());
//adjust gpr and fpr to normal numbering, make life easier
int gpr = (skip4Args) ? 7 : 6; // r3 - env, r4 - cls, r5 - method id
int fpr = 1;
// not set the starting gprs array address
// and fpr starting array address, so we can use gpr and fpr to
// calculate the right position to get values
// GPR starts with r3;
Address gprarray = regsavearea.plus(-3 * BYTES_IN_ADDRESS);
Address fprarray = regsavearea.plus(8 * BYTES_IN_ADDRESS - 2 * BYTES_IN_ADDRESS);
// call the common function for SVR4
packageArgumentForSVR4(argTypes, argObjectArray, gprarray, fprarray, overflowarea, gpr, fpr, env);
return argObjectArray;
}
// linux has totally different layout of va_list
// see /usr/lib/gcc-lib/powerpc-linux/xxxx/include/va-ppc.h
//
// va_list is defined as following
//
// struct {
// char unsigned gpr; // compiled to 1 byte, index of gprs in saved area
// // 0 -> r3, 1 -> r4, ....
// char unsigned fpr; // compiled to 1 byte, index to fprs in saved area
// // 0 -> fr1, 1 -> fr2, ....
// char * over_flow_area;
// char * reg_save_area;
// }
//
// The interpretation of data can be found in PowerPC Processor ABI Supplement
//
// The reg_save area lays out r3 - r10, f1 - f8
//
// I am not sure if GCC understand the ABI in a right way, it saves GPRs 1 - 10
// in the area, while only gprs starting from r3 are used.
//
// -- Feng
//
static Object[] packageParameterFromVarArgSVR4(MethodReference targetMethod, Address argAddress) {
if (!VM.BuildForSVR4ABI) {
if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
return null;
}
TypeReference[] argTypes = targetMethod.getParameterTypes();
int argCount = argTypes.length;
Object[] argObjectArray = new Object[argCount];
JNIEnvironment env = RVMThread.getCurrentThread().getJNIEnv();
// the va_list has following layout on PPC/Linux
// GPR FPR 0 0 (4 bytes)
// overflowarea (pointer)
// reg_save_area (pointer)
Address va_list_addr = argAddress;
int word1 = va_list_addr.loadWord().toInt();
int gpr = word1 >> 24;
int fpr = (word1 >> 16) & 0x0FF;
Address overflowarea = va_list_addr.loadAddress(Offset.fromIntSignExtend(BYTES_IN_ADDRESS));
Address regsavearea = va_list_addr.loadAddress(Offset.fromIntSignExtend(2 * BYTES_IN_ADDRESS));
if (VM.BuildForSVR4ABI) {
//overflowarea is aligned to 8 bytes
if (VM.VerifyAssertions) VM._assert(overflowarea.toWord().and(Word.fromIntZeroExtend(0x07)).isZero());
}
//adjust gpr and fpr to normal numbering, make life easier
gpr += 3;
fpr += 1;
// not set the starting gprs array address
// and fpr starting array address, so we can use gpr and fpr to
// calculate the right position to get values
// GPR starts with r3;
Address gprarray = regsavearea.plus(-3 * BYTES_IN_ADDRESS);
Address fprarray = regsavearea.plus(8 * BYTES_IN_ADDRESS - 2 * BYTES_IN_ADDRESS);
// call the common function for SVR4
packageArgumentForSVR4(argTypes, argObjectArray, gprarray, fprarray, overflowarea, gpr, fpr, env);
return argObjectArray;
}
static void packageArgumentForSVR4(TypeReference[] argTypes, Object[] argObjectArray, Address gprarray,
Address fprarray, Address overflowarea, int gpr, int fpr, JNIEnvironment env) {
if (!VM.BuildForSVR4ABI) {
if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
return;
}
// also make overflow offset, we may need to round it
Offset overflowoffset = Offset.zero();
int argCount = argTypes.length;
// now interpret values by types, see PPC ABI
for (int i = 0; i < argCount; i++) {
if (argTypes[i].isFloatingPointType()) {
int loword, hiword;
if (fpr > LAST_OS_PARAMETER_FPR.value()) {
// overflow, OTHER
// round it, bytes are saved from lowest to highest one, regardless endian
overflowoffset = overflowoffset.plus(7).toWord().and(Word.fromIntSignExtend(-8)).toOffset();
hiword = overflowarea.loadInt(overflowoffset);
overflowoffset = overflowoffset.plus(BYTES_IN_INT);
loword = overflowarea.loadInt(overflowoffset);
overflowoffset = overflowoffset.plus(BYTES_IN_INT);
} else {
// get value from fpr, increase fpr by 1
hiword = fprarray.plus(fpr * BYTES_IN_DOUBLE).loadInt();
loword = fprarray.plus(fpr * BYTES_IN_DOUBLE + BYTES_IN_INT).loadInt();
fpr += 1;
}
long doubleBits = (((long) hiword) << BITS_IN_INT) | (loword & 0xFFFFFFFFL);
if (argTypes[i].isFloatType()) {
argObjectArray[i] = Reflection.wrapFloat((float) (Double.longBitsToDouble(doubleBits)));
} else { // double type
argObjectArray[i] = Reflection.wrapDouble(Double.longBitsToDouble(doubleBits));
}
// VM.sysWriteln("double "+Double.longBitsToDouble(doubleBits));
} else if (argTypes[i].isLongType()) {
int loword, hiword;
if (gpr > (LAST_OS_PARAMETER_GPR.value() - 1)) {
// overflow, OTHER
// round overflowoffset, assuming overflowarea is aligned to 8 bytes
overflowoffset = overflowoffset.plus(7).toWord().and(Word.fromIntSignExtend(-8)).toOffset();
hiword = overflowarea.loadInt(overflowoffset);
overflowoffset = overflowoffset.plus(BYTES_IN_INT);
loword = overflowarea.loadInt(overflowoffset);
overflowoffset = overflowoffset.plus(BYTES_IN_INT);
// va-ppc.h makes last gpr useless
gpr = 11;
} else {
gpr += (gpr + 1) & 0x01; // if gpr is even, gpr += 1
hiword = gprarray.plus(gpr * 4).loadInt();
loword = gprarray.plus((gpr + 1) * 4).loadInt();
gpr += 2;
}
long longBits = (((long) hiword) << BITS_IN_INT) | (loword & 0xFFFFFFFFL);
argObjectArray[i] = Reflection.wrapLong(longBits);
// VM.sysWriteln("long 0x"+Long.toHexString(longBits));
} else {
// int type left now
int ivalue;
if (gpr > LAST_OS_PARAMETER_GPR.value()) {
// overflow, OTHER
ivalue = overflowarea.loadInt(overflowoffset);
overflowoffset = overflowoffset.plus(4);
} else {
ivalue = gprarray.plus(gpr * 4).loadInt();
gpr += 1;
}
// VM.sysWriteln("int "+ivalue);
if (argTypes[i].isBooleanType()) {
argObjectArray[i] = Reflection.wrapBoolean(ivalue);
} else if (argTypes[i].isByteType()) {
argObjectArray[i] = Reflection.wrapByte((byte) ivalue);
} else if (argTypes[i].isShortType()) {
argObjectArray[i] = Reflection.wrapShort((short) ivalue);
} else if (argTypes[i].isCharType()) {
argObjectArray[i] = Reflection.wrapChar((char) ivalue);
} else if (argTypes[i].isIntType()) {
argObjectArray[i] = Reflection.wrapInt(ivalue);
} else if (argTypes[i].isReferenceType()) {
argObjectArray[i] = env.getJNIRef(ivalue);
} else {
if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
}
}
}
}
/**
* Repackage the arguments passed as a variable argument list into an array of Object,
* used by the JNI functions CallStatic<type>MethodV
* @param targetMethod The target {@link RVMMethod}
* @param argAddress an address into the C space for the array of jvalue unions;
* each element is 2-word and holds the argument of the appropriate type
* @return an Object array holding the arguments wrapped at Objects
*/
static Object[] packageParameterFromVarArg(MethodReference targetMethod, Address argAddress) {
TypeReference[] argTypes = targetMethod.getParameterTypes();
int argCount = argTypes.length;
Object[] argObjectArray = new Object[argCount];
// get the JNIEnvironment for this thread in case we need to dereference any object arg
JNIEnvironment env = RVMThread.getCurrentThread().getJNIEnv();
// VM.sysWriteln("JNI packageParameterFromVarArg: packaging " + argCount + " arguments");
Address addr = argAddress;
for (int i = 0; i < argCount; i++) {
long hiword = VM.BuildFor64Addr ? addr.loadLong() : (long) addr.loadInt();
// VM.sysWrite("JNI packageParameterFromVarArg: arg " + i + " = " + hiword +
// " or " + Services.intAsHexString(hiword) + "\n");
addr = addr.plus(BYTES_IN_ADDRESS);
// convert and wrap the argument according to the expected type
if (argTypes[i].isFloatType()) {
// NOTE: in VarArg convention, C compiler will expand a float to a double that occupy 2 words
// so we have to extract it as a double and convert it back to a float
if (VM.BuildFor32Addr) {
int loword = addr.loadInt();
addr = addr.plus(BYTES_IN_ADDRESS);
long doubleBits = (hiword << BITS_IN_INT) | (loword & 0xFFFFFFFFL);
argObjectArray[i] = Reflection.wrapFloat((float) (Double.longBitsToDouble(doubleBits)));
} else {
argObjectArray[i] = Reflection.wrapFloat((float) (Double.longBitsToDouble(hiword)));
}
} else if (argTypes[i].isDoubleType()) {
if (VM.BuildFor32Addr) {
int loword = addr.loadInt();
addr = addr.plus(BYTES_IN_ADDRESS);
long doubleBits = (hiword << BITS_IN_INT) | (loword & 0xFFFFFFFFL);
argObjectArray[i] = Reflection.wrapDouble(Double.longBitsToDouble(doubleBits));
} else {
argObjectArray[i] = Reflection.wrapDouble(Double.longBitsToDouble(hiword));
}
} else if (argTypes[i].isLongType()) {
if (VM.BuildFor32Addr) {
int loword = addr.loadInt();
addr = addr.plus(BYTES_IN_ADDRESS);
long longValue = (hiword << BITS_IN_INT) | (loword & 0xFFFFFFFFL);
argObjectArray[i] = Reflection.wrapLong(longValue);
} else {
argObjectArray[i] = Reflection.wrapLong(hiword);
}
} else if (argTypes[i].isBooleanType()) {
// the 0/1 bit is stored in the high byte
argObjectArray[i] = Reflection.wrapBoolean((int) hiword);
} else if (argTypes[i].isByteType()) {
// the target byte is stored in the high byte
argObjectArray[i] = Reflection.wrapByte((byte) hiword);
} else if (argTypes[i].isCharType()) {
// char is stored in the high 2 bytes
argObjectArray[i] = Reflection.wrapChar((char) hiword);
} else if (argTypes[i].isShortType()) {
// short is stored in the high 2 bytes
argObjectArray[i] = Reflection.wrapShort((short) hiword);
} else if (argTypes[i].isReferenceType()) {
// for object, the arg is a JREF index, dereference to get the real object
argObjectArray[i] = env.getJNIRef((int) hiword);
} else if (argTypes[i].isIntType()) {
argObjectArray[i] = Reflection.wrapInt((int) hiword);
} else {
return null;
}
}
return argObjectArray;
}
}