Search in sources :

Example 11 with RVMMethod

use of org.jikesrvm.classloader.RVMMethod 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 RVMMethod

use of org.jikesrvm.classloader.RVMMethod 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 13 with RVMMethod

use of org.jikesrvm.classloader.RVMMethod in project JikesRVM by JikesRVM.

the class JNIFunctions method RegisterNatives.

/**
 * RegisterNatives: registers implementation of native methods
 * @param env A JREF index for the JNI environment object
 * @param classJREF a JREF index for the class to register native methods in
 * @param methodsAddress the address of an array of native methods to be registered
 * @param nmethods the number of native methods in the array
 * @return 0 is successful -1 if failed
 * @throws NoSuchMethodError if a specified method cannot be found or is not native
 */
private static int RegisterNatives(JNIEnvironment env, int classJREF, Address methodsAddress, int nmethods) {
    if (traceJNI)
        VM.sysWriteln("JNI called: RegisterNatives");
    RuntimeEntrypoints.checkJNICountDownToGC();
    try {
        // get the target class
        Class<?> jcls = (Class<?>) env.getJNIRef(classJREF);
        RVMType type = java.lang.JikesRVMSupport.getTypeForClass(jcls);
        if (!type.isClassType()) {
            env.recordException(new NoSuchMethodError());
            return 0;
        }
        RVMClass klass = type.asClass();
        if (!klass.isInitialized()) {
            RuntimeEntrypoints.initializeClassForDynamicLink(klass);
        }
        // Create list of methods and verify them to avoid partial success
        NativeMethod[] methods = new NativeMethod[nmethods];
        AddressArray symbols = AddressArray.create(nmethods);
        Address curMethod = methodsAddress;
        for (int i = 0; i < nmethods; i++) {
            String methodString = JNIGenericHelpers.createStringFromC(curMethod.loadAddress());
            Atom methodName = Atom.findOrCreateAsciiAtom(methodString);
            String sigString = JNIGenericHelpers.createStringFromC(curMethod.loadAddress(Offset.fromIntSignExtend(BYTES_IN_ADDRESS)));
            Atom sigName = Atom.findOrCreateAsciiAtom(sigString);
            // Find the target method
            RVMMethod meth = klass.findDeclaredMethod(methodName, sigName);
            if (meth == null || !meth.isNative()) {
                env.recordException(new NoSuchMethodError(klass + ": " + methodName + " " + sigName));
                return -1;
            }
            methods[i] = (NativeMethod) meth;
            symbols.set(i, curMethod.loadAddress(Offset.fromIntSignExtend(BYTES_IN_ADDRESS * 2)));
            curMethod = curMethod.plus(3 * BYTES_IN_ADDRESS);
        }
        // Register methods
        for (int i = 0; i < nmethods; i++) {
            methods[i].registerNativeSymbol(symbols.get(i));
        }
        return 0;
    } catch (Throwable unexpected) {
        if (traceJNI)
            unexpected.printStackTrace(System.err);
        env.recordException(unexpected);
        return -1;
    }
}
Also used : AddressArray(org.vmmagic.unboxed.AddressArray) Address(org.vmmagic.unboxed.Address) RVMType(org.jikesrvm.classloader.RVMType) Atom(org.jikesrvm.classloader.Atom) RVMClass(org.jikesrvm.classloader.RVMClass) RVMMethod(org.jikesrvm.classloader.RVMMethod) NativeMethod(org.jikesrvm.classloader.NativeMethod) RVMClass(org.jikesrvm.classloader.RVMClass)

Example 14 with RVMMethod

use of org.jikesrvm.classloader.RVMMethod in project JikesRVM by JikesRVM.

the class JNIFunctions method GetStaticMethodID.

/**
 * GetStaticMethodID:  return the method ID for invocation later
 * @param env A JREF index for the JNI environment object
 * @param classJREF a JREF index for the class object
 * @param methodNameAddress a raw address to a null-terminated string in C for the method name
 * @param methodSigAddress a raw address to a null-terminated string in C for (TODO: document me)
 * @return a method ID or null if it fails
 * @throws NoSuchMethodError if the method is not found
 * @throws ExceptionInInitializerError if the initializer fails
 * @throws OutOfMemoryError if the system runs out of memory
 */
