001/* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013package org.jikesrvm.tools.header_gen; 014 015import static org.jikesrvm.objectmodel.ThinLockConstants.TL_THREAD_ID_SHIFT; 016import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_BAD_WORKING_DIR; 017import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG; 018import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_COULD_NOT_EXECUTE; 019import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_DYING_WITH_UNCAUGHT_EXCEPTION; 020import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_EXECUTABLE_NOT_FOUND; 021import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_IMPOSSIBLE_LIBRARY_FUNCTION_ERROR; 022import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_JNI_TROUBLE; 023import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_MISC_TROUBLE; 024import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_SYSCALL_TROUBLE; 025import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_TIMER_TROUBLE; 026import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_UNEXPECTED_CALL_TO_SYS; 027import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_UNSUPPORTED_INTERNAL_OP; 028 029import java.io.FileOutputStream; 030import java.io.IOException; 031import java.io.PrintStream; 032import java.util.Arrays; 033 034import org.jikesrvm.VM; 035import org.jikesrvm.architecture.StackFrameLayout; 036import org.jikesrvm.classloader.RVMClass; 037import org.jikesrvm.classloader.RVMField; 038import org.jikesrvm.classloader.TypeReference; 039import org.jikesrvm.objectmodel.ObjectModel; 040import org.jikesrvm.runtime.ArchEntrypoints; 041import org.jikesrvm.runtime.Entrypoints; 042import org.jikesrvm.runtime.RuntimeEntrypoints; 043import org.jikesrvm.scheduler.RVMThread; 044import org.jikesrvm.util.Services; 045import org.vmmagic.unboxed.Address; 046import org.vmmagic.unboxed.Offset; 047 048/** 049 * Emit a header file containing declarations required to access VM 050 * data structures from C. 051 */ 052public class GenerateInterfaceDeclarations { 053 054 static PrintStream out; 055 static final GenArch arch; 056 057 static { 058 GenArch tmp = null; 059 try { 060 tmp = 061 (GenArch) Class.forName(VM.BuildForIA32 ? "org.jikesrvm.tools.header_gen.GenArch_ia32" : "org.jikesrvm.tools.header_gen.GenArch_ppc").newInstance(); 062 } catch (Exception e) { 063 e.printStackTrace(); 064 System.exit(EXIT_STATUS_MISC_TROUBLE); // we must *not* go on if the above has failed 065 } 066 arch = tmp; 067 } 068 069 static void p(String s) { 070 out.print(s); 071 } 072 073 static void p(String s, Offset off) { 074 if (VM.BuildFor64Addr) { 075 out.print(s + off.toLong()); 076 } else { 077 out.print(s + Services.addressAsHexString(off.toWord().toAddress())); 078 } 079 } 080 081 static void pln(String s) { 082 out.println(s); 083 } 084 085 static void pln(String s, int i) { 086 out.print("#define " + s + " 0x" + Integer.toHexString(i) + "\n"); 087 } 088 089 static void pln(String s, Address addr) { 090 out.print("#define " + s + " ((Address)" + Services.addressAsHexString(addr) + ")\n"); 091 } 092 093 static void pln(String s, Offset off) { 094 out.print("#define " + s + " ((Offset)" + Services.addressAsHexString(off.toWord().toAddress()) + ")\n"); 095 } 096 097 static void pln() { 098 out.println(); 099 } 100 101 GenerateInterfaceDeclarations() { 102 } 103 104 static long bootImageDataAddress = 0; 105 static long bootImageCodeAddress = 0; 106 static long bootImageRMapAddress = 0; 107 static String outFileName; 108 109 private static long decodeLong(String s) { 110 if (s.endsWith("L")) { 111 s = s.substring(0, s.length() - 1); 112 } 113 return Long.decode(s); 114 } 115 116 public static void main(String[] args) throws Exception { 117 118 // Process command line directives. 119 // 120 for (int i = 0, n = args.length; i < n; ++i) { 121 if (args[i].equals("-da")) { // image address 122 if (++i == args.length) { 123 System.err.println("Error: The -da flag requires an argument"); 124 System.exit(EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); 125 } 126 bootImageDataAddress = decodeLong(args[i]); 127 continue; 128 } 129 if (args[i].equals("-ca")) { // image address 130 if (++i == args.length) { 131 System.err.println("Error: The -ca flag requires an argument"); 132 System.exit(EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); 133 } 134 bootImageCodeAddress = decodeLong(args[i]); 135 continue; 136 } 137 if (args[i].equals("-ra")) { // image address 138 if (++i == args.length) { 139 System.err.println("Error: The -ra flag requires an argument"); 140 System.exit(EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); 141 } 142 bootImageRMapAddress = decodeLong(args[i]); 143 continue; 144 } 145 if (args[i].equals("-out")) { // output file 146 if (++i == args.length) { 147 System.err.println("Error: The -out flag requires an argument"); 148 System.exit(EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); 149 } 150 outFileName = args[i]; 151 continue; 152 } 153 System.err.println("Error: unrecognized command line argument: " + args[i]); 154 System.exit(EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); 155 } 156 157 if (bootImageDataAddress == 0) { 158 System.err.println("Error: Must specify boot image data load address."); 159 System.exit(EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); 160 } 161 if (bootImageCodeAddress == 0) { 162 System.err.println("Error: Must specify boot image code load address."); 163 System.exit(EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); 164 } 165 if (bootImageRMapAddress == 0) { 166 System.err.println("Error: Must specify boot image ref map load address."); 167 System.exit(EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); 168 } 169 if (outFileName == null) { 170 out = System.out; 171 } else { 172 try { 173 // We'll let an unhandled exception throw an I/O error for us. 174 out = new PrintStream(new FileOutputStream(outFileName)); 175 } catch (IOException e) { 176 reportTrouble("Caught an exception while opening" + outFileName + " for writing: " + e.toString()); 177 } 178 } 179 180 VM.initForTool(); 181 182 emitStuff(); 183 if (out.checkError()) { 184 reportTrouble("an output error happened"); 185 } 186 // try { 187 out.close(); // exception thrown up. 188 // } catch (IOException e) { 189 // reportTrouble("An output error when closing the output: " + e.toString()); 190 // } 191 System.exit(0); 192 } 193 194 private static void reportTrouble(String msg) { 195 System.err.println( 196 "org.jikesrvm.tools.header_gen.GenerateInterfaceDeclarations: While we were creating InterfaceDeclarations.h, there was a problem."); 197 System.err.println(msg); 198 System.err.print("The build system will delete the output file"); 199 if (outFileName != null) { 200 System.err.print(' '); 201 System.err.print(outFileName); 202 } 203 System.err.println(); 204 205 System.exit(1); 206 } 207 208 private static void emitStuff() { 209 p("/*------ MACHINE GENERATED by "); 210 p("org.jikesrvm.tools.header_gen.GenerateInterfaceDeclarations.java: DO NOT EDIT"); 211 p("------*/\n\n"); 212 213 if (VM.PortableNativeSync) { 214 pln("#define PORTABLE_NATIVE_SYNC 1"); 215 pln(); 216 } 217 218 pln("#ifdef NEED_BOOT_RECORD_DECLARATIONS"); 219 emitBootRecordDeclarations(); 220 pln("#endif /* NEED_BOOT_RECORD_DECLARATIONS */"); 221 pln(); 222 223 pln("#ifdef NEED_BOOT_RECORD_INITIALIZATION"); 224 emitBootRecordInitialization(); 225 pln("#endif /* NEED_BOOT_RECORD_INITIALIZATION */"); 226 pln(); 227 228 pln("#ifdef NEED_VIRTUAL_MACHINE_DECLARATIONS"); 229 emitVirtualMachineDeclarations(bootImageDataAddress, bootImageCodeAddress, bootImageRMapAddress); 230 pln("#endif /* NEED_VIRTUAL_MACHINE_DECLARATIONS */"); 231 pln(); 232 233 pln("#ifdef NEED_EXIT_STATUS_CODES"); 234 emitExitStatusCodes(); 235 pln("#endif /* NEED_EXIT_STATUS_CODES */"); 236 pln(); 237 238 pln("#ifdef NEED_ASSEMBLER_DECLARATIONS"); 239 emitAssemblerDeclarations(); 240 pln("#endif /* NEED_ASSEMBLER_DECLARATIONS */"); 241 242 pln("#ifdef NEED_MEMORY_MANAGER_DECLARATIONS"); 243 pln("#define MAXHEAPS " + org.jikesrvm.mm.mminterface.MemoryManager.getMaxHeaps()); 244 pln("#endif /* NEED_MEMORY_MANAGER_DECLARATIONS */"); 245 pln(); 246 247 } 248 249 static void emitCDeclarationsForJavaType(String Cname, RVMClass cls) { 250 251 // How many instance fields are there? 252 // 253 RVMField[] allFields = cls.getDeclaredFields(); 254 int fieldCount = 0; 255 for (RVMField field : allFields) { 256 if (!field.isStatic()) { 257 fieldCount++; 258 } 259 } 260 261 RVMField[] fields = new RVMField[fieldCount]; 262 for (int i = 0, j = 0; i < allFields.length; i++) { 263 if (!allFields[i].isStatic()) { 264 fields[j++] = allFields[i]; 265 } 266 } 267 Arrays.sort(fields, new AscendingOffsetComparator()); 268 269 // Emit field declarations 270 // 271 p("struct " + Cname + " {\n"); 272 273 // Set up cursor - scalars will waste 4 bytes on 64-bit arch 274 // 275 boolean needsAlign = VM.BuildFor64Addr; 276 int addrSize = VM.BuildFor32Addr ? 4 : 8; 277 278 // Header Space for objects 279 int startOffset = ObjectModel.objectStartOffset(cls); 280 Offset current = Offset.fromIntSignExtend(startOffset); 281 for (int i = 0; current.sLT(fields[0].getOffset()); i++) { 282 pln(" uint32_t headerPadding" + i + ";\n"); 283 current = current.plus(4); 284 } 285 286 for (int i = 0; i < fields.length; i++) { 287 RVMField field = fields[i]; 288 TypeReference t = field.getType(); 289 Offset offset = field.getOffset(); 290 String name = field.getName().toString(); 291 // Align by blowing 4 bytes if needed 292 if (needsAlign && current.plus(4).EQ(offset)) { 293 pln(" uint32_t padding" + i + ";"); 294 current = current.plus(4); 295 } 296 if (!current.EQ(offset)) { 297 System.err.printf("current (%d) and offset (%d) are neither identical nor differ by 4", 298 current.toInt(), 299 offset.toInt()); 300 System.exit(1); 301 } 302 if (t.isIntType()) { 303 current = current.plus(4); 304 p(" uint32_t " + name + ";\n"); 305 } else if (t.isLongType()) { 306 current = current.plus(8); 307 p(" uint64_t " + name + ";\n"); 308 } else if (t.isWordLikeType()) { 309 p(" Address " + name + ";\n"); 310 current = current.plus(addrSize); 311 } else if (t.isArrayType() && t.getArrayElementType().isWordLikeType()) { 312 p(" Address * " + name + ";\n"); 313 current = current.plus(addrSize); 314 } else if (t.isArrayType() && t.getArrayElementType().isIntType()) { 315 p(" unsigned int * " + name + ";\n"); 316 current = current.plus(addrSize); 317 } else if (t.isReferenceType()) { 318 p(" Address " + name + ";\n"); 319 current = current.plus(addrSize); 320 } else { 321 System.err.println("Unexpected field " + name + " with type " + t); 322 throw new RuntimeException("unexpected field type"); 323 } 324 } 325 326 p("};\n"); 327 } 328 329 static void emitBootRecordDeclarations() { 330 RVMClass bootRecord = TypeReference.findOrCreate(org.jikesrvm.runtime.BootRecord.class).resolve().asClass(); 331 emitCDeclarationsForJavaType("BootRecord", bootRecord); 332 } 333 334 // Emit declarations for BootRecord object. 335 // 336 static void emitBootRecordInitialization() { 337 RVMClass bootRecord = TypeReference.findOrCreate(org.jikesrvm.runtime.BootRecord.class).resolve().asClass(); 338 RVMField[] fields = bootRecord.getDeclaredFields(); 339 340 // emit field initializers 341 // 342 p("static void setLinkage(struct BootRecord* br){\n"); 343 for (int i = fields.length; --i >= 0;) { 344 RVMField field = fields[i]; 345 if (field.isStatic()) { 346 continue; 347 } 348 349 String fieldName = field.getName().toString(); 350 if (fieldName.indexOf("gcspy") > -1 && !VM.BuildWithGCSpy) { 351 continue; // ugh. NOTE: ugly hack to side-step unconditional inclusion of GCSpy stuff 352 } 353 int suffixIndex = fieldName.indexOf("IP"); 354 if (suffixIndex > 0) { 355 // java field "xxxIP" corresponds to C function "xxx" 356 String functionName = fieldName.substring(0, suffixIndex); 357 // e. g., 358 //sysFOOIP = (int) sysFOO; 359 p(" br->" + fieldName + " = (Address)" + functionName + ";\n"); 360 } else if (fieldName.equals("sysJavaVM")) { 361 p(" br->" + fieldName + " = (Address)&" + fieldName + ";\n"); 362 } 363 } 364 365 p("}\n"); 366 } 367 368 // Emit virtual machine class interface information. 369 // 370 static void emitVirtualMachineDeclarations(long bootImageDataAddress, long bootImageCodeAddress, 371 long bootImageRMapAddress) { 372 373 // load address for the boot image 374 // 375 pln("bootImageDataAddress", Address.fromLong(bootImageDataAddress)); 376 pln("bootImageCodeAddress", Address.fromLong(bootImageCodeAddress)); 377 pln("bootImageRMapAddress", Address.fromLong(bootImageRMapAddress)); 378 379 // values in Constants, from Configuration 380 // 381 pln("Constants_STACK_SIZE_GUARD", StackFrameLayout.getStackSizeGuard()); 382 pln("Constants_INVISIBLE_METHOD_ID", StackFrameLayout.getInvisibleMethodID()); 383 pln("Constants_STACKFRAME_HEADER_SIZE", StackFrameLayout.getStackFrameHeaderSize()); 384 pln("Constants_STACKFRAME_METHOD_ID_OFFSET", StackFrameLayout.getStackFrameMethodIDOffset()); 385 pln("Constants_STACKFRAME_FRAME_POINTER_OFFSET", StackFrameLayout.getStackFramePointerOffset()); 386 pln("Constants_STACKFRAME_SENTINEL_FP", StackFrameLayout.getStackFrameSentinelFP()); 387 388 pln("ThinLockConstants_TL_THREAD_ID_SHIFT", TL_THREAD_ID_SHIFT); 389 390 // values in RuntimeEntrypoints 391 // 392 pln("Runtime_TRAP_UNKNOWN", RuntimeEntrypoints.TRAP_UNKNOWN); 393 pln("Runtime_TRAP_NULL_POINTER", RuntimeEntrypoints.TRAP_NULL_POINTER); 394 pln("Runtime_TRAP_ARRAY_BOUNDS", RuntimeEntrypoints.TRAP_ARRAY_BOUNDS); 395 pln("Runtime_TRAP_DIVIDE_BY_ZERO", RuntimeEntrypoints.TRAP_DIVIDE_BY_ZERO); 396 pln("Runtime_TRAP_STACK_OVERFLOW", RuntimeEntrypoints.TRAP_STACK_OVERFLOW); 397 pln("Runtime_TRAP_CHECKCAST", RuntimeEntrypoints.TRAP_CHECKCAST); 398 pln("Runtime_TRAP_REGENERATE", RuntimeEntrypoints.TRAP_REGENERATE); 399 pln("Runtime_TRAP_JNI_STACK", RuntimeEntrypoints.TRAP_JNI_STACK); 400 pln("Runtime_TRAP_MUST_IMPLEMENT", RuntimeEntrypoints.TRAP_MUST_IMPLEMENT); 401 pln("Runtime_TRAP_STORE_CHECK", RuntimeEntrypoints.TRAP_STORE_CHECK); 402 pln("Runtime_TRAP_UNREACHABLE_BYTECODE", RuntimeEntrypoints.TRAP_UNREACHABLE_BYTECODE); 403 pln(); 404 405 // fields in RVMThread 406 // 407 Offset offset = Entrypoints.threadStackField.getOffset(); 408 pln("RVMThread_stack_offset", offset); 409 offset = Entrypoints.stackLimitField.getOffset(); 410 pln("RVMThread_stackLimit_offset", offset); 411 offset = Entrypoints.threadExceptionRegistersField.getOffset(); 412 pln("RVMThread_exceptionRegisters_offset", offset); 413 offset = Entrypoints.jniEnvField.getOffset(); 414 pln("RVMThread_jniEnv_offset", offset); 415 offset = Entrypoints.execStatusField.getOffset(); 416 pln("RVMThread_execStatus_offset", offset); 417 // constants in RVMThread 418 pln("RVMThread_TERMINATED", RVMThread.TERMINATED); 419 // fields in Registers 420 // 421 offset = ArchEntrypoints.registersGPRsField.getOffset(); 422 pln("Registers_gprs_offset", offset); 423 offset = ArchEntrypoints.registersFPRsField.getOffset(); 424 pln("Registers_fprs_offset", offset); 425 offset = ArchEntrypoints.registersIPField.getOffset(); 426 pln("Registers_ip_offset", offset); 427 428 offset = ArchEntrypoints.registersInUseField.getOffset(); 429 pln("Registers_inuse_offset", offset); 430 431 // fields in JNIEnvironment 432 offset = Entrypoints.JNIExternalFunctionsField.getOffset(); 433 pln("JNIEnvironment_JNIExternalFunctions_offset", offset); 434 435 arch.emitArchVirtualMachineDeclarations(); 436 } 437 438 // Codes for exit(3). 439 static void emitExitStatusCodes() { 440 pln("/* Automatically generated from the exitStatus declarations in ExitStatus.java */"); 441 pln("EXIT_STATUS_EXECUTABLE_NOT_FOUND", EXIT_STATUS_EXECUTABLE_NOT_FOUND); 442 pln("EXIT_STATUS_COULD_NOT_EXECUTE", EXIT_STATUS_COULD_NOT_EXECUTE); 443 pln("EXIT_STATUS_MISC_TROUBLE", EXIT_STATUS_MISC_TROUBLE); 444 pln("EXIT_STATUS_IMPOSSIBLE_LIBRARY_FUNCTION_ERROR", EXIT_STATUS_IMPOSSIBLE_LIBRARY_FUNCTION_ERROR); 445 pln("EXIT_STATUS_SYSCALL_TROUBLE", EXIT_STATUS_SYSCALL_TROUBLE); 446 pln("EXIT_STATUS_TIMER_TROUBLE", EXIT_STATUS_TIMER_TROUBLE); 447 pln("EXIT_STATUS_UNSUPPORTED_INTERNAL_OP", EXIT_STATUS_UNSUPPORTED_INTERNAL_OP); 448 pln("EXIT_STATUS_UNEXPECTED_CALL_TO_SYS", EXIT_STATUS_UNEXPECTED_CALL_TO_SYS); 449 pln("EXIT_STATUS_DYING_WITH_UNCAUGHT_EXCEPTION", EXIT_STATUS_DYING_WITH_UNCAUGHT_EXCEPTION); 450 pln("EXIT_STATUS_BOGUS_COMMAND_LINE_ARG", EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); 451 pln("EXIT_STATUS_JNI_TROUBLE", EXIT_STATUS_JNI_TROUBLE); 452 pln("EXIT_STATUS_BAD_WORKING_DIR", EXIT_STATUS_BAD_WORKING_DIR); 453 } 454 455 // Emit assembler constants. 456 // 457 static void emitAssemblerDeclarations() { 458 arch.emitArchAssemblerDeclarations(); 459 } 460} 461 462 463