Search in sources :

Example 11 with TypeReference

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);
}
Also used : RVMMethod(org.jikesrvm.classloader.RVMMethod) Address(org.vmmagic.unboxed.Address) MemberReference(org.jikesrvm.classloader.MemberReference) MethodReference(org.jikesrvm.classloader.MethodReference) TypeReference(org.jikesrvm.classloader.TypeReference)

Example 12 with TypeReference

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;
}
Also used : ForwardReference(org.jikesrvm.compilers.common.assembler.ForwardReference) Address(org.vmmagic.unboxed.Address) Assembler(org.jikesrvm.compilers.common.assembler.ppc.Assembler) TypeReference(org.jikesrvm.classloader.TypeReference) JNICompiledMethod(org.jikesrvm.jni.JNICompiledMethod) RVMClass(org.jikesrvm.classloader.RVMClass)

Example 13 with TypeReference

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;
}
Also used : RVMMethod(org.jikesrvm.classloader.RVMMethod) Word(org.vmmagic.unboxed.Word) Address(org.vmmagic.unboxed.Address) TypeReference(org.jikesrvm.classloader.TypeReference) Offset(org.vmmagic.unboxed.Offset) NoInline(org.vmmagic.pragma.NoInline)

Example 14 with TypeReference

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);
}
Also used : RVMMethod(org.jikesrvm.classloader.RVMMethod) TypeReference(org.jikesrvm.classloader.TypeReference)

Example 15 with TypeReference

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&lt;type&gt;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;
}
Also used : Word(org.vmmagic.unboxed.Word) Address(org.vmmagic.unboxed.Address) TypeReference(org.jikesrvm.classloader.TypeReference)

Aggregations

TypeReference (org.jikesrvm.classloader.TypeReference)164 RegisterOperand (org.jikesrvm.compilers.opt.ir.operand.RegisterOperand)58 Operand (org.jikesrvm.compilers.opt.ir.operand.Operand)43 Instruction (org.jikesrvm.compilers.opt.ir.Instruction)38 MethodOperand (org.jikesrvm.compilers.opt.ir.operand.MethodOperand)30 BranchProfileOperand (org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand)28 TrueGuardOperand (org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand)27 IntConstantOperand (org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand)25 ConditionOperand (org.jikesrvm.compilers.opt.ir.operand.ConditionOperand)24 RVMClass (org.jikesrvm.classloader.RVMClass)23 RVMField (org.jikesrvm.classloader.RVMField)21 Register (org.jikesrvm.compilers.opt.ir.Register)21 LocationOperand (org.jikesrvm.compilers.opt.ir.operand.LocationOperand)21 NullConstantOperand (org.jikesrvm.compilers.opt.ir.operand.NullConstantOperand)21 Address (org.vmmagic.unboxed.Address)21 RVMType (org.jikesrvm.classloader.RVMType)18 BasicBlock (org.jikesrvm.compilers.opt.ir.BasicBlock)18 AddressConstantOperand (org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand)18 TrapCodeOperand (org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand)18 RVMMethod (org.jikesrvm.classloader.RVMMethod)17