private static int GetStaticMethodID(JNIEnvironment env, int classJREF, Address methodNameAddress, Address methodSigAddress) {
    if (traceJNI)
        VM.sysWriteln("JNI called: GetStaticMethodID");
    RuntimeEntrypoints.checkJNICountDownToGC();
    try {
        // obtain the names as String from the native space
        String methodString = JNIGenericHelpers.createStringFromC(methodNameAddress);
        Atom methodName = Atom.findOrCreateAsciiAtom(methodString);
        String sigString = JNIGenericHelpers.createStringFromC(methodSigAddress);
        Atom sigName = Atom.findOrCreateAsciiAtom(sigString);
        // get the target class
        Class<?> jcls = (Class<?>) env.getJNIRef(classJREF);
        RVMType type = java.lang.JikesRVMSupport.getTypeForClass(jcls);
        if (!type.isClassType()) {
            env.recordException(new NoSuchMethodError());
            return 0;
        }
        RVMClass klass = type.asClass();
        if (!klass.isInitialized()) {
            RuntimeEntrypoints.initializeClassForDynamicLink(klass);
        }
        // Find the target method
        RVMMethod meth = klass.findStaticMethod(methodName, sigName);
        if (meth == null) {
            env.recordException(new NoSuchMethodError());
            return 0;
        }
        if (traceJNI)
            VM.sysWriteln("got method " + meth);
        return meth.getId();
    } catch (Throwable unexpected) {
        if (traceJNI)
            unexpected.printStackTrace(System.err);
        env.recordException(unexpected);
        return 0;
    }
}
Also used : RVMMethod(org.jikesrvm.classloader.RVMMethod) RVMType(org.jikesrvm.classloader.RVMType) RVMClass(org.jikesrvm.classloader.RVMClass) Atom(org.jikesrvm.classloader.Atom) RVMClass(org.jikesrvm.classloader.RVMClass)

Example 15 with RVMMethod

use of org.jikesrvm.classloader.RVMMethod in project JikesRVM by JikesRVM.

the class JNIFunctions method ToReflectedMethod.

/**
 * ToReflectedMethod
 * @param env A JREF index for the JNI environment object
 * @param clsJREF The JREF index of the class from which methodID was
 * derived.
 * @param methodID a jmethodID to turn into a reflected method
 * @param isStatic argument that is not specified in Sun's JNI 1.2 spec,
 *            but IS present in the 1.4.2 JDK's implementation!  Our
 *            implementation will just ignore it, in any case.  This is a
 *            good example of why the same entity
 *            shouldn't get to write both the spec and the reference
 *            implementation.
 * @return a JREF index for the java.lang.reflect.Method or
 * java.lang.reflect.Constructor object associated with methodID.
 */
private static int ToReflectedMethod(JNIEnvironment env, int clsJREF, int methodID, boolean isStatic) {
    if (traceJNI)
        VM.sysWriteln("JNI called: ToReflectedMethod");
    RuntimeEntrypoints.checkJNICountDownToGC();
    RVMMethod targetMethod = MemberReference.getMethodRef(methodID).resolve();
    Object ret;
    if (targetMethod.isObjectInitializer()) {
        ret = java.lang.reflect.JikesRVMSupport.createConstructor(targetMethod);
    } else {
        ret = java.lang.reflect.JikesRVMSupport.createMethod(targetMethod);
    }
    return env.pushJNIRef(ret);
}
Also used : RVMMethod(org.jikesrvm.classloader.RVMMethod)

Aggregations

RVMMethod (org.jikesrvm.classloader.RVMMethod)86 RVMClass (org.jikesrvm.classloader.RVMClass)29 TypeReference (org.jikesrvm.classloader.TypeReference)17 RVMType (org.jikesrvm.classloader.RVMType)15 CompiledMethod (org.jikesrvm.compilers.common.CompiledMethod)14 MethodOperand (org.jikesrvm.compilers.opt.ir.operand.MethodOperand)13 Atom (org.jikesrvm.classloader.Atom)11 RegisterOperand (org.jikesrvm.compilers.opt.ir.operand.RegisterOperand)11 Offset (org.vmmagic.unboxed.Offset)11 Instruction (org.jikesrvm.compilers.opt.ir.Instruction)10 Operand (org.jikesrvm.compilers.opt.ir.operand.Operand)10 Address (org.vmmagic.unboxed.Address)9 MethodReference (org.jikesrvm.classloader.MethodReference)8 NormalMethod (org.jikesrvm.classloader.NormalMethod)8 BranchProfileOperand (org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand)8 IntConstantOperand (org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand)8 Method (java.lang.reflect.Method)7 ConditionOperand (org.jikesrvm.compilers.opt.ir.operand.ConditionOperand)7 TrapCodeOperand (org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand)7 OptCompiledMethod (org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod)7