Search in sources :

Example 1 with FunctionTable

use of org.jikesrvm.jni.FunctionTable in project JikesRVM by JikesRVM.

the class BuildJNIFunctionTable method buildTable.

/**
 * Construct the JNIFuntionTable.
 * This is not very efficient, but is done at bootImageWriting time,
 * so we just don't worry about it.
 */
public static FunctionTable buildTable() {
    String[] names = initNames();
    FunctionTable functions = FunctionTable.allocate(JNIFunctions.FUNCTIONCOUNT);
    RVMClass cls = TypeReference.JNIFunctions.peekType().asClass();
    if (VM.VerifyAssertions)
        VM._assert(cls.isInstantiated());
    for (RVMMethod mth : cls.getDeclaredMethods()) {
        String methodName = mth.getName().toString();
        int jniIndex = indexOf(names, methodName);
        if (jniIndex != -1) {
            functions.set(jniIndex, mth.getCurrentEntryCodeArray());
        }
    }
    return functions;
}
Also used : RVMMethod(org.jikesrvm.classloader.RVMMethod) FunctionTable(org.jikesrvm.jni.FunctionTable) RVMClass(org.jikesrvm.classloader.RVMClass)

Example 2 with FunctionTable

use of org.jikesrvm.jni.FunctionTable in project JikesRVM by JikesRVM.

the class BootImageWriter method createBootImageObjects.

/**
 * Create (in host JDK address space) the RVM objects that will be
 * needed at run time to execute enough of the virtual machine
 * to dynamically load and compile the remainder of itself.<p>
 *
 * Side effects:
 * <ul>
 *   <li>RVM objects are created in host JDK address space
 *   <li>Statics is populated
 *   <li>"bootImageTypes" dictionary is populated with name/type pairs
 * </ul>
 *
 * @param typeNames names of RVM classes whose static fields will contain
 *                  the objects comprising the virtual machine bootimage
 */
