use of org.jikesrvm.classloader.TypeReference in project JikesRVM by JikesRVM.
the class JNIHelpers method invokeInitializer.
/**
* Common code shared by the JNI functions NewObjectA, NewObjectV, NewObject
* (object creation)
* @param cls class whose constructor is to be invoked
* @param methodID the method ID for a constructor
* @param argAddress where to find the arguments for the constructor
* @param isJvalue {@code true} if parameters are passed as a jvalue array
* @param isDotDotStyle {@code true} if the method uses varargs
* @return a new object created by the specified constructor
* @throws Exception when the reflective invocation of the constructor fails
*/
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);
}
// Package the parameters for the constructor
Address varargAddress;
if (isDotDotStyle) {
// flag is false because this JNI function has 3 args before the var args
varargAddress = getVarArgAddress(false);
} else {
varargAddress = argAddress;
}
Object[] argObjs;
if (isJvalue) {
argObjs = packageParametersFromJValuePtr(methodRef, argAddress);
} else {
argObjs = packageParameterFromVarArg(methodRef, varargAddress);
}
// construct the new object
return constMethod.newInstance(argObjs);
}
use of org.jikesrvm.classloader.TypeReference in project JikesRVM by JikesRVM.
the class JNICompiler method compile.
/**
* This method creates the stub to link native method. It will be called
* from the lazy linker the first time a native method is invoked. The stub
* generated will be patched by the lazy linker to link to the native method
* for all future calls. <p>
* <pre>
* The stub performs the following tasks in the prologue:
* <ol>
* <li>Allocate the glue frame
* <li>Save the TR and JTOC registers in the JNI Environment for reentering Java later
* <li>Shuffle the parameters in the registers to conform to the OS calling convention
* <li>Save the nonvolatile registers in a known space in the frame to be used
* for the GC stack map
* <li>Push a new JREF frame on the JNIRefs stack
* <li>Supply the first JNI argument: the JNI environment pointer
* <li>Supply the second JNI argument: class object if static, "this" if virtual
* </ol>
* <p>
* The stub performs the following tasks in the epilogue:
* <ol>
* <li>Restore TR and JTOC registers saved in JNI Environment
* <li>Restore the nonvolatile registers if GC has occurred
* <li>Pop the JREF frame off the JNIRefs stack
* <li>Check for pending exception and deliver to Java caller if present
* <li>Process the return value from native: push onto caller's Java stack
* </ol>
* <p>
* Within the stackframe, we have two frames.
* The "main" frame exactly follows the OS native ABI and is therefore
* different for each ABI.
* The "mini-frame" is identical on all platforms and is stores RVM-specific fields.
* The picture below shows the frames for 64-bit PowerPC ELF ABI.
* <pre>
*
* | fp | <- native frame
* | cr |
* | lr |
* | resv |
* | resv |
* + toc +
* | |
* | |
* |----------| <- Java to C glue frame using native calling conventions
* | fp | saved fp of mini-frame
* | cr |
* | lr | native caller saves return address of native method here
* | resv |
* | resv |
* + toc +
* | 0 | spill area (at least 8 words reserved)
* | 1 | (also used for saving volatile regs during calls in prolog)
* | 2 |
* | 3 |
* | 4 |
* | 5 |
* | 6 |
* | 7 |
* | ... |
* |----------| <- mini-frame for use by RVM stackwalkers
* | fp | saved fp of Java caller <- JNI_SAVE_AREA_OFFSET
* | mid | cmid of native method
* | xxx (lr) | lr slot not used in mini frame
* |GC flag | did GC happen while thread in native? <- JNI_GC_FLAG_OFFSET
* |ENV | JNIEnvironment <- JNI_ENV_OFFSET
* |RVM nonvol| save RVM nonvolatile GPRs for updating by GC stack mapper
* | ... |
* |RVM nonvol| <- JNI_RVM_NONVOLATILE_OFFSET
* |----------|
* | fp | <- Java caller frame
* | mid |
* | xxx |
* | |
* | |
* | |
* |----------|
* | |
* </pre>
* <p>
* Runtime.unwindNativeStackFrame will return a pointer to the mini-frame
* because none of our stack walkers need to do anything with the main frame.
*/
public static synchronized CompiledMethod compile(NativeMethod method) {
JNICompiledMethod cm = (JNICompiledMethod) CompiledMethods.createCompiledMethod(method, CompiledMethod.JNI);
int compiledMethodId = cm.getId();
Assembler asm = new Assembler(0);
int frameSize = getFrameSize(method);
RVMClass klass = method.getDeclaringClass();
// need 4 gp temps
if (VM.VerifyAssertions)
VM._assert(T3.value() <= LAST_VOLATILE_GPR.value());
// need 4 fp temps
if (VM.VerifyAssertions)
VM._assert(F3.value() <= LAST_VOLATILE_FPR.value());
if (VM.VerifyAssertions)
VM._assert(S0.value() < S1.value() && // need 2 scratch
S1.value() <= LAST_SCRATCH_GPR.value());
Address nativeIP = method.getNativeIP();
Address nativeTOC = method.getNativeTOC();
// NOTE: this must be done before the condition Thread.hasNativeStackFrame() become true
// so that the first Java to C transition will be allowed to resize the stack
// (currently, this is true when the JNIRefsTop index has been incremented from 0)
// add at least 14 for C frame (header + spill)
asm.emitNativeStackOverflowCheck(frameSize + 14);
// save return address in caller frame
asm.emitMFLR(REGISTER_ZERO);
asm.emitSTAddr(REGISTER_ZERO, STACKFRAME_RETURN_ADDRESS_OFFSET.toInt(), FP);
// buy mini frame
asm.emitSTAddrU(FP, -JNI_SAVE_AREA_SIZE, FP);
// store CMID for native method in mini-frame
asm.emitLVAL(S0, compiledMethodId);
asm.emitSTW(S0, STACKFRAME_METHOD_ID_OFFSET.toInt(), FP);
// buy main frame, the total size equals to frameSize
asm.emitSTAddrU(FP, -frameSize + JNI_SAVE_AREA_SIZE, FP);
// establish S0 -> threads JNIEnv structure
asm.emitLAddrOffset(S0, THREAD_REGISTER, Entrypoints.jniEnvField.getOffset());
// save the TR register in the JNIEnvironment object for possible calls back into Java
asm.emitSTAddrOffset(THREAD_REGISTER, S0, Entrypoints.JNIEnvSavedTRField.getOffset());
// save the JNIEnvironment in the stack frame so we can use it to acquire the TR
// when we return from native code.
// save TR in frame
asm.emitSTAddr(S0, frameSize - JNI_ENV_OFFSET, FP);
// save mini-frame frame pointer in JNIEnv, JNITopJavaFP, which will be the frame
// to start scanning this stack during GC, if top of stack is still executing in C
asm.emitLAddr(THREAD_REGISTER, 0, FP);
asm.emitSTAddrOffset(THREAD_REGISTER, S0, Entrypoints.JNITopJavaFPField.getOffset());
// save the RVM nonvolatile GPRs, to be scanned by GC stack mapper
for (int i = LAST_NONVOLATILE_GPR.value(), offset = JNI_RVM_NONVOLATILE_OFFSET; i >= FIRST_NONVOLATILE_GPR.value(); --i, offset += BYTES_IN_STACKSLOT) {
asm.emitSTAddr(GPR.lookup(i), frameSize - offset, FP);
}
// clear the GC flag on entry to native code
// use TR as scratch
asm.emitLVAL(THREAD_REGISTER, 0);
asm.emitSTW(THREAD_REGISTER, frameSize - JNI_GC_FLAG_OFFSET, FP);
// generate the code to map the parameters to OS convention and add the
// second parameter (either the "this" ptr or class if a static method).
// The JNI Function ptr first parameter is set before making the call
// by the out of line machine code we invoke below.
// Opens a new frame in the JNIRefs table to register the references.
// Assumes S0 set to JNIEnv, kills KLUDGE_TI_REG, S1 & THREAD_REGISTER
// On return, S0 still contains JNIEnv
storeParameters(asm, frameSize, method, klass);
//
// Load required JNI function ptr into first parameter reg (GPR3/T0)
// This pointer is an interior pointer to the JNIEnvironment which is
// currently in S0.
//
asm.emitADDI(T0, Entrypoints.JNIExternalFunctionsField.getOffset(), S0);
//
// change the status of the thread to IN_JNI
//
asm.emitLAddrOffset(THREAD_REGISTER, S0, Entrypoints.JNIEnvSavedTRField.getOffset());
asm.emitLVALAddr(S1, Entrypoints.execStatusField.getOffset());
// get status for thread
asm.emitLWARX(S0, S1, THREAD_REGISTER);
// we should be in java code?
asm.emitCMPI(S0, RVMThread.IN_JAVA + (RVMThread.ALWAYS_LOCK_ON_STATE_TRANSITION ? 100 : 0));
ForwardReference notInJava = asm.emitForwardBC(NE);
// S0 <- new state value
asm.emitLVAL(S0, RVMThread.IN_JNI);
// attempt to change state to IN_JNI
asm.emitSTWCXr(S0, S1, THREAD_REGISTER);
// branch if success over slow path
ForwardReference enteredJNIRef = asm.emitForwardBC(EQ);
notInJava.resolve(asm);
asm.emitLAddrOffset(S0, THREAD_REGISTER, Entrypoints.threadContextRegistersField.getOffset());
asm.emitLAddrOffset(S1, JTOC, ArchEntrypoints.saveVolatilesInstructionsField.getOffset());
asm.emitMTLR(S1);
asm.emitBCLRL();
// NOTE: THREAD_REGISTER should still have the thread
// pointer, since up to this point we would have saved it but not
// overwritten it.
// call into our friendly slow path function. note that this should
// work because:
// 1) we're not calling from C so we don't care what registers are
// considered non-volatile in C
// 2) all Java non-volatiles have been saved
// 3) the only other registers we need - TR and S0 are taken care
// of (see above)
// 4) the prologue and epilogue will take care of the frame pointer
// accordingly (it will just save it on the stack and then restore
// it - so we don't even have to know what its value is here)
// the only thing we have to make sure of is that MMTk ignores the
// framePointer field in RVMThread and uses the one in the JNI
// environment instead (see Collection.prepareMutator)...
// T1 gets address of function
asm.emitLAddrOffset(S1, JTOC, Entrypoints.enterJNIBlockedFromCallIntoNativeMethod.getOffset());
asm.emitMTLR(S1);
// call RVMThread.enterJNIBlocked
asm.emitBCLRL();
asm.emitLAddrOffset(S0, THREAD_REGISTER, Entrypoints.threadContextRegistersField.getOffset());
asm.emitLAddrOffset(S1, JTOC, ArchEntrypoints.restoreVolatilesInstructionsField.getOffset());
asm.emitMTLR(S1);
asm.emitBCLRL();
// come here when we're done
enteredJNIRef.resolve(asm);
// set the TOC and IP for branch to out_of_line code
asm.emitLVALAddr(JTOC, nativeTOC);
asm.emitLVALAddr(S1, nativeIP);
// move native code address to CTR reg;
// do this early so that S1 will be available as a scratch.
asm.emitMTCTR(S1);
//
// CALL NATIVE METHOD
//
asm.emitBCCTRL();
// if we have to call sysVirtualProcessorYield because we are locked in native.
if (VM.BuildFor64Addr) {
asm.emitSTD(T0, NATIVE_FRAME_HEADER_SIZE, FP);
} else {
asm.emitSTW(T0, NATIVE_FRAME_HEADER_SIZE, FP);
asm.emitSTW(T1, NATIVE_FRAME_HEADER_SIZE + BYTES_IN_ADDRESS, FP);
}
//
// try to return thread status to IN_JAVA
//
int label1 = asm.getMachineCodeIndex();
// TODO: we can do this directly from FP because we know framesize at compiletime
// (the same way we stored the JNI Env above)
// get mini-frame
asm.emitLAddr(S0, 0, FP);
// get Java caller FP
asm.emitLAddr(S0, 0, S0);
// load JNIEnvironment into TR
asm.emitLAddr(THREAD_REGISTER, -JNI_ENV_OFFSET, S0);
// Restore JTOC and TR
asm.emitLAddrOffset(JTOC, THREAD_REGISTER, Entrypoints.JNIEnvSavedJTOCField.getOffset());
asm.emitLAddrOffset(THREAD_REGISTER, THREAD_REGISTER, Entrypoints.JNIEnvSavedTRField.getOffset());
asm.emitLVALAddr(S1, Entrypoints.execStatusField.getOffset());
// get status for processor
asm.emitLWARX(S0, S1, THREAD_REGISTER);
// are we IN_JNI code?
asm.emitCMPI(S0, RVMThread.IN_JNI + (RVMThread.ALWAYS_LOCK_ON_STATE_TRANSITION ? 100 : 0));
ForwardReference blocked = asm.emitForwardBC(NE);
// S0 <- new state value
asm.emitLVAL(S0, RVMThread.IN_JAVA);
// attempt to change state to java
asm.emitSTWCXr(S0, S1, THREAD_REGISTER);
// branch over blocked call if state change successful
ForwardReference fr = asm.emitForwardBC(EQ);
blocked.resolve(asm);
// if not IN_JNI call RVMThread.leaveJNIBlockedFromCallIntoNative
// T1 gets address of function
asm.emitLAddrOffset(T1, JTOC, Entrypoints.leaveJNIBlockedFromCallIntoNativeMethod.getOffset());
asm.emitMTLR(T1);
// call RVMThread.leaveJNIBlockedFromCallIntoNative
asm.emitBCLRL();
fr.resolve(asm);
// check if GC has occurred, If GC did not occur, then
// VM NON_VOLATILE regs were restored by OS and are valid. If GC did occur
// objects referenced by these restored regs may have moved, in this case we
// restore the nonvolatile registers from our save area,
// where any object references would have been relocated during GC.
// use T2 as scratch (not needed any more on return from call)
//
asm.emitLWZ(T2, frameSize - JNI_GC_FLAG_OFFSET, FP);
asm.emitCMPI(T2, 0);
ForwardReference fr1 = asm.emitForwardBC(EQ);
for (int i = LAST_NONVOLATILE_GPR.value(), offset = JNI_RVM_NONVOLATILE_OFFSET; i >= FIRST_NONVOLATILE_GPR.value(); --i, offset += BYTES_IN_STACKSLOT) {
asm.emitLAddr(GPR.lookup(i), frameSize - offset, FP);
}
fr1.resolve(asm);
// reestablish S0 to hold pointer to JNIEnvironment
asm.emitLAddrOffset(S0, THREAD_REGISTER, Entrypoints.jniEnvField.getOffset());
// pop jrefs frame off the JNIRefs stack, "reopen" the previous top jref frame
// use S1 as scratch, also use T2, T3 for scratch which are no longer needed
// load base of JNIRefs array
asm.emitLAddrOffset(S1, S0, Entrypoints.JNIRefsField.getOffset());
asm.emitLIntOffset(T2, S0, // get saved offset for JNIRefs frame ptr previously pushed onto JNIRefs array
Entrypoints.JNIRefsSavedFPField.getOffset());
// compute offset for new TOP
asm.emitADDI(T3, -BYTES_IN_STACKSLOT, T2);
// store new offset for TOP into JNIEnv
asm.emitSTWoffset(T3, S0, Entrypoints.JNIRefsTopField.getOffset());
// retrieve the previous frame ptr
asm.emitLIntX(T2, S1, T2);
asm.emitSTWoffset(T2, S0, // store new offset for JNIRefs frame ptr into JNIEnv
Entrypoints.JNIRefsSavedFPField.getOffset());
// Restore the return value R3-R4 saved in the glue frame spill area before the migration
if (VM.BuildFor64Addr) {
asm.emitLD(T0, NATIVE_FRAME_HEADER_SIZE, FP);
} else {
asm.emitLWZ(T0, NATIVE_FRAME_HEADER_SIZE, FP);
asm.emitLWZ(T1, NATIVE_FRAME_HEADER_SIZE + BYTES_IN_STACKSLOT, FP);
}
// if the the return type is a reference, the native C is returning a jref
// which is a byte offset from the beginning of the threads JNIRefs stack/array
// of the corresponding ref. In this case, emit code to replace the returned
// offset (in R3) with the ref from the JNIRefs array
TypeReference returnType = method.getReturnType();
if (returnType.isReferenceType()) {
asm.emitCMPI(T0, 0);
ForwardReference globalRef = asm.emitForwardBC(LT);
// Local ref - load from JNIRefs
// S1 is still the base of the JNIRefs array
asm.emitLAddrX(T0, S1, T0);
ForwardReference afterGlobalRef = asm.emitForwardB();
// Deal with global references
globalRef.resolve(asm);
asm.emitLVAL(T3, JNIGlobalRefTable.STRONG_REF_BIT);
asm.emitAND(T1, T0, T3);
asm.emitLAddrOffset(T2, JTOC, Entrypoints.JNIGlobalRefsField.getOffset());
asm.emitCMPI(T1, 0);
ForwardReference weakGlobalRef = asm.emitForwardBC(EQ);
// Strong global references
asm.emitNEG(T0, T0);
// convert index to offset
asm.emitSLWI(T0, T0, LOG_BYTES_IN_ADDRESS);
asm.emitLAddrX(T0, T2, T0);
ForwardReference afterWeakGlobalRef = asm.emitForwardB();
// Weak global references
weakGlobalRef.resolve(asm);
// STRONG_REF_BIT
asm.emitOR(T0, T0, T3);
asm.emitNEG(T0, T0);
// convert index to offset
asm.emitSLWI(T0, T0, LOG_BYTES_IN_ADDRESS);
asm.emitLAddrX(T0, T2, T0);
asm.emitLAddrOffset(T0, T0, Entrypoints.referenceReferentField.getOffset());
afterWeakGlobalRef.resolve(asm);
afterGlobalRef.resolve(asm);
}
// pop the whole stack frame (main & mini), restore the Java caller frame
asm.emitADDI(FP, +frameSize, FP);
// C return value is already where caller expected it (T0/T1 or F0)
// So, just restore the return address to the link register.
asm.emitLAddr(REGISTER_ZERO, STACKFRAME_RETURN_ADDRESS_OFFSET.toInt(), FP);
// restore return address
asm.emitMTLR(REGISTER_ZERO);
// CHECK EXCEPTION AND BRANCH TO ATHROW CODE OR RETURN NORMALLY
asm.emitLIntOffset(T2, S0, Entrypoints.JNIHasPendingExceptionField.getOffset());
// get a zero value to compare
asm.emitLVAL(T3, 0);
asm.emitCMP(T2, T3);
ForwardReference fr3 = asm.emitForwardBC(NE);
// if no pending exception, proceed to return to caller
asm.emitBCLR();
fr3.resolve(asm);
// T1 gets address of function
asm.emitLAddrToc(T1, Entrypoints.jniThrowPendingException.getOffset());
// point LR to the exception delivery code
asm.emitMTCTR(T1);
// then branch to the exception delivery code, does not return
asm.emitBCCTR();
cm.compileComplete(asm.getMachineCodes());
return cm;
}
use of org.jikesrvm.classloader.TypeReference in project JikesRVM by JikesRVM.
the class JNIHelpers method pushVarArgToSpillArea.
/**
* 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 = // *.ppc.JNIHelpers.invoke*
Magic.getFramePointer().plus(StackFrameLayout.getStackFramePointerOffset()).loadAddress();
// architecture.JNIHelpers.invoke*
gluefp = gluefp.plus(StackFrameLayout.getStackFramePointerOffset()).loadAddress();
// JNIFunctions
gluefp = gluefp.plus(StackFrameLayout.getStackFramePointerOffset()).loadAddress();
// glue frame
gluefp = gluefp.plus(StackFrameLayout.getStackFramePointerOffset()).loadAddress();
// 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);
}
}
// return the address of the beginning of the vararg to use in invoking the target method
return varargAddress;
}
use of org.jikesrvm.classloader.TypeReference in project JikesRVM by JikesRVM.
the class JNIGenericHelpers method callMethod.
/**
* Dispatch method call
* @param obj this pointer for method to be invoked, or null if method is static
* @param mr reference to method to be invoked
* @param args argument array
* @param expectedReturnType a type reference for the expected return type
* @param nonVirtual should invocation be of the given method or should we use virtual dispatch on the object?
* @return return value of the method (boxed if primitive)
* @throws InvocationTargetException when the reflective method call fails
*/
protected static Object callMethod(Object obj, MethodReference mr, Object[] args, TypeReference expectedReturnType, boolean nonVirtual) throws InvocationTargetException {
RVMMethod targetMethod = mr.resolve();
TypeReference returnType = targetMethod.getReturnType();
if (JNIFunctions.traceJNI) {
VM.sysWriteln("JNI CallXXXMethod: " + mr);
}
if (expectedReturnType == null) {
// for reference return type
if (!returnType.isReferenceType()) {
throw new IllegalArgumentException("Wrong return type for method (" + targetMethod + "): expected reference type instead of " + returnType);
}
} else {
// for primitive return type
if (!returnType.definitelySame(expectedReturnType)) {
throw new IllegalArgumentException("Wrong return type for method (" + targetMethod + "): expected " + expectedReturnType + " instead of " + returnType);
}
}
// invoke the method
return Reflection.invoke(targetMethod, null, obj, args, nonVirtual);
}
use of org.jikesrvm.classloader.TypeReference in project JikesRVM by JikesRVM.
the class JNIGenericHelpers method packageParametersFromJValuePtr.
/**
* Repackage the arguments passed as an array of jvalue into an array of Object,
* used by the JNI functions CallStatic<type>MethodA
* @param targetMethod the target {@link MethodReference}
* @param argAddress an address into the C space for the array of jvalue unions
* @return an Object array holding the arguments wrapped at Objects
*/
protected static Object[] packageParametersFromJValuePtr(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();
Address addr = argAddress;
for (int i = 0; i < argCount; i++, addr = addr.plus(BYTES_IN_LONG)) {
// convert and wrap the argument according to the expected type
if (argTypes[i].isReferenceType()) {
// Avoid endianness issues by loading the whole slot
Word wholeSlot = addr.loadWord();
// for object, the arg is a JREF index, dereference to get the real object
int JREFindex = wholeSlot.toInt();
argObjectArray[i] = env.getJNIRef(JREFindex);
} else if (argTypes[i].isIntType()) {
argObjectArray[i] = addr.loadInt();
} else if (argTypes[i].isLongType()) {
argObjectArray[i] = addr.loadLong();
} else if (argTypes[i].isBooleanType()) {
// the 0/1 bit is stored in the high byte
argObjectArray[i] = addr.loadByte() != 0;
} else if (argTypes[i].isByteType()) {
// the target byte is stored in the high byte
argObjectArray[i] = addr.loadByte();
} else if (argTypes[i].isCharType()) {
// char is stored in the high 2 bytes
argObjectArray[i] = addr.loadChar();
} else if (argTypes[i].isShortType()) {
// short is stored in the high 2 bytes
argObjectArray[i] = addr.loadShort();
} else if (argTypes[i].isFloatType()) {
argObjectArray[i] = addr.loadFloat();
} else {
if (VM.VerifyAssertions)
VM._assert(argTypes[i].isDoubleType());
argObjectArray[i] = addr.loadDouble();
}
}
return argObjectArray;
}
Aggregations