/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.tools.header_gen; import static org.jikesrvm.objectmodel.ThinLockConstants.TL_THREAD_ID_SHIFT; import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_BAD_WORKING_DIR; import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG; import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_COULD_NOT_EXECUTE; import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_DYING_WITH_UNCAUGHT_EXCEPTION; import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_EXECUTABLE_NOT_FOUND; import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_IMPOSSIBLE_LIBRARY_FUNCTION_ERROR; import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_JNI_TROUBLE; import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_MISC_TROUBLE; import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_SYSCALL_TROUBLE; import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_TIMER_TROUBLE; import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_UNEXPECTED_CALL_TO_SYS; import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_UNSUPPORTED_INTERNAL_OP; import static org.jikesrvm.util.Services.unboxedValueString; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.util.Arrays; import org.jikesrvm.HeapLayoutConstants; import org.jikesrvm.VM; import org.jikesrvm.architecture.StackFrameLayout; import org.jikesrvm.classloader.RVMClass; import org.jikesrvm.classloader.RVMField; import org.jikesrvm.classloader.TypeReference; import org.jikesrvm.objectmodel.ObjectModel; import org.jikesrvm.runtime.ArchEntrypoints; import org.jikesrvm.runtime.Entrypoints; import org.jikesrvm.runtime.RuntimeEntrypoints; import org.jikesrvm.scheduler.RVMThread; import org.jikesrvm.util.Services; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Offset; /** * Emit a header file containing declarations required to access VM * data structures from C. */ public class GenerateInterfaceDeclarations { static PrintStream out; static final GenArch arch; static { GenArch tmp = null; try { tmp = (GenArch) Class.forName(VM.BuildForIA32 ? "org.jikesrvm.tools.header_gen.GenArch_ia32" : "org.jikesrvm.tools.header_gen.GenArch_ppc").newInstance(); } catch (Exception e) { e.printStackTrace(); System.exit(EXIT_STATUS_MISC_TROUBLE); // we must *not* go on if the above has failed } arch = tmp; } static void p(String s) { out.print(s); } static void p(String s, Offset off) { if (VM.BuildFor64Addr) { out.print(s + off.toLong()); } else { out.print(s + Services.addressAsHexString(off.toWord().toAddress())); } } static void pln(String s) { out.println(s); } static void pln(String s, int i) { out.println("#define " + s + " 0x" + Integer.toHexString(i)); } static void pln(String s, Address addr) { out.println("#define " + s + " ((Address)" + Services.addressAsHexString(addr) + ")"); } static void pln(String s, Offset off) { out.println("#define " + s + " ((Offset)" + Services.addressAsHexString(off.toWord().toAddress()) + ")"); } static void pln() { out.println(); } GenerateInterfaceDeclarations() { } protected static final long bootImageDataAddress = HeapLayoutConstants.BOOT_IMAGE_DATA_START.toLong(); protected static final long bootImageCodeAddress = HeapLayoutConstants.BOOT_IMAGE_CODE_START.toLong(); protected static final long bootImageRMapAddress = HeapLayoutConstants.BOOT_IMAGE_RMAP_START.toLong(); static String outFileName; public static void main(String[] args) throws Exception { // Process command line directives. // for (int i = 0, n = args.length; i < n; ++i) { if (args[i].equals("-out")) { // output file if (++i == args.length) { System.err.println("Error: The -out flag requires an argument"); System.exit(EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); } outFileName = args[i]; continue; } System.err.println("Error: unrecognized command line argument: " + args[i]); System.exit(EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); } if (outFileName == null) { out = System.out; } else { try { // We'll let an unhandled exception throw an I/O error for us. out = new PrintStream(new FileOutputStream(outFileName)); } catch (IOException e) { reportTrouble("Caught an exception while opening" + outFileName + " for writing: " + e.toString()); } } VM.initForTool(); emitStuff(); if (out.checkError()) { reportTrouble("an output error happened"); } // try { out.close(); // exception thrown up. // } catch (IOException e) { // reportTrouble("An output error when closing the output: " + e.toString()); // } System.exit(0); } private static void reportTrouble(String msg) { System.err.println( "org.jikesrvm.tools.header_gen.GenerateInterfaceDeclarations: While we were creating InterfaceDeclarations.h, there was a problem."); System.err.println(msg); System.err.print("The build system will delete the output file"); if (outFileName != null) { System.err.print(' '); System.err.print(outFileName); } System.err.println(); System.exit(1); } private static void emitStuff() { p("/*------ MACHINE GENERATED by "); p("org.jikesrvm.tools.header_gen.GenerateInterfaceDeclarations.java: DO NOT EDIT"); pln("------*/"); pln(); if (VM.PortableNativeSync) { pln("#define PORTABLE_NATIVE_SYNC 1"); pln(); } pln("#ifdef NEED_BOOT_RECORD_DECLARATIONS"); emitBootRecordDeclarations(); pln("#endif /* NEED_BOOT_RECORD_DECLARATIONS */"); pln(); pln("#ifdef NEED_BOOT_RECORD_INITIALIZATION"); emitBootRecordInitialization(); pln("#endif /* NEED_BOOT_RECORD_INITIALIZATION */"); pln(); pln("#ifdef NEED_VIRTUAL_MACHINE_DECLARATIONS"); emitVirtualMachineDeclarations(bootImageDataAddress, bootImageCodeAddress, bootImageRMapAddress); pln("#endif /* NEED_VIRTUAL_MACHINE_DECLARATIONS */"); pln(); pln("#ifdef NEED_EXIT_STATUS_CODES"); emitExitStatusCodes(); pln("#endif /* NEED_EXIT_STATUS_CODES */"); pln(); pln("#ifdef NEED_ASSEMBLER_DECLARATIONS"); emitAssemblerDeclarations(); pln("#endif /* NEED_ASSEMBLER_DECLARATIONS */"); pln("#ifdef NEED_MEMORY_MANAGER_DECLARATIONS"); pln("#define MAXHEAPS " + org.jikesrvm.mm.mminterface.MemoryManager.getMaxHeaps()); pln("#endif /* NEED_MEMORY_MANAGER_DECLARATIONS */"); pln(); } static void emitCDeclarationsForJavaType(String Cname, RVMClass cls) { // How many instance fields are there? // RVMField[] allFields = cls.getDeclaredFields(); int fieldCount = 0; for (RVMField field : allFields) { if (!field.isStatic()) { fieldCount++; } } RVMField[] fields = new RVMField[fieldCount]; for (int i = 0, j = 0; i < allFields.length; i++) { if (!allFields[i].isStatic()) { fields[j++] = allFields[i]; } } Arrays.sort(fields, new AscendingOffsetComparator()); // Emit field declarations // pln("struct " + Cname + " {"); // Set up cursor - scalars will waste 4 bytes on 64-bit arch // boolean needsAlign = VM.BuildFor64Addr; int addrSize = VM.BuildFor32Addr ? 4 : 8; // Header Space for objects int startOffset = ObjectModel.objectStartOffset(cls); Offset current = Offset.fromIntSignExtend(startOffset); for (int i = 0; current.sLT(fields[0].getOffset()); i++) { pln(" uint32_t headerPadding" + i + ";"); current = current.plus(4); } for (int i = 0; i < fields.length; i++) { RVMField field = fields[i]; TypeReference t = field.getType(); Offset offset = field.getOffset(); String name = field.getName().toString(); // Align by blowing 4 bytes if needed if (needsAlign && current.plus(4).EQ(offset)) { pln(" uint32_t padding" + i + ";"); current = current.plus(4); } if (!current.EQ(offset)) { System.err.printf("current (%s) and offset (%s) are neither identical nor differ by 4", unboxedValueString(current), unboxedValueString(offset)); System.exit(1); } if (t.isIntType()) { current = current.plus(4); pln(" uint32_t " + name + ";"); } else if (t.isLongType()) { current = current.plus(8); pln(" uint64_t " + name + ";"); } else if (t.isWordLikeType()) { pln(" Address " + name + ";"); current = current.plus(addrSize); } else if (t.isArrayType() && t.getArrayElementType().isWordLikeType()) { pln(" Address * " + name + ";"); current = current.plus(addrSize); } else if (t.isArrayType() && t.getArrayElementType().isIntType()) { pln(" unsigned int * " + name + ";"); current = current.plus(addrSize); } else if (t.isReferenceType()) { pln(" Address " + name + ";"); current = current.plus(addrSize); } else { System.err.println("Unexpected field " + name + " with type " + t); throw new RuntimeException("unexpected field type"); } } pln("};"); } static void emitBootRecordDeclarations() { RVMClass bootRecord = TypeReference.findOrCreate(org.jikesrvm.runtime.BootRecord.class).resolve().asClass(); emitCDeclarationsForJavaType("BootRecord", bootRecord); } // Emit declarations for BootRecord object. // static void emitBootRecordInitialization() { RVMClass bootRecord = TypeReference.findOrCreate(org.jikesrvm.runtime.BootRecord.class).resolve().asClass(); RVMField[] fields = bootRecord.getDeclaredFields(); // emit field initializers // pln("static void setLinkage(struct BootRecord* br){"); for (int i = fields.length; --i >= 0;) { RVMField field = fields[i]; if (field.isStatic()) { continue; } String fieldName = field.getName().toString(); if (fieldName.indexOf("gcspy") > -1 && !VM.BuildWithGCSpy) { continue; // ugh. NOTE: ugly hack to side-step unconditional inclusion of GCSpy stuff } int suffixIndex = fieldName.indexOf("IP"); if (suffixIndex > 0) { // java field "xxxIP" corresponds to C function "xxx" String functionName = fieldName.substring(0, suffixIndex); // e. g., //sysFOOIP = (int) sysFOO; pln(" br->" + fieldName + " = (Address)" + functionName + ";"); } else if (fieldName.equals("sysJavaVM")) { pln(" br->" + fieldName + " = (Address)&" + fieldName + ";"); } } pln("}"); } // Emit virtual machine class interface information. // static void emitVirtualMachineDeclarations(long bootImageDataAddress, long bootImageCodeAddress, long bootImageRMapAddress) { // load address for the boot image // pln("bootImageDataAddress", Address.fromLong(bootImageDataAddress)); pln("bootImageCodeAddress", Address.fromLong(bootImageCodeAddress)); pln("bootImageRMapAddress", Address.fromLong(bootImageRMapAddress)); // values in Constants, from Configuration // pln("Constants_STACK_SIZE_GUARD", StackFrameLayout.getStackSizeGuard()); pln("Constants_INVISIBLE_METHOD_ID", StackFrameLayout.getInvisibleMethodID()); pln("Constants_STACKFRAME_HEADER_SIZE", StackFrameLayout.getStackFrameHeaderSize()); pln("Constants_STACKFRAME_METHOD_ID_OFFSET", StackFrameLayout.getStackFrameMethodIDOffset()); pln("Constants_STACKFRAME_FRAME_POINTER_OFFSET", StackFrameLayout.getStackFramePointerOffset()); pln("Constants_STACKFRAME_SENTINEL_FP", StackFrameLayout.getStackFrameSentinelFP()); pln("ThinLockConstants_TL_THREAD_ID_SHIFT", TL_THREAD_ID_SHIFT); // values in RuntimeEntrypoints // pln("Runtime_TRAP_UNKNOWN", RuntimeEntrypoints.TRAP_UNKNOWN); pln("Runtime_TRAP_NULL_POINTER", RuntimeEntrypoints.TRAP_NULL_POINTER); pln("Runtime_TRAP_ARRAY_BOUNDS", RuntimeEntrypoints.TRAP_ARRAY_BOUNDS); pln("Runtime_TRAP_DIVIDE_BY_ZERO", RuntimeEntrypoints.TRAP_DIVIDE_BY_ZERO); pln("Runtime_TRAP_STACK_OVERFLOW", RuntimeEntrypoints.TRAP_STACK_OVERFLOW); pln("Runtime_TRAP_CHECKCAST", RuntimeEntrypoints.TRAP_CHECKCAST); pln("Runtime_TRAP_REGENERATE", RuntimeEntrypoints.TRAP_REGENERATE); pln("Runtime_TRAP_JNI_STACK", RuntimeEntrypoints.TRAP_JNI_STACK); pln("Runtime_TRAP_MUST_IMPLEMENT", RuntimeEntrypoints.TRAP_MUST_IMPLEMENT); pln("Runtime_TRAP_STORE_CHECK", RuntimeEntrypoints.TRAP_STORE_CHECK); pln("Runtime_TRAP_UNREACHABLE_BYTECODE", RuntimeEntrypoints.TRAP_UNREACHABLE_BYTECODE); pln(); // fields in RVMThread // Offset offset = Entrypoints.threadStackField.getOffset(); pln("RVMThread_stack_offset", offset); offset = Entrypoints.stackLimitField.getOffset(); pln("RVMThread_stackLimit_offset", offset); offset = Entrypoints.threadExceptionRegistersField.getOffset(); pln("RVMThread_exceptionRegisters_offset", offset); offset = Entrypoints.jniEnvField.getOffset(); pln("RVMThread_jniEnv_offset", offset); offset = Entrypoints.execStatusField.getOffset(); pln("RVMThread_execStatus_offset", offset); // constants in RVMThread pln("RVMThread_TERMINATED", RVMThread.TERMINATED); // fields in Registers // offset = ArchEntrypoints.registersGPRsField.getOffset(); pln("Registers_gprs_offset", offset); offset = ArchEntrypoints.registersFPRsField.getOffset(); pln("Registers_fprs_offset", offset); offset = ArchEntrypoints.registersIPField.getOffset(); pln("Registers_ip_offset", offset); offset = ArchEntrypoints.registersInUseField.getOffset(); pln("Registers_inuse_offset", offset); // fields in JNIEnvironment offset = Entrypoints.JNIExternalFunctionsField.getOffset(); pln("JNIEnvironment_JNIExternalFunctions_offset", offset); arch.emitArchVirtualMachineDeclarations(); } // Codes for exit(3). static void emitExitStatusCodes() { pln("/* Automatically generated from the exitStatus declarations in ExitStatus.java */"); pln("EXIT_STATUS_EXECUTABLE_NOT_FOUND", EXIT_STATUS_EXECUTABLE_NOT_FOUND); pln("EXIT_STATUS_COULD_NOT_EXECUTE", EXIT_STATUS_COULD_NOT_EXECUTE); pln("EXIT_STATUS_MISC_TROUBLE", EXIT_STATUS_MISC_TROUBLE); pln("EXIT_STATUS_IMPOSSIBLE_LIBRARY_FUNCTION_ERROR", EXIT_STATUS_IMPOSSIBLE_LIBRARY_FUNCTION_ERROR); pln("EXIT_STATUS_SYSCALL_TROUBLE", EXIT_STATUS_SYSCALL_TROUBLE); pln("EXIT_STATUS_TIMER_TROUBLE", EXIT_STATUS_TIMER_TROUBLE); pln("EXIT_STATUS_UNSUPPORTED_INTERNAL_OP", EXIT_STATUS_UNSUPPORTED_INTERNAL_OP); pln("EXIT_STATUS_UNEXPECTED_CALL_TO_SYS", EXIT_STATUS_UNEXPECTED_CALL_TO_SYS); pln("EXIT_STATUS_DYING_WITH_UNCAUGHT_EXCEPTION", EXIT_STATUS_DYING_WITH_UNCAUGHT_EXCEPTION); pln("EXIT_STATUS_BOGUS_COMMAND_LINE_ARG", EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); pln("EXIT_STATUS_JNI_TROUBLE", EXIT_STATUS_JNI_TROUBLE); pln("EXIT_STATUS_BAD_WORKING_DIR", EXIT_STATUS_BAD_WORKING_DIR); } // Emit assembler constants. // static void emitAssemblerDeclarations() { arch.emitArchAssemblerDeclarations(); } }