public static void createBootImageObjects(Vector<String> typeNames, String bootImageTypeNamesFile) throws IllegalAccessException {
    Callbacks.notifyBootImage(typeNames.elements());
    long startTime = 0;
    long stopTime = 0;
    // 
    if (verbosity.isAtLeast(SUMMARY))
        say("loading");
    if (profile)
        startTime = System.currentTimeMillis();
    for (String typeName : typeNames) {
        // 
        if (verbosity.isAtLeast(TYPE_NAMES))
            say("typeName:", typeName);
        // 
        // create corresponding rvm type
        // 
        RVMType type;
        try {
            TypeReference tRef = TypeReference.findOrCreate(typeName);
            type = tRef.resolve();
        } catch (NoClassDefFoundError ncdf) {
            ncdf.printStackTrace(System.out);
            fail(bootImageTypeNamesFile + " contains a class named \"" + typeName + "\", but we can't find a class with that name: " + ncdf);
            // NOTREACHED
            return;
        } catch (IllegalArgumentException ila) {
            /* We should've caught any illegal type names at the data validation
           * stage, when we read these in.  If not, though,
           * TypeReference.findOrCreate() will do its own sanity check.  */
            ila.printStackTrace(System.out);
            fail(bootImageTypeNamesFile + " is supposed to contain type names.  It contains \"" + typeName + "\", which does not parse as a legal type name: " + ila);
            // NOTREACHED
            return;
        }
        type.markAsBootImageClass();
        // 
        // convert type name from internal form to external form
        // ie:    Ljava/lang/Object;   -->     java.lang.Object
        // [Ljava/lang/Object;   -->   [Ljava.lang.Object;
        // 
        // NOTE: duplicate functionality.  There is a method that does the same.
        // 
        typeName = typeName.replace('/', '.');
        if (typeName.startsWith("L"))
            typeName = typeName.substring(1, typeName.length() - 1);
        // 
        // record name/type pair for later lookup by getRvmType()
        // 
        bootImageTypes.put(typeName, type);
    }
    if (profile) {
        stopTime = System.currentTimeMillis();
        System.out.println("PROF: \tloading types " + (stopTime - startTime) + " ms");
    }
    int typeCount = bootImageTypes.size();
    JMXSupport.CLASS_LOADING_JMX_SUPPORT.setClassLoadedCountForBootimage(typeCount);
    if (verbosity.isAtLeast(SUMMARY))
        say(String.valueOf(typeCount), " types");
    // 
    if (profile)
        startTime = System.currentTimeMillis();
    if (verbosity.isAtLeast(SUMMARY))
        say("resolving");
    for (RVMType type : bootImageTypes.values()) {
        if (verbosity.isAtLeast(DETAILED))
            say("resolving " + type);
        // The resolution is supposed to be cached already.
        type.resolve();
    }
    // 
    for (RVMType type : bootImageTypes.values()) {
        type.allBootImageTypesResolved();
    }
    if (profile) {
        stopTime = System.currentTimeMillis();
        System.out.println("PROF: \tresolving types " + (stopTime - startTime) + " ms");
    }
    // Set tocRegister early so opt compiler can access it to
    // perform fixed_jtoc optimization (compile static addresses into code).
    // In the boot image, the bootrecord comes first followed by a
    // Address array and then the TOC.  To do this, we must fully
    // simulate the alignment logic in the allocation code!  Rather
    // than replicate the allocation code here, we perform dummy
    // allocations and then reset the boot image allocator.
    BootRecord bootRecord = BootRecord.the_boot_record;
    RVMClass rvmBRType = getRvmType(bootRecord.getClass()).asClass();
    RVMArray intArrayType = RVMArray.IntArray;
    // allocate storage for boot record
    bootImage.allocateDataStorage(rvmBRType.getInstanceSize(), ObjectModel.getAlignment(rvmBRType), ObjectModel.getOffsetForAlignment(rvmBRType, false));
    // allocate storage for JTOC (force 16byte alignment of the JTOC on Intel)
    Address jtocAddress = bootImage.allocateDataStorage(intArrayType.getInstanceSize(0), VM.BuildForIA32 ? 16 : ObjectModel.getAlignment(intArrayType), ObjectModel.getOffsetForAlignment(intArrayType, false));
    bootImage.resetAllocator();
    bootRecord.tocRegister = jtocAddress.plus(intArrayType.getInstanceSize(Statics.middleOfTable));
    // set up some stuff we need for compiling
    ArchitectureFactory.initOutOfLineMachineCode();
    // 
    if (profile)
        startTime = System.currentTimeMillis();
    if (verbosity.isAtLeast(SUMMARY))
        say("instantiating");
    if (verbosity.isAtLeast(SUMMARY))
        say("setting up compilation infrastructure and pre-compiling easy cases");
    CompilationOrder order = new CompilationOrder(typeCount, numThreads);
    for (RVMType type : bootImageTypes.values()) {
        order.addType(type);
    }
    order.fixUpMissingSuperClasses();
    if (verbosity.isAtLeast(SUMMARY))
        say(" compiling with " + numThreads + " threads");
    ThreadFactory threadFactory = new KillVMonUncaughtExceptionThreadFactory();
    ExecutorService threadPool = Executors.newFixedThreadPool(numThreads, threadFactory);
    int runnableCount = order.getCountOfNeededWorkers();
    while (runnableCount > 0) {
        try {
            threadPool.execute(order.getNextRunnable());
            runnableCount--;
        } catch (InterruptedException e) {
            throw new Error("Build interrupted", e);
        }
    }
    threadPool.shutdown();
    try {
        while (!threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS)) {
            say("Compilation really shouldn't take this long");
        }
    } catch (InterruptedException e) {
        throw new Error("Build interrupted", e);
    }
    if (BootImageWorker.instantiationFailed) {
        throw new Error("Error during instantiaion");
    }
    if (profile) {
        stopTime = System.currentTimeMillis();
        System.out.println("PROF: \tinstantiating types " + (stopTime - startTime) + " ms");
    }
    // Free up unnecessary Statics data structures
    staticsJunk = Statics.bootImageInstantiationFinished();
    // Do the portion of JNIEnvironment initialization that can be done
    // at bootimage writing time.
    FunctionTable functionTable = BuildJNIFunctionTable.buildTable();
    JNIEnvironment.initFunctionTable(functionTable);
    // 
    if (verbosity.isAtLeast(SUMMARY))
        say("field info gathering");
    if (profile)
        startTime = System.currentTimeMillis();
    bootImageTypeFields = new HashMap<Key, FieldInfo>(typeCount);
    HashSet<String> invalidEntrys = new HashSet<String>();
    // First retrieve the jdk Field table for each class of interest
    for (RVMType rvmType : bootImageTypes.values()) {
        FieldInfo fieldInfo;
        if (!rvmType.isClassType())
            // arrays and primitives have no static or instance fields
            continue;
        Class<?> jdkType = getJdkType(rvmType);
        if (jdkType == null)
            // won't need the field info
            continue;
        Key key = new Key(jdkType);
        fieldInfo = bootImageTypeFields.get(key);
        if (fieldInfo != null) {
            fieldInfo.rvmType = rvmType;
        } else {
            if (verbosity.isAtLeast(SUMMARY))
                say("making fieldinfo for " + rvmType);
            fieldInfo = new FieldInfo(jdkType, rvmType);
            bootImageTypeFields.put(key, fieldInfo);
            // Can't add them in next loop as Iterator's don't allow updates to collection
            for (Class<?> cls = jdkType.getSuperclass(); cls != null; cls = cls.getSuperclass()) {
                key = new Key(cls);
                fieldInfo = bootImageTypeFields.get(key);
                if (fieldInfo != null) {
                    break;
                } else {
                    if (verbosity.isAtLeast(SUMMARY))
                        say("making fieldinfo for " + jdkType);
                    fieldInfo = new FieldInfo(cls, null);
                    bootImageTypeFields.put(key, fieldInfo);
                }
            }
        }
    }
    // Now build the one-to-one instance and static field maps
    for (FieldInfo fieldInfo : bootImageTypeFields.values()) {
        RVMType rvmType = fieldInfo.rvmType;
        if (rvmType == null) {
            if (verbosity.isAtLeast(SUMMARY))
                say("bootImageTypeField entry has no rvmType:" + fieldInfo.jdkType);
            continue;
        }
        Class<?> jdkType = fieldInfo.jdkType;
        if (verbosity.isAtLeast(SUMMARY))
            say("building static and instance fieldinfo for " + rvmType);
        // First the static fields
        // 
        RVMField[] rvmFields = rvmType.getStaticFields();
        fieldInfo.jdkStaticFields = new Field[rvmFields.length];
        for (int j = 0; j < rvmFields.length; j++) {
            String rvmName = rvmFields[j].getName().toString();
            for (Field f : fieldInfo.jdkFields) {
                if (f.getName().equals(rvmName)) {
                    fieldInfo.jdkStaticFields[j] = f;
                    f.setAccessible(true);
                    break;
                }
            }
        }
        // Now the instance fields
        // 
        rvmFields = rvmType.getInstanceFields();
        fieldInfo.jdkInstanceFields = new Field[rvmFields.length];
        for (int j = 0; j < rvmFields.length; j++) {
            String rvmName = rvmFields[j].getName().toString();
            // We look only in the JDK type that corresponds to the
            // RVMType of the field's declaring class.
            // This is the only way to correctly handle private fields.
            jdkType = getJdkType(rvmFields[j].getDeclaringClass());
            if (jdkType == null)
                continue;
            FieldInfo jdkFieldInfo = bootImageTypeFields.get(new Key(jdkType));
            if (jdkFieldInfo == null)
                continue;
            Field[] jdkFields = jdkFieldInfo.jdkFields;
            for (Field f : jdkFields) {
                if (f.getName().equals(rvmName)) {
                    fieldInfo.jdkInstanceFields[j] = f;
                    f.setAccessible(true);
                    break;
                }
            }
        }
    }
    if (profile) {
        stopTime = System.currentTimeMillis();
        System.out.println("PROF: \tcreating type mapping " + (stopTime - startTime) + " ms");
    }
    // 
    // Create stack, thread, and processor context in which rvm will begin
    // execution.
    startupThread = RVMThread.setupBootThread();
    byte[] stack = startupThread.getStack();
    // sanity check for bootstrap loader
    int idx = stack.length - 1;
    if (VM.LittleEndian) {
        stack[idx--] = (byte) 0xde;
        stack[idx--] = (byte) 0xad;
        stack[idx--] = (byte) 0xba;
        stack[idx--] = (byte) 0xbe;
    } else {
        stack[idx--] = (byte) 0xbe;
        stack[idx--] = (byte) 0xba;
        stack[idx--] = (byte) 0xad;
        stack[idx--] = (byte) 0xde;
    }
    // 
    // Tell RVM where to find itself at execution time.
    // This may not be the same place it was at build time, ie. if image is
    // moved to another machine with different directory structure.
    // 
    BootstrapClassLoader.setBootstrapRepositories(bootImageRepositoriesAtExecutionTime);
    // 
    if (verbosity.isAtLeast(SUMMARY))
        say("populating jtoc with static fields");
    if (profile)
        startTime = System.currentTimeMillis();
    for (RVMType rvmType : bootImageTypes.values()) {
        if (verbosity.isAtLeast(SUMMARY))
            say("  jtoc for ", rvmType.toString());
        if (!rvmType.isClassType())
            // arrays and primitives have no static fields
            continue;
        Class<?> jdkType = getJdkType(rvmType);
        if (jdkType == null && verbosity.isAtLeast(SUMMARY)) {
            say("host has no class \"" + rvmType + "\"");
        }
        RVMField[] rvmFields = rvmType.getStaticFields();
        for (int j = 0; j < rvmFields.length; ++j) {
            RVMField rvmField = rvmFields[j];
            TypeReference rvmFieldType = rvmField.getType();
            Offset rvmFieldOffset = rvmField.getOffset();
            String rvmFieldName = rvmField.getName().toString();
            Field jdkFieldAcc = null;
            if (jdkType != null && jdkType.equals(java.util.concurrent.locks.AbstractQueuedSynchronizer.class)) {
                RVMClass c = (RVMClass) rvmType;
                if (rvmFieldName.equals("stateOffset")) {
                    Statics.setSlotContents(rvmFieldOffset, c.findDeclaredField(Atom.findOrCreateAsciiAtom("state")).getOffset().toLong());
                    continue;
                } else if (rvmFieldName.equals("headOffset")) {
                    Statics.setSlotContents(rvmFieldOffset, c.findDeclaredField(Atom.findOrCreateAsciiAtom("head")).getOffset().toLong());
                    continue;
                } else if (rvmFieldName.equals("tailOffset")) {
                    Statics.setSlotContents(rvmFieldOffset, c.findDeclaredField(Atom.findOrCreateAsciiAtom("tail")).getOffset().toLong());
                    continue;
                } else if (rvmFieldName.equals("waitStatusOffset")) {
                    try {
                        Statics.setSlotContents(rvmFieldOffset, ((RVMClass) getRvmType(Class.forName("java.util.concurrent.locks.AbstractQueuedSynchronizer$Node"))).findDeclaredField(Atom.findOrCreateAsciiAtom("waitStatus")).getOffset().toLong());
                    } catch (ClassNotFoundException e) {
                        throw new Error(e);
                    }
                    continue;
                }
            } else if (jdkType != null && jdkType.equals(java.util.concurrent.locks.LockSupport.class)) {
                RVMClass c = (RVMClass) rvmType;
                if (rvmFieldName.equals("parkBlockerOffset")) {
                    Statics.setSlotContents(rvmFieldOffset, ((RVMClass) getRvmType(java.lang.Thread.class)).findDeclaredField(Atom.findOrCreateAsciiAtom("parkBlocker")).getOffset().toLong());
                    continue;
                }
            }
            if (jdkType != null)
                jdkFieldAcc = getJdkFieldAccessor(jdkType, j, STATIC_FIELD);
            if (jdkFieldAcc == null) {
                // we failed to get a reflective field accessors
                if (jdkType != null) {
                    // we know the type - probably a private field of a java.lang class
                    if (!copyKnownStaticField(jdkType, rvmFieldName, rvmFieldType, rvmFieldOffset)) {
                        // we didn't know the field so nullify
                        if (verbosity.isAtLeast(DETAILED)) {
                            traceContext.push(rvmFieldType.toString(), jdkType.getName(), rvmFieldName);
                            traceContext.traceFieldNotInHostJdk();
                            traceContext.pop();
                        }
                        Statics.setSlotContents(rvmFieldOffset, 0);
                        if (!VM.runningTool)
                            bootImage.countNulledReference();
                        invalidEntrys.add(jdkType.getName());
                    }
                } else {
                    // no accessor and we don't know the type so nullify
                    if (verbosity.isAtLeast(DETAILED)) {
                        traceContext.push(rvmFieldType.toString(), rvmFieldType.toString(), rvmFieldName);
                        traceContext.traceFieldNotInHostJdk();
                        traceContext.pop();
                    }
                    Statics.setSlotContents(rvmFieldOffset, 0);
                    if (!VM.runningTool)
                        bootImage.countNulledReference();
                    invalidEntrys.add(rvmField.getDeclaringClass().toString());
                }
                continue;
            }
            if (!Modifier.isStatic(jdkFieldAcc.getModifiers())) {
                if (verbosity.isAtLeast(DETAILED))
                    traceContext.push(rvmFieldType.toString(), jdkType.getName(), rvmFieldName);
                if (verbosity.isAtLeast(DETAILED))
                    traceContext.traceFieldNotStaticInHostJdk();
                if (verbosity.isAtLeast(DETAILED))
                    traceContext.pop();
                Statics.setSlotContents(rvmFieldOffset, 0);
                if (!VM.runningTool)
                    bootImage.countNulledReference();
                invalidEntrys.add(jdkType.getName());
                continue;
            }
            if (!equalTypes(jdkFieldAcc.getType().getName(), rvmFieldType)) {
                if (verbosity.isAtLeast(DETAILED))
                    traceContext.push(rvmFieldType.toString(), jdkType.getName(), rvmFieldName);
                if (verbosity.isAtLeast(DETAILED))
                    traceContext.traceFieldDifferentTypeInHostJdk();
                if (verbosity.isAtLeast(DETAILED))
                    traceContext.pop();
                Statics.setSlotContents(rvmFieldOffset, 0);
                if (!VM.runningTool)
                    bootImage.countNulledReference();
                invalidEntrys.add(jdkType.getName());
                continue;
            }
            if (verbosity.isAtLeast(DETAILED))
                say("    populating jtoc slot ", String.valueOf(Statics.offsetAsSlot(rvmFieldOffset)), " with ", rvmField.toString());
            if (rvmFieldType.isPrimitiveType()) {
                // field is logical or numeric type
                if (rvmFieldType.isBooleanType()) {
                    Statics.setSlotContents(rvmFieldOffset, jdkFieldAcc.getBoolean(null) ? 1 : 0);
                } else if (rvmFieldType.isByteType()) {
                    Statics.setSlotContents(rvmFieldOffset, jdkFieldAcc.getByte(null));
                } else if (rvmFieldType.isCharType()) {
                    Statics.setSlotContents(rvmFieldOffset, jdkFieldAcc.getChar(null));
                } else if (rvmFieldType.isShortType()) {
                    Statics.setSlotContents(rvmFieldOffset, jdkFieldAcc.getShort(null));
                } else if (rvmFieldType.isIntType()) {
                    Statics.setSlotContents(rvmFieldOffset, jdkFieldAcc.getInt(null));
                } else if (rvmFieldType.isLongType()) {
                    // note: Endian issues handled in setSlotContents.
                    Statics.setSlotContents(rvmFieldOffset, jdkFieldAcc.getLong(null));
                } else if (rvmFieldType.isFloatType()) {
                    float f = jdkFieldAcc.getFloat(null);
                    Statics.setSlotContents(rvmFieldOffset, Float.floatToIntBits(f));
                } else if (rvmFieldType.isDoubleType()) {
                    double d = jdkFieldAcc.getDouble(null);
                    // note: Endian issues handled in setSlotContents.
                    Statics.setSlotContents(rvmFieldOffset, Double.doubleToLongBits(d));
                } else if (rvmFieldType.equals(TypeReference.Address) || rvmFieldType.equals(TypeReference.Word) || rvmFieldType.equals(TypeReference.Extent) || rvmFieldType.equals(TypeReference.Offset)) {
                    Object o = jdkFieldAcc.get(null);
                    String msg = " static field " + rvmField.toString();
                    boolean warn = rvmFieldType.equals(TypeReference.Address);
                    Statics.setSlotContents(rvmFieldOffset, getWordValue(o, msg, warn));
                } else {
                    fail("unexpected primitive field type: " + rvmFieldType);
                }
            } else {
                // field is reference type
                final Object o = jdkFieldAcc.get(null);
                if (verbosity.isAtLeast(ADDRESSES))
                    say("       setting with ", Services.addressAsHexString(Magic.objectAsAddress(o)));
                Statics.setSlotContents(rvmFieldOffset, o);
            }
        }
    }
    if (verbosity.isAtLeast(DETAILED)) {
        for (final String entry : invalidEntrys) {
            say("Static fields of type are invalid: ", entry);
        }
    }
    if (profile) {
        stopTime = System.currentTimeMillis();
        System.out.println("PROF: \tinitializing jtoc " + (stopTime - startTime) + " ms");
    }
}
Also used : ThreadFactory(java.util.concurrent.ThreadFactory) Address(org.vmmagic.unboxed.Address) RVMType(org.jikesrvm.classloader.RVMType) RVMField(org.jikesrvm.classloader.RVMField) Field(java.lang.reflect.Field) FunctionTable(org.jikesrvm.jni.FunctionTable) RVMField(org.jikesrvm.classloader.RVMField) TypeReference(org.jikesrvm.classloader.TypeReference) HashSet(java.util.HashSet) RVMClass(org.jikesrvm.classloader.RVMClass) Offset(org.vmmagic.unboxed.Offset) RVMThread(org.jikesrvm.scheduler.RVMThread) RVMArray(org.jikesrvm.classloader.RVMArray) BootRecord(org.jikesrvm.runtime.BootRecord) ExecutorService(java.util.concurrent.ExecutorService)

Aggregations

RVMClass (org.jikesrvm.classloader.RVMClass)2 FunctionTable (org.jikesrvm.jni.FunctionTable)2 Field (java.lang.reflect.Field)1 HashSet (java.util.HashSet)1 ExecutorService (java.util.concurrent.ExecutorService)1 ThreadFactory (java.util.concurrent.ThreadFactory)1 RVMArray (org.jikesrvm.classloader.RVMArray)1 RVMField (org.jikesrvm.classloader.RVMField)1 RVMMethod (org.jikesrvm.classloader.RVMMethod)1 RVMType (org.jikesrvm.classloader.RVMType)1 TypeReference (org.jikesrvm.classloader.TypeReference)1 BootRecord (org.jikesrvm.runtime.BootRecord)1 RVMThread (org.jikesrvm.scheduler.RVMThread)1 Address (org.vmmagic.unboxed.Address)1 Offset (org.vmmagic.unboxed.Offset)1