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