aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoramurillo <none@none>2013-03-23 01:47:24 -0700
committeramurillo <none@none>2013-03-23 01:47:24 -0700
commitbb6a442c5065da20e76e2aee14e9726da0c1cc30 (patch)
tree5b8f4591a32c0ca76fc269c61666dec89824c0f6
parentefff27ea26d5a07aa10bf229fdac7e61e2876e27 (diff)
parent36b2eebc19b1c8084230034d1143547afae3f86b (diff)
-rw-r--r--agent/src/os/bsd/MacosxDebuggerLocal.m697
-rw-r--r--agent/src/os/bsd/Makefile51
-rw-r--r--agent/src/os/bsd/libproc.h49
-rw-r--r--agent/src/os/bsd/libproc_impl.c476
-rw-r--r--agent/src/os/bsd/libproc_impl.h109
-rw-r--r--agent/src/os/bsd/ps_core.c1372
-rw-r--r--agent/src/os/bsd/symtab.c199
-rw-r--r--agent/src/os/bsd/symtab.h6
-rw-r--r--agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java17
-rw-r--r--agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java105
-rw-r--r--agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java33
-rw-r--r--agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java52
-rw-r--r--agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java12
-rw-r--r--agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java4
-rw-r--r--agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java6
-rw-r--r--agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java12
-rw-r--r--agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java8
-rw-r--r--agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java13
-rw-r--r--agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java6
-rw-r--r--agent/src/share/native/sadis.c12
-rw-r--r--make/Makefile33
-rw-r--r--make/bsd/Makefile21
-rw-r--r--make/bsd/makefiles/buildtree.make124
-rw-r--r--make/bsd/makefiles/saproc.make18
-rw-r--r--make/defs.make5
-rw-r--r--make/hotspot_version2
-rw-r--r--make/jprt.properties26
-rw-r--r--make/linux/Makefile21
-rw-r--r--make/linux/makefiles/buildtree.make124
-rw-r--r--make/solaris/Makefile12
-rw-r--r--make/solaris/makefiles/buildtree.make131
-rw-r--r--make/test/Queens.java86
-rw-r--r--src/cpu/sparc/vm/macroAssembler_sparc.cpp38
-rw-r--r--src/cpu/x86/vm/frame_x86.inline.hpp12
-rw-r--r--src/cpu/x86/vm/macroAssembler_x86.cpp28
-rw-r--r--src/cpu/x86/vm/relocInfo_x86.cpp9
-rw-r--r--src/os_cpu/linux_x86/vm/os_linux_x86.cpp2
-rw-r--r--src/share/vm/asm/assembler.cpp10
-rw-r--r--src/share/vm/asm/assembler.hpp2
-rw-r--r--src/share/vm/asm/codeBuffer.cpp126
-rw-r--r--src/share/vm/asm/codeBuffer.hpp25
-rw-r--r--src/share/vm/ci/ciEnv.cpp1
-rw-r--r--src/share/vm/classfile/classLoaderData.cpp5
-rw-r--r--src/share/vm/classfile/defaultMethods.cpp2
-rw-r--r--src/share/vm/classfile/systemDictionary.cpp44
-rw-r--r--src/share/vm/classfile/systemDictionary.hpp1
-rw-r--r--src/share/vm/code/codeBlob.cpp2
-rw-r--r--src/share/vm/code/codeBlob.hpp8
-rw-r--r--src/share/vm/code/compiledIC.cpp2
-rw-r--r--src/share/vm/code/icBuffer.hpp2
-rw-r--r--src/share/vm/code/stubs.cpp16
-rw-r--r--src/share/vm/code/stubs.hpp10
-rw-r--r--src/share/vm/compiler/compileBroker.cpp77
-rw-r--r--src/share/vm/compiler/compileBroker.hpp3
-rw-r--r--src/share/vm/compiler/disassembler.cpp12
-rw-r--r--src/share/vm/compiler/disassembler.hpp2
-rw-r--r--src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp4
-rw-r--r--src/share/vm/gc_implementation/g1/concurrentMark.cpp300
-rw-r--r--src/share/vm/gc_implementation/g1/concurrentMark.hpp11
-rw-r--r--src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp2
-rw-r--r--src/share/vm/interpreter/interpreter.cpp2
-rw-r--r--src/share/vm/interpreter/interpreter.hpp6
-rw-r--r--src/share/vm/memory/genCollectedHeap.cpp7
-rw-r--r--src/share/vm/memory/metaspace.cpp26
-rw-r--r--src/share/vm/memory/sharedHeap.cpp2
-rw-r--r--src/share/vm/oops/constantPool.cpp1
-rw-r--r--src/share/vm/oops/fieldInfo.hpp26
-rw-r--r--src/share/vm/oops/generateOopMap.cpp4
-rw-r--r--src/share/vm/oops/klass.cpp6
-rw-r--r--src/share/vm/oops/method.cpp10
-rw-r--r--src/share/vm/opto/bytecodeInfo.cpp3
-rw-r--r--src/share/vm/opto/loopTransform.cpp14
-rw-r--r--src/share/vm/opto/loopnode.hpp8
-rw-r--r--src/share/vm/opto/loopopts.cpp17
-rw-r--r--src/share/vm/opto/output.cpp1
-rw-r--r--src/share/vm/opto/type.cpp1
-rw-r--r--src/share/vm/prims/jni.cpp4
-rw-r--r--src/share/vm/prims/jni.h3
-rw-r--r--src/share/vm/runtime/stubCodeGenerator.cpp2
-rw-r--r--src/share/vm/runtime/thread.cpp1
-rw-r--r--src/share/vm/runtime/vm_version.cpp4
-rw-r--r--src/share/vm/services/memoryService.cpp1
-rw-r--r--src/share/vm/utilities/debug.cpp4
-rw-r--r--src/share/vm/utilities/debug.hpp7
-rw-r--r--test/compiler/whitebox/CompilerWhiteBoxTest.java18
-rw-r--r--test/compiler/whitebox/DeoptimizeAllTest.java4
-rw-r--r--test/compiler/whitebox/DeoptimizeMethodTest.java4
-rw-r--r--test/compiler/whitebox/IsMethodCompilableTest.java4
-rw-r--r--test/compiler/whitebox/MakeMethodNotCompilableTest.java2
89 files changed, 2849 insertions, 1941 deletions
diff --git a/agent/src/os/bsd/MacosxDebuggerLocal.m b/agent/src/os/bsd/MacosxDebuggerLocal.m
index c14c6b7bc..d5c23a012 100644
--- a/agent/src/os/bsd/MacosxDebuggerLocal.m
+++ b/agent/src/os/bsd/MacosxDebuggerLocal.m
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -40,12 +40,34 @@
#import <errno.h>
#import <sys/types.h>
#import <sys/ptrace.h>
+#include "libproc_impl.h"
-jboolean debug = JNI_FALSE;
+#define UNSUPPORTED_ARCH "Unsupported architecture!"
+
+#if defined(x86_64) && !defined(amd64)
+#define amd64 1
+#endif
+
+#if amd64
+#include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h"
+#else
+#error UNSUPPORTED_ARCH
+#endif
static jfieldID symbolicatorID = 0; // set in _init0
static jfieldID taskID = 0; // set in _init0
+static jfieldID p_ps_prochandle_ID = 0;
+static jfieldID loadObjectList_ID = 0;
+static jmethodID listAdd_ID = 0;
+
+static jmethodID createClosestSymbol_ID = 0;
+static jmethodID createLoadObject_ID = 0;
+static jmethodID getJavaThreadsInfo_ID = 0;
+
+// indicator if thread id (lwpid_t) was set
+static bool _threads_filled = false;
+
static void putSymbolicator(JNIEnv *env, jobject this_obj, id symbolicator) {
(*env)->SetLongField(env, this_obj, symbolicatorID, (jlong)(intptr_t)symbolicator);
}
@@ -76,6 +98,11 @@ static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) {
(*env)->ThrowNew(env, (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"), errMsg);
}
+static struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) {
+ jlong ptr = (*env)->GetLongField(env, this_obj, p_ps_prochandle_ID);
+ return (struct ps_prochandle*)(intptr_t)ptr;
+}
+
#if defined(__i386__)
#define hsdb_thread_state_t x86_thread_state32_t
#define hsdb_float_state_t x86_float_state32_t
@@ -91,7 +118,7 @@ static void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) {
#define HSDB_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
#define HSDB_FLOAT_STATE_COUNT x86_FLOAT_STATE64_COUNT
#else
- #error "Unsupported architecture"
+ #error UNSUPPORTED_ARCH
#endif
/*
@@ -104,6 +131,66 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls
symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J");
taskID = (*env)->GetFieldID(env, cls, "task", "J");
CHECK_EXCEPTION;
+
+ // for core file
+ p_ps_prochandle_ID = (*env)->GetFieldID(env, cls, "p_ps_prochandle", "J");
+ CHECK_EXCEPTION;
+ loadObjectList_ID = (*env)->GetFieldID(env, cls, "loadObjectList", "Ljava/util/List;");
+ CHECK_EXCEPTION;
+
+ // methods we use
+ createClosestSymbol_ID = (*env)->GetMethodID(env, cls, "createClosestSymbol",
+ "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;");
+ CHECK_EXCEPTION;
+ createLoadObject_ID = (*env)->GetMethodID(env, cls, "createLoadObject",
+ "(Ljava/lang/String;JJ)Lsun/jvm/hotspot/debugger/cdbg/LoadObject;");
+ CHECK_EXCEPTION;
+
+ // java.util.List method we call
+ jclass listClass = (*env)->FindClass(env, "java/util/List");
+ CHECK_EXCEPTION;
+ listAdd_ID = (*env)->GetMethodID(env, listClass, "add", "(Ljava/lang/Object;)Z");
+ CHECK_EXCEPTION;
+ getJavaThreadsInfo_ID = (*env)->GetMethodID(env, cls, "getJavaThreadsInfo",
+ "()[J");
+ CHECK_EXCEPTION;
+
+ init_libproc(getenv("LIBSAPROC_DEBUG") != NULL);
+}
+
+JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getAddressSize
+ (JNIEnv *env, jclass cls)
+{
+#ifdef _LP64
+ return 8;
+#else
+ #error UNSUPPORTED_ARCH
+#endif
+}
+
+/** called by Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0 */
+jlong lookupByNameIncore(
+ JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jstring objectName, jstring symbolName)
+{
+ const char *objectName_cstr, *symbolName_cstr;
+ jlong addr;
+ jboolean isCopy;
+ objectName_cstr = NULL;
+ if (objectName != NULL) {
+ objectName_cstr = (*env)->GetStringUTFChars(env, objectName, &isCopy);
+ CHECK_EXCEPTION_(0);
+ }
+ symbolName_cstr = (*env)->GetStringUTFChars(env, symbolName, &isCopy);
+ CHECK_EXCEPTION_(0);
+
+ print_debug("look for %s \n", symbolName_cstr);
+ addr = (jlong) lookup_symbol(ph, objectName_cstr, symbolName_cstr);
+
+ if (objectName_cstr != NULL) {
+ (*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr);
+ }
+ (*env)->ReleaseStringUTFChars(env, symbolName, symbolName_cstr);
+ return addr;
}
/*
@@ -116,14 +203,17 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0(
JNIEnv *env, jobject this_obj,
jstring objectName, jstring symbolName)
{
+ struct ps_prochandle* ph = get_proc_handle(env, this_obj);
+ if (ph->core != NULL) {
+ return lookupByNameIncore(env, ph, this_obj, objectName, symbolName);
+ }
+
jlong address = 0;
JNF_COCOA_ENTER(env);
NSString *symbolNameString = JNFJavaToNSString(env, symbolName);
- if (debug) {
- printf("lookupInProcess called for %s\n", [symbolNameString UTF8String]);
- }
+ print_debug("lookupInProcess called for %s\n", [symbolNameString UTF8String]);
id symbolicator = getSymbolicator(env, this_obj);
if (symbolicator != nil) {
@@ -131,9 +221,7 @@ JNF_COCOA_ENTER(env);
address = (jlong) dynamicCall(symbolicator, @selector(addressForSymbol:), symbolNameString);
}
- if (debug) {
- printf("address of symbol %s = %llx\n", [symbolNameString UTF8String], address);
- }
+ print_debug("address of symbol %s = %llx\n", [symbolNameString UTF8String], address);
JNF_COCOA_EXIT(env);
return address;
@@ -141,6 +229,42 @@ JNF_COCOA_EXIT(env);
/*
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
+ * Method: lookupByAddress0
+ * Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;
+ */
+JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0
+ (JNIEnv *env, jobject this_obj, jlong addr) {
+ uintptr_t offset;
+ const char* sym = NULL;
+
+ struct ps_prochandle* ph = get_proc_handle(env, this_obj);
+ sym = symbol_for_pc(ph, (uintptr_t) addr, &offset);
+ if (sym == NULL) return 0;
+ return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID,
+ (*env)->NewStringUTF(env, sym), (jlong)offset);
+}
+
+/** called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0 */
+jbyteArray readBytesFromCore(
+ JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jlong addr, jlong numBytes)
+{
+ jboolean isCopy;
+ jbyteArray array;
+ jbyte *bufPtr;
+ ps_err_e err;
+
+ array = (*env)->NewByteArray(env, numBytes);
+ CHECK_EXCEPTION_(0);
+ bufPtr = (*env)->GetByteArrayElements(env, array, &isCopy);
+ CHECK_EXCEPTION_(0);
+
+ err = ps_pread(ph, (psaddr_t) (uintptr_t)addr, bufPtr, numBytes);
+ (*env)->ReleaseByteArrayElements(env, array, bufPtr, 0);
+ return (err == PS_OK)? array : 0;
+}
+
+/*
+ * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
* Method: readBytesFromProcess0
* Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult;
*/
@@ -149,12 +273,15 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0(
JNIEnv *env, jobject this_obj,
jlong addr, jlong numBytes)
{
- if (debug) printf("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes);
+ print_debug("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes);
// must allocate storage instead of using former parameter buf
- jboolean isCopy;
jbyteArray array;
- jbyte *bufPtr;
+
+ struct ps_prochandle* ph = get_proc_handle(env, this_obj);
+ if (ph->core != NULL) {
+ return readBytesFromCore(env, ph, this_obj, addr, numBytes);
+ }
array = (*env)->NewByteArray(env, numBytes);
CHECK_EXCEPTION_(0);
@@ -189,7 +316,7 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0(
// assume all failures are unmapped pages
}
- if (debug) fprintf(stderr, "%ld pages\n", pageCount);
+ print_debug("%ld pages\n", pageCount);
remaining = numBytes;
@@ -207,7 +334,7 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0(
}
if (mapped[i]) {
- if (debug) fprintf(stderr, "page %d mapped (len %ld start %ld)\n", i, len, start);
+ print_debug("page %d mapped (len %ld start %ld)\n", i, len, start);
(*env)->SetByteArrayRegion(env, array, 0, len, ((jbyte *) pages[i] + start));
vm_deallocate(mach_task_self(), pages[i], vm_page_size);
}
@@ -220,6 +347,115 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0(
return array;
}
+/** Only used for core file reading, set thread_id for threads which is got after core file parsed.
+ * Thread context is available in Mach-O core file but thread id is not. We can get thread id
+ * from Threads which store all java threads information when they are created. Here we can identify
+ * them as java threads by checking if a thread's rsp or rbp within a java thread's stack.
+ * Note Macosx uses unique_thread_id which is different from other platforms though printed ids
+ * are still pthread id. Function BsdDebuggerLocal.getJavaThreadsInfo returns an array of long
+ * integers to host all java threads' id, stack_start, stack_end as:
+ * [uid0, stack_start0, stack_end0, uid1, stack_start1, stack_end1, ...]
+ *
+ * The work cannot be done at init0 since Threads is not available yet(VM not initialized yet).
+ * This function should be called only once if succeeded
+ */
+bool fill_java_threads(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) {
+ int n = 0, i = 0, j;
+ struct reg regs;
+
+ jlongArray thrinfos = (*env)->CallObjectMethod(env, this_obj, getJavaThreadsInfo_ID);
+ CHECK_EXCEPTION_(false);
+ int len = (int)(*env)->GetArrayLength(env, thrinfos);
+ uint64_t* cinfos = (uint64_t *)(*env)->GetLongArrayElements(env, thrinfos, NULL);
+ CHECK_EXCEPTION_(false);
+ n = get_num_threads(ph);
+ print_debug("fill_java_threads called, num_of_thread = %d\n", n);
+ for (i = 0; i < n; i++) {
+ if (!get_nth_lwp_regs(ph, i, &regs)) {
+ print_debug("Could not get regs of thread %d, already set!\n", i);
+ return false;
+ }
+ for (j = 0; j < len; j += 3) {
+ lwpid_t uid = cinfos[j];
+ uint64_t beg = cinfos[j + 1];
+ uint64_t end = cinfos[j + 2];
+ if ((regs.r_rsp < end && regs.r_rsp >= beg) ||
+ (regs.r_rbp < end && regs.r_rbp >= beg)) {
+ set_lwp_id(ph, i, uid);
+ break;
+ }
+ }
+ }
+ (*env)->ReleaseLongArrayElements(env, thrinfos, (jlong*)cinfos, 0);
+ CHECK_EXCEPTION_(false);
+ return true;
+}
+
+/* For core file only, called from
+ * Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0
+ */
+jlongArray getThreadIntegerRegisterSetFromCore(JNIEnv *env, jobject this_obj, long lwp_id) {
+ if (!_threads_filled) {
+ if (!fill_java_threads(env, this_obj, get_proc_handle(env, this_obj))) {
+ throw_new_debugger_exception(env, "Failed to fill in threads");
+ return 0;
+ } else {
+ _threads_filled = true;
+ }
+ }
+
+ struct reg gregs;
+ jboolean isCopy;
+ jlongArray array;
+ jlong *regs;
+
+ struct ps_prochandle* ph = get_proc_handle(env, this_obj);
+ if (get_lwp_regs(ph, lwp_id, &gregs) != true) {
+ THROW_NEW_DEBUGGER_EXCEPTION_("get_thread_regs failed for a lwp", 0);
+ }
+
+#undef NPRGREG
+#undef REG_INDEX
+#if amd64
+#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG
+#define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg
+
+ array = (*env)->NewLongArray(env, NPRGREG);
+ CHECK_EXCEPTION_(0);
+ regs = (*env)->GetLongArrayElements(env, array, &isCopy);
+
+ regs[REG_INDEX(R15)] = gregs.r_r15;
+ regs[REG_INDEX(R14)] = gregs.r_r14;
+ regs[REG_INDEX(R13)] = gregs.r_r13;
+ regs[REG_INDEX(R12)] = gregs.r_r12;
+ regs[REG_INDEX(RBP)] = gregs.r_rbp;
+ regs[REG_INDEX(RBX)] = gregs.r_rbx;
+ regs[REG_INDEX(R11)] = gregs.r_r11;
+ regs[REG_INDEX(R10)] = gregs.r_r10;
+ regs[REG_INDEX(R9)] = gregs.r_r9;
+ regs[REG_INDEX(R8)] = gregs.r_r8;
+ regs[REG_INDEX(RAX)] = gregs.r_rax;
+ regs[REG_INDEX(RCX)] = gregs.r_rcx;
+ regs[REG_INDEX(RDX)] = gregs.r_rdx;
+ regs[REG_INDEX(RSI)] = gregs.r_rsi;
+ regs[REG_INDEX(RDI)] = gregs.r_rdi;
+ regs[REG_INDEX(RIP)] = gregs.r_rip;
+ regs[REG_INDEX(CS)] = gregs.r_cs;
+ regs[REG_INDEX(RSP)] = gregs.r_rsp;
+ regs[REG_INDEX(SS)] = gregs.r_ss;
+ regs[REG_INDEX(FSBASE)] = 0;
+ regs[REG_INDEX(GSBASE)] = 0;
+ regs[REG_INDEX(DS)] = gregs.r_ds;
+ regs[REG_INDEX(ES)] = gregs.r_es;
+ regs[REG_INDEX(FS)] = gregs.r_fs;
+ regs[REG_INDEX(GS)] = gregs.r_gs;
+ regs[REG_INDEX(TRAPNO)] = gregs.r_trapno;
+ regs[REG_INDEX(RFL)] = gregs.r_rflags;
+
+#endif /* amd64 */
+ (*env)->ReleaseLongArrayElements(env, array, regs, JNI_COMMIT);
+ return array;
+}
/*
* Lookup the thread_t that corresponds to the given thread_id.
@@ -232,9 +468,7 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0(
*/
thread_t
lookupThreadFromThreadId(task_t task, jlong thread_id) {
- if (debug) {
- printf("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id);
- }
+ print_debug("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id);
thread_array_t thread_list = NULL;
mach_msg_type_number_t thread_list_count = 0;
@@ -244,9 +478,7 @@ lookupThreadFromThreadId(task_t task, jlong thread_id) {
// get the list of all the send rights
kern_return_t result = task_threads(task, &thread_list, &thread_list_count);
if (result != KERN_SUCCESS) {
- if (debug) {
- printf("task_threads returned 0x%x\n", result);
- }
+ print_debug("task_threads returned 0x%x\n", result);
return 0;
}
@@ -257,9 +489,7 @@ lookupThreadFromThreadId(task_t task, jlong thread_id) {
// get the THREAD_IDENTIFIER_INFO for the send right
result = thread_info(thread_list[i], THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count);
if (result != KERN_SUCCESS) {
- if (debug) {
- printf("thread_info returned 0x%x\n", result);
- }
+ print_debug("thread_info returned 0x%x\n", result);
break;
}
@@ -288,15 +518,17 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0(
JNIEnv *env, jobject this_obj,
jlong thread_id)
{
- if (debug)
- printf("getThreadRegisterSet0 called\n");
+ print_debug("getThreadRegisterSet0 called\n");
+
+ struct ps_prochandle* ph = get_proc_handle(env, this_obj);
+ if (ph->core != NULL) {
+ return getThreadIntegerRegisterSetFromCore(env, this_obj, thread_id);
+ }
kern_return_t result;
thread_t tid;
mach_msg_type_number_t count = HSDB_THREAD_STATE_COUNT;
hsdb_thread_state_t state;
- unsigned int *r;
- int i;
jlongArray registerArray;
jlong *primitiveArray;
task_t gTask = getTask(env, this_obj);
@@ -306,97 +538,56 @@ Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0(
result = thread_get_state(tid, HSDB_THREAD_STATE, (thread_state_t)&state, &count);
if (result != KERN_SUCCESS) {
- if (debug)
- printf("getregs: thread_get_state(%d) failed (%d)\n", tid, result);
+ print_error("getregs: thread_get_state(%d) failed (%d)\n", tid, result);
return NULL;
}
- // 40 32-bit registers on ppc, 16 on x86.
- // Output order is the same as the order in the ppc_thread_state/i386_thread_state struct.
-#if defined(__i386__)
- r = (unsigned int *)&state;
- registerArray = (*env)->NewLongArray(env, 8);
- primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL);
- primitiveArray[0] = r[0]; // eax
- primitiveArray[1] = r[2]; // ecx
- primitiveArray[2] = r[3]; // edx
- primitiveArray[3] = r[1]; // ebx
- primitiveArray[4] = r[7]; // esp
- primitiveArray[5] = r[6]; // ebp
- primitiveArray[6] = r[5]; // esi
- primitiveArray[7] = r[4]; // edi
- (*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0);
-#elif defined(__x86_64__)
- /* From AMD64ThreadContext.java
- public static final int R15 = 0;
- public static final int R14 = 1;
- public static final int R13 = 2;
- public static final int R12 = 3;
- public static final int R11 = 4;
- public static final int R10 = 5;
- public static final int R9 = 6;
- public static final int R8 = 7;
- public static final int RDI = 8;
- public static final int RSI = 9;
- public static final int RBP = 10;
- public static final int RBX = 11;
- public static final int RDX = 12;
- public static final int RCX = 13;
- public static final int RAX = 14;
- public static final int TRAPNO = 15;
- public static final int ERR = 16;
- public static final int RIP = 17;
- public static final int CS = 18;
- public static final int RFL = 19;
- public static final int RSP = 20;
- public static final int SS = 21;
- public static final int FS = 22;
- public static final int GS = 23;
- public static final int ES = 24;
- public static final int DS = 25;
- public static final int FSBASE = 26;
- public static final int GSBASE = 27;
- */
- // 64 bit
- if (debug) printf("Getting threads for a 64-bit process\n");
- registerArray = (*env)->NewLongArray(env, 28);
- primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL);
-
- primitiveArray[0] = state.__r15;
- primitiveArray[1] = state.__r14;
- primitiveArray[2] = state.__r13;
- primitiveArray[3] = state.__r12;
- primitiveArray[4] = state.__r11;
- primitiveArray[5] = state.__r10;
- primitiveArray[6] = state.__r9;
- primitiveArray[7] = state.__r8;
- primitiveArray[8] = state.__rdi;
- primitiveArray[9] = state.__rsi;
- primitiveArray[10] = state.__rbp;
- primitiveArray[11] = state.__rbx;
- primitiveArray[12] = state.__rdx;
- primitiveArray[13] = state.__rcx;
- primitiveArray[14] = state.__rax;
- primitiveArray[15] = 0; // trapno ?
- primitiveArray[16] = 0; // err ?
- primitiveArray[17] = state.__rip;
- primitiveArray[18] = state.__cs;
- primitiveArray[19] = state.__rflags;
- primitiveArray[20] = state.__rsp;
- primitiveArray[21] = 0; // We don't have SS
- primitiveArray[22] = state.__fs;
- primitiveArray[23] = state.__gs;
- primitiveArray[24] = 0;
- primitiveArray[25] = 0;
- primitiveArray[26] = 0;
- primitiveArray[27] = 0;
-
- if (debug) printf("set registers\n");
-
- (*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0);
+#if amd64
+#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG
+#undef REG_INDEX
+#define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg
+
+ // 64 bit
+ print_debug("Getting threads for a 64-bit process\n");
+ registerArray = (*env)->NewLongArray(env, NPRGREG);
+ CHECK_EXCEPTION_(0);
+ primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL);
+
+ primitiveArray[REG_INDEX(R15)] = state.__r15;
+ primitiveArray[REG_INDEX(R14)] = state.__r14;
+ primitiveArray[REG_INDEX(R13)] = state.__r13;
+ primitiveArray[REG_INDEX(R12)] = state.__r12;
+ primitiveArray[REG_INDEX(R11)] = state.__r11;
+ primitiveArray[REG_INDEX(R10)] = state.__r10;
+ primitiveArray[REG_INDEX(R9)] = state.__r9;
+ primitiveArray[REG_INDEX(R8)] = state.__r8;
+ primitiveArray[REG_INDEX(RDI)] = state.__rdi;
+ primitiveArray[REG_INDEX(RSI)] = state.__rsi;
+ primitiveArray[REG_INDEX(RBP)] = state.__rbp;
+ primitiveArray[REG_INDEX(RBX)] = state.__rbx;
+ primitiveArray[REG_INDEX(RDX)] = state.__rdx;
+ primitiveArray[REG_INDEX(RCX)] = state.__rcx;
+ primitiveArray[REG_INDEX(RAX)] = state.__rax;
+ primitiveArray[REG_INDEX(TRAPNO)] = 0; // trapno, not used
+ primitiveArray[REG_INDEX(ERR)] = 0; // err, not used
+ primitiveArray[REG_INDEX(RIP)] = state.__rip;
+ primitiveArray[REG_INDEX(CS)] = state.__cs;
+ primitiveArray[REG_INDEX(RFL)] = state.__rflags;
+ primitiveArray[REG_INDEX(RSP)] = state.__rsp;
+ primitiveArray[REG_INDEX(SS)] = 0; // We don't have SS
+ primitiveArray[REG_INDEX(FS)] = state.__fs;
+ primitiveArray[REG_INDEX(GS)] = state.__gs;
+ primitiveArray[REG_INDEX(ES)] = 0;
+ primitiveArray[REG_INDEX(DS)] = 0;
+ primitiveArray[REG_INDEX(FSBASE)] = 0;
+ primitiveArray[REG_INDEX(GSBASE)] = 0;
+ print_debug("set registers\n");
+
+ (*env)->ReleaseLongArrayElements(env, registerArray, primitiveArray, 0);
+
#else
-#error Unsupported architecture
-#endif
+#error UNSUPPORTED_ARCH
+#endif /* amd64 */
return registerArray;
}
@@ -410,8 +601,7 @@ JNIEXPORT jint JNICALL
Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0(
JNIEnv *env, jobject this_obj, jint tid)
{
- if (debug)
- printf("translateTID0 called on tid = 0x%x\n", (int)tid);
+ print_debug("translateTID0 called on tid = 0x%x\n", (int)tid);
kern_return_t result;
thread_t foreign_tid, usable_tid;
@@ -426,8 +616,7 @@ Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0(
if (result != KERN_SUCCESS)
return -1;
- if (debug)
- printf("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid);
+ print_debug("translateTID0: 0x%x -> 0x%x\n", foreign_tid, usable_tid);
return (jint) usable_tid;
}
@@ -437,7 +626,7 @@ static bool ptrace_continue(pid_t pid, int signal) {
// pass the signal to the process so we don't swallow it
int res;
if ((res = ptrace(PT_CONTINUE, pid, (caddr_t)1, signal)) < 0) {
- fprintf(stderr, "attach: ptrace(PT_CONTINUE, %d) failed with %d\n", pid, res);
+ print_error("attach: ptrace(PT_CONTINUE, %d) failed with %d\n", pid, res);
return false;
}
return true;
@@ -461,11 +650,11 @@ static bool ptrace_waitpid(pid_t pid) {
return true;
}
if (!ptrace_continue(pid, WSTOPSIG(status))) {
- fprintf(stderr, "attach: Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status));
+ print_error("attach: Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status));
return false;
}
} else {
- fprintf(stderr, "attach: waitpid(): Child process exited/terminated (status = 0x%x)\n", status);
+ print_error("attach: waitpid(): Child process exited/terminated (status = 0x%x)\n", status);
return false;
}
} else {
@@ -474,13 +663,13 @@ static bool ptrace_waitpid(pid_t pid) {
continue;
break;
case ECHILD:
- fprintf(stderr, "attach: waitpid() failed. Child process pid (%d) does not exist \n", pid);
+ print_error("attach: waitpid() failed. Child process pid (%d) does not exist \n", pid);
break;
case EINVAL:
- fprintf(stderr, "attach: waitpid() failed. Invalid options argument.\n");
+ print_error("attach: waitpid() failed. Invalid options argument.\n");
break;
default:
- fprintf(stderr, "attach: waitpid() failed. Unexpected error %d\n",errno);
+ print_error("attach: waitpid() failed. Unexpected error %d\n",errno);
break;
}
return false;
@@ -492,7 +681,7 @@ static bool ptrace_waitpid(pid_t pid) {
static bool ptrace_attach(pid_t pid) {
int res;
if ((res = ptrace(PT_ATTACH, pid, 0, 0)) < 0) {
- fprintf(stderr, "ptrace(PT_ATTACH, %d) failed with %d\n", pid, res);
+ print_error("ptrace(PT_ATTACH, %d) failed with %d\n", pid, res);
return false;
} else {
return ptrace_waitpid(pid);
@@ -504,23 +693,19 @@ static bool ptrace_attach(pid_t pid) {
* Method: attach0
* Signature: (I)V
*/
-JNIEXPORT void JNICALL
+JNIEXPORT void JNICALL
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I(
- JNIEnv *env, jobject this_obj, jint jpid)
+ JNIEnv *env, jobject this_obj, jint jpid)
{
+ print_debug("attach0 called for jpid=%d\n", (int)jpid);
+
JNF_COCOA_ENTER(env);
- if (getenv("JAVA_SAPROC_DEBUG") != NULL)
- debug = JNI_TRUE;
- else
- debug = JNI_FALSE;
- if (debug) printf("attach0 called for jpid=%d\n", (int)jpid);
-
- // get the task from the pid
+
kern_return_t result;
task_t gTask = 0;
result = task_for_pid(mach_task_self(), jpid, &gTask);
if (result != KERN_SUCCESS) {
- fprintf(stderr, "attach: task_for_pid(%d) failed (%d)\n", (int)jpid, result);
+ print_error("attach: task_for_pid(%d) failed (%d)\n", (int)jpid, result);
THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
}
putTask(env, this_obj, gTask);
@@ -550,18 +735,79 @@ JNF_COCOA_ENTER(env);
JNF_COCOA_EXIT(env);
}
+/** For core file,
+ called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2 */
+static void fillLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) {
+ int n = 0, i = 0;
+
+ // add load objects
+ n = get_num_libs(ph);
+ for (i = 0; i < n; i++) {
+ uintptr_t base;
+ const char* name;
+ jobject loadObject;
+ jobject loadObjectList;
+
+ base = get_lib_base(ph, i);
+ name = get_lib_name(ph, i);
+ loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID,
+ (*env)->NewStringUTF(env, name), (jlong)0, (jlong)base);
+ CHECK_EXCEPTION;
+ loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID);
+ CHECK_EXCEPTION;
+ (*env)->CallBooleanMethod(env, loadObjectList, listAdd_ID, loadObject);
+ CHECK_EXCEPTION;
+ }
+}
+
+/*
+ * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
+ * Method: attach0
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL
+Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2(
+ JNIEnv *env, jobject this_obj, jstring execName, jstring coreName)
+{
+ const char *execName_cstr;
+ const char *coreName_cstr;
+ jboolean isCopy;
+ struct ps_prochandle* ph;
+
+ execName_cstr = (*env)->GetStringUTFChars(env, execName, &isCopy);
+ CHECK_EXCEPTION;
+ coreName_cstr = (*env)->GetStringUTFChars(env, coreName, &isCopy);
+ CHECK_EXCEPTION;
+
+ print_debug("attach: %s %s\n", execName_cstr, coreName_cstr);
+
+ if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) {
+ (*env)->ReleaseStringUTFChars(env, execName, execName_cstr);
+ (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr);
+ THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file");
+ }
+ (*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph);
+ (*env)->ReleaseStringUTFChars(env, execName, execName_cstr);
+ (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr);
+ fillLoadObjects(env, this_obj, ph);
+}
+
/*
* Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
* Method: detach0
* Signature: ()V
*/
-JNIEXPORT void JNICALL
+JNIEXPORT void JNICALL
Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0(
- JNIEnv *env, jobject this_obj)
+ JNIEnv *env, jobject this_obj)
{
+ print_debug("detach0 called\n");
+ struct ps_prochandle* ph = get_proc_handle(env, this_obj);
+ if (ph != NULL && ph->core != NULL) {
+ Prelease(ph);
+ return;
+ }
JNF_COCOA_ENTER(env);
- if (debug) printf("detach0 called\n");
-
task_t gTask = getTask(env, this_obj);
// detach from the ptraced process causing it to resume execution
@@ -569,15 +815,15 @@ JNF_COCOA_ENTER(env);
kern_return_t k_res;
k_res = pid_for_task(gTask, &pid);
if (k_res != KERN_SUCCESS) {
- fprintf(stderr, "detach: pid_for_task(%d) failed (%d)\n", pid, k_res);
+ print_error("detach: pid_for_task(%d) failed (%d)\n", pid, k_res);
}
else {
int res = ptrace(PT_DETACH, pid, 0, 0);
if (res < 0) {
- fprintf(stderr, "detach: ptrace(PT_DETACH, %d) failed (%d)\n", pid, res);
+ print_error("detach: ptrace(PT_DETACH, %d) failed (%d)\n", pid, res);
}
}
-
+
mach_port_deallocate(mach_task_self(), gTask);
id symbolicator = getSymbolicator(env, this_obj);
if (symbolicator != nil) {
@@ -585,170 +831,3 @@ JNF_COCOA_ENTER(env);
}
JNF_COCOA_EXIT(env);
}
-
-/*
- * Class: sun_jvm_hotspot_asm_Disassembler
- * Method: load_library
- * Signature: (Ljava/lang/String;)L
- */
-JNIEXPORT jlong JNICALL
-Java_sun_jvm_hotspot_asm_Disassembler_load_1library(
- JNIEnv * env,
- jclass disclass,
- jstring jrepath_s,
- jstring libname_s)
-{
- uintptr_t func = 0;
- const char* error_message = NULL;
- const char* java_home;
- jboolean isCopy;
- uintptr_t *handle = NULL;
-
- const char * jrepath = (*env)->GetStringUTFChars(env, jrepath_s, &isCopy); // like $JAVA_HOME/jre/lib/sparc/
- const char * libname = (*env)->GetStringUTFChars(env, libname_s, &isCopy);
- char buffer[128];
-
- /* Load the hsdis library */
- void* hsdis_handle;
- hsdis_handle = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL);
- if (hsdis_handle == NULL) {
- snprintf(buffer, sizeof(buffer), "%s%s", jrepath, libname);
- hsdis_handle = dlopen(buffer, RTLD_LAZY | RTLD_GLOBAL);
- }
- if (hsdis_handle != NULL) {
- func = (uintptr_t)dlsym(hsdis_handle, "decode_instructions_virtual");
- }
- if (func == 0) {
- error_message = dlerror();
- fprintf(stderr, "%s\n", error_message);
- }
-
- (*env)->ReleaseStringUTFChars(env, libname_s, libname);
- (*env)->ReleaseStringUTFChars(env, jrepath_s, jrepath);
-
- if (func == 0) {
- /* Couldn't find entry point. error_message should contain some
- * platform dependent error message.
- */
- THROW_NEW_DEBUGGER_EXCEPTION_(error_message, (jlong)func);
- }
- return (jlong)func;
-}
-
-/* signature of decode_instructions_virtual from hsdis.h */
-typedef void* (*decode_func)(uintptr_t start_va, uintptr_t end_va,
- unsigned char* start, uintptr_t length,
- void* (*event_callback)(void*, const char*, void*),
- void* event_stream,
- int (*printf_callback)(void*, const char*, ...),
- void* printf_stream,
- const char* options);
-
-/* container for call back state when decoding instructions */
-typedef struct {
- JNIEnv* env;
- jobject dis;
- jobject visitor;
- jmethodID handle_event;
- jmethodID raw_print;
- char buffer[4096];
-} decode_env;
-
-
-/* event callback binding to Disassembler.handleEvent */
-static void* event_to_env(void* env_pv, const char* event, void* arg) {
- decode_env* denv = (decode_env*)env_pv;
- JNIEnv* env = denv->env;
- jstring event_string = (*env)->NewStringUTF(env, event);
- jlong result = (*env)->CallLongMethod(env, denv->dis, denv->handle_event, denv->visitor,
- event_string, (jlong) (uintptr_t)arg);
- /* ignore exceptions for now */
- CHECK_EXCEPTION_CLEAR_((void *)0);
- return (void*)(uintptr_t)result;
-}
-
-/* printing callback binding to Disassembler.rawPrint */
-static int printf_to_env(void* env_pv, const char* format, ...) {
- jstring output;
- va_list ap;
- int cnt;
- decode_env* denv = (decode_env*)env_pv;
- JNIEnv* env = denv->env;
- size_t flen = strlen(format);
- const char* raw = NULL;
-
- if (flen == 0) return 0;
- if (flen < 2 ||
- strchr(format, '%') == NULL) {
- raw = format;
- } else if (format[0] == '%' && format[1] == '%' &&
- strchr(format+2, '%') == NULL) {
- // happens a lot on machines with names like %foo
- flen--;
- raw = format+1;
- }
- if (raw != NULL) {
- jstring output = (*env)->NewStringUTF(env, raw);
- (*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output);
- CHECK_EXCEPTION_CLEAR;
- return (int) flen;
- }
- va_start(ap, format);
- cnt = vsnprintf(denv->buffer, sizeof(denv->buffer), format, ap);
- va_end(ap);
-
- output = (*env)->NewStringUTF(env, denv->buffer);
- (*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output);
- CHECK_EXCEPTION_CLEAR;
- return cnt;
-}
-
-/*
- * Class: sun_jvm_hotspot_asm_Disassembler
- * Method: decode
- * Signature: (Lsun/jvm/hotspot/asm/InstructionVisitor;J[BLjava/lang/String;J)V
- */
-JNIEXPORT void JNICALL
-Java_sun_jvm_hotspot_asm_Disassembler_decode(
- JNIEnv * env,
- jobject dis,
- jobject visitor,
- jlong startPc,
- jbyteArray code,
- jstring options_s,
- jlong decode_instructions_virtual)
-{
- jboolean isCopy;
- jbyte* start = (*env)->GetByteArrayElements(env, code, &isCopy);
- jbyte* end = start + (*env)->GetArrayLength(env, code);
- const char * options = (*env)->GetStringUTFChars(env, options_s, &isCopy);
- jclass disclass = (*env)->GetObjectClass(env, dis);
-
- decode_env denv;
- denv.env = env;
- denv.dis = dis;
- denv.visitor = visitor;
-
- /* find Disassembler.handleEvent callback */
- denv.handle_event = (*env)->GetMethodID(env, disclass, "handleEvent",
- "(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;J)J");
- CHECK_EXCEPTION_CLEAR_VOID
-
- /* find Disassembler.rawPrint callback */
- denv.raw_print = (*env)->GetMethodID(env, disclass, "rawPrint",
- "(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;)V");
- CHECK_EXCEPTION_CLEAR_VOID
-
- /* decode the buffer */
- (*(decode_func)(uintptr_t)decode_instructions_virtual)(startPc,
- startPc + end - start,
- (unsigned char*)start,
- end - start,
- &event_to_env, (void*) &denv,
- &printf_to_env, (void*) &denv,
- options);
-
- /* cleanup */
- (*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT);
- (*env)->ReleaseStringUTFChars(env, options_s, options);
-}
diff --git a/agent/src/os/bsd/Makefile b/agent/src/os/bsd/Makefile
index 90085c6ee..ce3e2c4c3 100644
--- a/agent/src/os/bsd/Makefile
+++ b/agent/src/os/bsd/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -22,34 +22,60 @@
#
#
-ARCH := $(shell if ([ `uname -m` = "ia64" ]) ; then echo ia64 ; elif ([ `uname -m` = "amd64" ]) ; then echo amd64; elif ([ `uname -m` = "sparc64" ]) ; then echo sparc; else echo i386 ; fi )
+ARCH := $(shell if ([ `uname -m` = "ia64" ]) ; then echo ia64 ; elif ([ `uname -m` = "amd64" ]) ; then echo amd64; elif ([ `uname -m` = "x86_64" ]) ; then echo amd64; elif ([ `uname -m` = "sparc64" ]) ; then echo sparc; else echo i386 ; fi )
+
+OS := $(shell uname -s)
+
GCC = gcc
JAVAH = ${JAVA_HOME}/bin/javah
+ifneq ($(OS), Darwin)
SOURCES = salibelf.c \
symtab.c \
libproc_impl.c \
ps_proc.c \
ps_core.c \
BsdDebuggerLocal.c
+OBJS = $(SOURCES:.c=.o)
+OBJSPLUS = $(OBJS) sadis.o
+LIBSA = $(ARCH)/libsaproc.so
-INCLUDES = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$(shell uname -s | tr "[:upper:]" "[:lower:]")
+LIBS = -lutil -lthread_db
-OBJS = $(SOURCES:.c=.o)
+else
-LIBS = -lutil -lthread_db
+SOURCES = symtab.c \
+ libproc_impl.c \
+ ps_core.c
+OBJS = $(SOURCES:.c=.o)
+OBJSPLUS = MacosxDebuggerLocal.o sadis.o $(OBJS)
+EXTINCLUDE = -I/System/Library/Frameworks/JavaVM.framework/Headers -I.
+EXTCFLAGS = -m64 -D__APPLE__ -framework JavaNativeFoundation
+FOUNDATIONFLAGS = -framework Foundation -F/System/Library/Frameworks/JavaVM.framework/Frameworks -framework JavaNativeFoundation -framework Security -framework CoreFoundation
+LIBSA = $(ARCH)/libsaproc.dylib
+endif # Darwin
+
+INCLUDES = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$(shell uname -s | tr "[:upper:]" "[:lower:]") $(EXTINCLUDE)
+
+
+
+CFLAGS = -c -fPIC -g -Wall -D_ALLBSD_SOURCE -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) $(EXTCFLAGS)
-CFLAGS = -c -fPIC -g -Wall -D_ALLBSD_SOURCE -D_GNU_SOURCE -D$(ARCH) $(INCLUDES)
-LIBSA = $(ARCH)/libsaproc.so
all: $(LIBSA)
-BsdDebuggerLocal.o: BsdDebuggerLocal.c
- $(JAVAH) -jni -classpath ../../../../../build/bsd-i586/hotspot/outputdir/bsd_i486_compiler2/generated/saclasses \
+MacosxDebuggerLocal.o: MacosxDebuggerLocal.m
+ echo "OS="$(OS)
+ $(JAVAH) -jni -classpath ../../../build/classes \
sun.jvm.hotspot.debugger.x86.X86ThreadContext \
sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext
+ $(GCC) $(CFLAGS) $(FOUNDATIONFLAGS) $<
+
+sadis.o: ../../share/native/sadis.c
+ $(JAVAH) -jni -classpath ../../../build/classes \
+ sun.jvm.hotspot.asm.Disassembler
$(GCC) $(CFLAGS) $<
.c.obj:
@@ -59,9 +85,9 @@ ifndef LDNOMAP
LFLAGS_LIBSA = -Xlinker --version-script=mapfile
endif
-$(LIBSA): $(OBJS) mapfile
+$(LIBSA): $(OBJSPLUS) mapfile
if [ ! -d $(ARCH) ] ; then mkdir $(ARCH) ; fi
- $(GCC) -shared $(LFLAGS_LIBSA) -o $(LIBSA) $(OBJS) $(LIBS)
+ $(GCC) -shared $(LFLAGS_LIBSA) -o $(LIBSA) $(FOUNDATIONFLAGS) $(OBJSPLUS) $(LIBS) $(SALIBS)
test.o: $(LIBSA) test.c
$(GCC) -c -o test.o -g -D_GNU_SOURCE -D$(ARCH) $(INCLUDES) test.c
@@ -71,7 +97,6 @@ test: test.o
clean:
rm -f $(LIBSA)
- rm -f $(OBJS)
+ rm -f *.o
rm -f test.o
-rmdir $(ARCH)
-
diff --git a/agent/src/os/bsd/libproc.h b/agent/src/os/bsd/libproc.h
index 74bb84c17..11e00dcb8 100644
--- a/agent/src/os/bsd/libproc.h
+++ b/agent/src/os/bsd/libproc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,9 +27,38 @@
#include <unistd.h>
#include <stdint.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#ifdef __APPLE__
+typedef enum ps_err_e {
+ PS_OK, PS_ERR, PS_BADPID, PS_BADLID,
+ PS_BADADDR, PS_NOSYM, PS_NOFREGS
+} ps_err_e;
+
+#ifndef psaddr_t
+#define psaddr_t uintptr_t
+#endif
+
+#ifndef bool
+typedef int bool;
+#define true 1
+#define false 0
+#endif // bool
+
+#ifndef lwpid_t
+#define lwpid_t uintptr_t
+#endif
+
+#include <mach/thread_status.h>
+#else // __APPLE__
+#include <elf.h>
+#include <link.h>
#include <machine/reg.h>
#include <proc_service.h>
-
#if defined(sparc) || defined(sparcv9)
/*
If _LP64 is defined ptrace.h should be taken from /usr/include/asm-sparc64
@@ -44,6 +73,14 @@
#endif //sparc or sparcv9
+// This C bool type must be int for compatibility with BSD calls and
+// it would be a mistake to equivalence it to C++ bool on many platforms
+typedef int bool;
+#define true 1
+#define false 0
+
+#endif // __APPLE__
+
/************************************************************************************
0. This is very minimal subset of Solaris libproc just enough for current application.
@@ -72,13 +109,7 @@ combination of ptrace and /proc calls.
*************************************************************************************/
-// This C bool type must be int for compatibility with BSD calls and
-// it would be a mistake to equivalence it to C++ bool on many platforms
-
-typedef int bool;
-#define true 1
-#define false 0
-
+struct reg;
struct ps_prochandle;
// attach to a process
diff --git a/agent/src/os/bsd/libproc_impl.c b/agent/src/os/bsd/libproc_impl.c
index e9fa1b82a..78da80617 100644
--- a/agent/src/os/bsd/libproc_impl.c
+++ b/agent/src/os/bsd/libproc_impl.c
@@ -21,12 +21,6 @@
* questions.
*
*/
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <thread_db.h>
#include "libproc_impl.h"
static const char* alt_root = NULL;
@@ -34,61 +28,65 @@ static int alt_root_len = -1;
#define SA_ALTROOT "SA_ALTROOT"
+off_t ltell(int fd) {
+ return lseek(fd, 0, SEEK_CUR);
+}
+
static void init_alt_root() {
- if (alt_root_len == -1) {
- alt_root = getenv(SA_ALTROOT);
- if (alt_root) {
- alt_root_len = strlen(alt_root);
- } else {
- alt_root_len = 0;
- }
- }
+ if (alt_root_len == -1) {
+ alt_root = getenv(SA_ALTROOT);
+ if (alt_root) {
+ alt_root_len = strlen(alt_root);
+ } else {
+ alt_root_len = 0;
+ }
+ }
}
int pathmap_open(const char* name) {
- int fd;
- char alt_path[PATH_MAX + 1];
+ int fd;
+ char alt_path[PATH_MAX + 1];
+
+ init_alt_root();
- init_alt_root();
- fd = open(name, O_RDONLY);
- if (fd >= 0) {
+ if (alt_root_len > 0) {
+ strcpy(alt_path, alt_root);
+ strcat(alt_path, name);
+ fd = open(alt_path, O_RDONLY);
+ if (fd >= 0) {
+ print_debug("path %s substituted for %s\n", alt_path, name);
return fd;
- }
+ }
- if (alt_root_len > 0) {
+ if (strrchr(name, '/')) {
strcpy(alt_path, alt_root);
- strcat(alt_path, name);
+ strcat(alt_path, strrchr(name, '/'));
fd = open(alt_path, O_RDONLY);
if (fd >= 0) {
- print_debug("path %s substituted for %s\n", alt_path, name);
- return fd;
- }
-
- if (strrchr(name, '/')) {
- strcpy(alt_path, alt_root);
- strcat(alt_path, strrchr(name, '/'));
- fd = open(alt_path, O_RDONLY);
- if (fd >= 0) {
- print_debug("path %s substituted for %s\n", alt_path, name);
- return fd;
- }
+ print_debug("path %s substituted for %s\n", alt_path, name);
+ return fd;
}
- }
-
- return -1;
+ }
+ } else {
+ fd = open(name, O_RDONLY);
+ if (fd >= 0) {
+ return fd;
+ }
+ }
+ return -1;
}
static bool _libsaproc_debug;
void print_debug(const char* format,...) {
- if (_libsaproc_debug) {
- va_list alist;
+ if (_libsaproc_debug) {
+ va_list alist;
- va_start(alist, format);
- fputs("libsaproc DEBUG: ", stderr);
- vfprintf(stderr, format, alist);
- va_end(alist);
- }
+ va_start(alist, format);
+ fputs("libsaproc DEBUG: ", stderr);
+ vfprintf(stderr, format, alist);
+ va_end(alist);
+ }
}
void print_error(const char* format,...) {
@@ -100,172 +98,235 @@ void print_error(const char* format,...) {
}
bool is_debug() {
- return _libsaproc_debug;
+ return _libsaproc_debug;
}
+#ifdef __APPLE__
+// get arch offset in file
+bool get_arch_off(int fd, cpu_type_t cputype, off_t *offset) {
+ struct fat_header fatheader;
+ struct fat_arch fatarch;
+ off_t img_start = 0;
+
+ off_t pos = ltell(fd);
+ if (read(fd, (void *)&fatheader, sizeof(struct fat_header)) != sizeof(struct fat_header)) {
+ return false;
+ }
+ if (fatheader.magic == FAT_CIGAM) {
+ int i;
+ for (i = 0; i < ntohl(fatheader.nfat_arch); i++) {
+ if (read(fd, (void *)&fatarch, sizeof(struct fat_arch)) != sizeof(struct fat_arch)) {
+ return false;
+ }
+ if (ntohl(fatarch.cputype) == cputype) {
+ print_debug("fat offset=%x\n", ntohl(fatarch.offset));
+ img_start = ntohl(fatarch.offset);
+ break;
+ }
+ }
+ if (img_start == 0) {
+ return false;
+ }
+ }
+ lseek(fd, pos, SEEK_SET);
+ *offset = img_start;
+ return true;
+}
+
+bool is_macho_file(int fd) {
+ mach_header_64 fhdr;
+ off_t x86_64_off;
+
+ if (fd < 0) {
+ print_debug("Invalid file handle passed to is_macho_file\n");
+ return false;
+ }
+
+ off_t pos = ltell(fd);
+ // check fat header
+ if (!get_arch_off(fd, CPU_TYPE_X86_64, &x86_64_off)) {
+ print_debug("failed to get fat header\n");
+ return false;
+ }
+ lseek(fd, x86_64_off, SEEK_SET);
+ if (read(fd, (void *)&fhdr, sizeof(mach_header_64)) != sizeof(mach_header_64)) {
+ return false;
+ }
+ lseek(fd, pos, SEEK_SET); // restore
+ print_debug("fhdr.magic %x\n", fhdr.magic);
+ return (fhdr.magic == MH_MAGIC_64 || fhdr.magic == MH_CIGAM_64);
+}
+
+#endif //__APPLE__
+
// initialize libproc
bool init_libproc(bool debug) {
- // init debug mode
_libsaproc_debug = debug;
-
+#ifndef __APPLE__
// initialize the thread_db library
if (td_init() != TD_OK) {
print_debug("libthread_db's td_init failed\n");
return false;
}
-
+#endif // __APPLE__
return true;
}
-static void destroy_lib_info(struct ps_prochandle* ph) {
- lib_info* lib = ph->libs;
- while (lib) {
- lib_info *next = lib->next;
- if (lib->symtab) {
- destroy_symtab(lib->symtab);
- }
- free(lib);
- lib = next;
- }
+void destroy_lib_info(struct ps_prochandle* ph) {
+ lib_info* lib = ph->libs;
+ while (lib) {
+ lib_info* next = lib->next;
+ if (lib->symtab) {
+ destroy_symtab(lib->symtab);
+ }
+ free(lib);
+ lib = next;
+ }
}
-static void destroy_thread_info(struct ps_prochandle* ph) {
- thread_info* thr = ph->threads;
- while (thr) {
- thread_info *next = thr->next;
- free(thr);
- thr = next;
- }
+void destroy_thread_info(struct ps_prochandle* ph) {
+ sa_thread_info* thr = ph->threads;
+ while (thr) {
+ sa_thread_info* n = thr->next;
+ free(thr);
+ thr = n;
+ }
}
// ps_prochandle cleanup
-
-// ps_prochandle cleanup
void Prelease(struct ps_prochandle* ph) {
- // do the "derived class" clean-up first
- ph->ops->release(ph);
- destroy_lib_info(ph);
- destroy_thread_info(ph);
- free(ph);
+ // do the "derived class" clean-up first
+ ph->ops->release(ph);
+ destroy_lib_info(ph);
+ destroy_thread_info(ph);
+ free(ph);
}
lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base) {
- return add_lib_info_fd(ph, libname, -1, base);
+ return add_lib_info_fd(ph, libname, -1, base);
}
lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) {
lib_info* newlib;
+ print_debug("add_lib_info_fd %s\n", libname);
- if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) {
- print_debug("can't allocate memory for lib_info\n");
- return NULL;
- }
+ if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) {
+ print_debug("can't allocate memory for lib_info\n");
+ return NULL;
+ }
- strncpy(newlib->name, libname, sizeof(newlib->name));
- newlib->base = base;
+ strncpy(newlib->name, libname, sizeof(newlib->name));
+ newlib->base = base;
- if (fd == -1) {
- if ( (newlib->fd = pathmap_open(newlib->name)) < 0) {
- print_debug("can't open shared object %s\n", newlib->name);
- free(newlib);
- return NULL;
- }
- } else {
- newlib->fd = fd;
- }
-
- // check whether we have got an ELF file. /proc/<pid>/map
- // gives out all file mappings and not just shared objects
- if (is_elf_file(newlib->fd) == false) {
- close(newlib->fd);
+ if (fd == -1) {
+ if ( (newlib->fd = pathmap_open(newlib->name)) < 0) {
+ print_debug("can't open shared object %s\n", newlib->name);
free(newlib);
return NULL;
- }
+ }
+ } else {
+ newlib->fd = fd;
+ }
- newlib->symtab = build_symtab(newlib->fd);
- if (newlib->symtab == NULL) {
- print_debug("symbol table build failed for %s\n", newlib->name);
- }
- else {
- print_debug("built symbol table for %s\n", newlib->name);
- }
+#ifdef __APPLE__
+ // check whether we have got an Macho file.
+ if (is_macho_file(newlib->fd) == false) {
+ close(newlib->fd);
+ free(newlib);
+ print_debug("not a mach-o file\n");
+ return NULL;
+ }
+#else
+ // check whether we have got an ELF file. /proc/<pid>/map
+ // gives out all file mappings and not just shared objects
+ if (is_elf_file(newlib->fd) == false) {
+ close(newlib->fd);
+ free(newlib);
+ return NULL;
+ }
+#endif // __APPLE__
- // even if symbol table building fails, we add the lib_info.
- // This is because we may need to read from the ELF file for core file
- // address read functionality. lookup_symbol checks for NULL symtab.
- if (ph->libs) {
- ph->lib_tail->next = newlib;
- ph->lib_tail = newlib;
- } else {
- ph->libs = ph->lib_tail = newlib;
- }
- ph->num_libs++;
+ newlib->symtab = build_symtab(newlib->fd);
+ if (newlib->symtab == NULL) {
+ print_debug("symbol table build failed for %s\n", newlib->name);
+ } else {
+ print_debug("built symbol table for %s\n", newlib->name);
+ }
- return newlib;
+ // even if symbol table building fails, we add the lib_info.
+ // This is because we may need to read from the ELF file or MachO file for core file
+ // address read functionality. lookup_symbol checks for NULL symtab.
+ if (ph->libs) {
+ ph->lib_tail->next = newlib;
+ ph->lib_tail = newlib;
+ } else {
+ ph->libs = ph->lib_tail = newlib;
+ }
+ ph->num_libs++;
+ return newlib;
}
// lookup for a specific symbol
uintptr_t lookup_symbol(struct ps_prochandle* ph, const char* object_name,
const char* sym_name) {
- // ignore object_name. search in all libraries
- // FIXME: what should we do with object_name?? The library names are obtained
- // by parsing /proc/<pid>/maps, which may not be the same as object_name.
- // What we need is a utility to map object_name to real file name, something
- // dlopen() does by looking at LD_LIBRARY_PATH and /etc/ld.so.cache. For
- // now, we just ignore object_name and do a global search for the symbol.
-
- lib_info* lib = ph->libs;
- while (lib) {
- if (lib->symtab) {
- uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL);
- if (res) return res;
- }
- lib = lib->next;
- }
+ // ignore object_name. search in all libraries
+ // FIXME: what should we do with object_name?? The library names are obtained
+ // by parsing /proc/<pid>/maps, which may not be the same as object_name.
+ // What we need is a utility to map object_name to real file name, something
+ // dlopen() does by looking at LD_LIBRARY_PATH and /etc/ld.so.cache. For
+ // now, we just ignore object_name and do a global search for the symbol.
+
+ lib_info* lib = ph->libs;
+ while (lib) {
+ if (lib->symtab) {
+ uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL);
+ if (res) return res;
+ }
+ lib = lib->next;
+ }
- print_debug("lookup failed for symbol '%s' in obj '%s'\n",
+ print_debug("lookup failed for symbol '%s' in obj '%s'\n",
sym_name, object_name);
- return (uintptr_t) NULL;
+ return (uintptr_t) NULL;
}
-
const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* poffset) {
- const char* res = NULL;
- lib_info* lib = ph->libs;
- while (lib) {
- if (lib->symtab && addr >= lib->base) {
- res = nearest_symbol(lib->symtab, addr - lib->base, poffset);
- if (res) return res;
- }
- lib = lib->next;
- }
- return NULL;
+ const char* res = NULL;
+ lib_info* lib = ph->libs;
+ while (lib) {
+ if (lib->symtab && addr >= lib->base) {
+ res = nearest_symbol(lib->symtab, addr - lib->base, poffset);
+ if (res) return res;
+ }
+ lib = lib->next;
+ }
+ return NULL;
}
// add a thread to ps_prochandle
-thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) {
- thread_info* newthr;
- if ( (newthr = (thread_info*) calloc(1, sizeof(thread_info))) == NULL) {
- print_debug("can't allocate memory for thread_info\n");
- return NULL;
- }
+sa_thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) {
+ sa_thread_info* newthr;
+ if ( (newthr = (sa_thread_info*) calloc(1, sizeof(sa_thread_info))) == NULL) {
+ print_debug("can't allocate memory for thread_info\n");
+ return NULL;
+ }
- // initialize thread info
- newthr->pthread_id = pthread_id;
- newthr->lwp_id = lwp_id;
+ // initialize thread info
+ newthr->pthread_id = pthread_id;
+ newthr->lwp_id = lwp_id;
- // add new thread to the list
- newthr->next = ph->threads;
- ph->threads = newthr;
- ph->num_threads++;
- return newthr;
+ // add new thread to the list
+ newthr->next = ph->threads;
+ ph->threads = newthr;
+ ph->num_threads++;
+ return newthr;
}
-
+#ifndef __APPLE__
// struct used for client data from thread_db callback
struct thread_db_client_data {
- struct ps_prochandle* ph;
- thread_info_callback callback;
+ struct ps_prochandle* ph;
+ thread_info_callback callback;
};
// callback function for libthread_db
@@ -314,6 +375,7 @@ bool read_thread_info(struct ps_prochandle* ph, thread_info_callback cb) {
return true;
}
+#endif // __APPLE__
// get number of threads
int get_num_threads(struct ps_prochandle* ph) {
@@ -322,18 +384,54 @@ int get_num_threads(struct ps_prochandle* ph) {
// get lwp_id of n'th thread
lwpid_t get_lwp_id(struct ps_prochandle* ph, int index) {
- int count = 0;
- thread_info* thr = ph->threads;
- while (thr) {
- if (count == index) {
- return thr->lwp_id;
- }
- count++;
- thr = thr->next;
- }
- return -1;
+ int count = 0;
+ sa_thread_info* thr = ph->threads;
+ while (thr) {
+ if (count == index) {
+ return thr->lwp_id;
+ }
+ count++;
+ thr = thr->next;
+ }
+ return 0;
}
+#ifdef __APPLE__
+// set lwp_id of n'th thread
+bool set_lwp_id(struct ps_prochandle* ph, int index, lwpid_t lwpid) {
+ int count = 0;
+ sa_thread_info* thr = ph->threads;
+ while (thr) {
+ if (count == index) {
+ thr->lwp_id = lwpid;
+ return true;
+ }
+ count++;
+ thr = thr->next;
+ }
+ return false;
+}
+
+// get regs of n-th thread, only used in fillThreads the first time called
+bool get_nth_lwp_regs(struct ps_prochandle* ph, int index, struct reg* regs) {
+ int count = 0;
+ sa_thread_info* thr = ph->threads;
+ while (thr) {
+ if (count == index) {
+ break;
+ }
+ count++;
+ thr = thr->next;
+ }
+ if (thr != NULL) {
+ memcpy(regs, &thr->regs, sizeof(struct reg));
+ return true;
+ }
+ return false;
+}
+
+#endif // __APPLE__
+
// get regs for a given lwp
bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) {
return ph->ops->get_lwp_regs(ph, lwp_id, regs);
@@ -341,35 +439,35 @@ bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) {
// get number of shared objects
int get_num_libs(struct ps_prochandle* ph) {
- return ph->num_libs;
+ return ph->num_libs;
}
// get name of n'th solib
const char* get_lib_name(struct ps_prochandle* ph, int index) {
- int count = 0;
- lib_info* lib = ph->libs;
- while (lib) {
- if (count == index) {
- return lib->name;
- }
- count++;
- lib = lib->next;
- }
- return NULL;
+ int count = 0;
+ lib_info* lib = ph->libs;
+ while (lib) {
+ if (count == index) {
+ return lib->name;
+ }
+ count++;
+ lib = lib->next;
+ }
+ return NULL;
}
// get base address of a lib
uintptr_t get_lib_base(struct ps_prochandle* ph, int index) {
- int count = 0;
- lib_info* lib = ph->libs;
- while (lib) {
- if (count == index) {
- return lib->base;
- }
- count++;
- lib = lib->next;
- }
- return (uintptr_t)NULL;
+ int count = 0;
+ lib_info* lib = ph->libs;
+ while (lib) {
+ if (count == index) {
+ return lib->base;
+ }
+ count++;
+ lib = lib->next;
+ }
+ return (uintptr_t)NULL;
}
bool find_lib(struct ps_prochandle* ph, const char *lib_name) {
@@ -425,6 +523,7 @@ ps_plog (const char *format, ...)
va_end(alist);
}
+#ifndef __APPLE__
// ------------------------------------------------------------------------
// Functions below this point are not yet implemented. They are here only
// to make the linker happy.
@@ -458,3 +557,4 @@ ps_err_e ps_pcontinue(struct ps_prochandle *ph) {
print_debug("ps_pcontinue not implemented\n");
return PS_OK;
}
+#endif // __APPLE__
diff --git a/agent/src/os/bsd/libproc_impl.h b/agent/src/os/bsd/libproc_impl.h
index 12326c17f..b5cec4d39 100644
--- a/agent/src/os/bsd/libproc_impl.h
+++ b/agent/src/os/bsd/libproc_impl.h
@@ -30,6 +30,60 @@
#include "libproc.h"
#include "symtab.h"
+#ifdef __APPLE__
+#include <inttypes.h> // for PRIx64, 32, ...
+#include <pthread.h>
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+#include <mach-o/fat.h>
+
+#ifndef register_t
+#define register_t uint64_t
+#endif
+
+/*** registers copied from bsd/amd64 */
+typedef struct reg {
+ register_t r_r15;
+ register_t r_r14;
+ register_t r_r13;
+ register_t r_r12;
+ register_t r_r11;
+ register_t r_r10;
+ register_t r_r9;
+ register_t r_r8;
+ register_t r_rdi;
+ register_t r_rsi;
+ register_t r_rbp;
+ register_t r_rbx;
+ register_t r_rdx;
+ register_t r_rcx;
+ register_t r_rax;
+ uint32_t r_trapno; // not used
+ uint16_t r_fs;
+ uint16_t r_gs;
+ uint32_t r_err; // not used
+ uint16_t r_es; // not used
+ uint16_t r_ds; // not used
+ register_t r_rip;
+ register_t r_cs;
+ register_t r_rflags;
+ register_t r_rsp;
+ register_t r_ss; // not used
+} reg;
+
+// convenient defs
+typedef struct mach_header_64 mach_header_64;
+typedef struct load_command load_command;
+typedef struct segment_command_64 segment_command_64;
+typedef struct thread_command thread_command;
+typedef struct dylib_command dylib_command;
+typedef struct symtab_command symtab_command;
+typedef struct nlist_64 nlist_64;
+#else
+#include <thread_db.h>
+#include "salibelf.h"
+#endif // __APPLE__
+
// data structures in this file mimic those of Solaris 8.0 - libproc's Pcontrol.h
#define BUF_SIZE (PATH_MAX + NAME_MAX + 1)
@@ -44,12 +98,12 @@ typedef struct lib_info {
} lib_info;
// list of threads
-typedef struct thread_info {
- lwpid_t lwp_id;
- pthread_t pthread_id; // not used cores, always -1
+typedef struct sa_thread_info {
+ lwpid_t lwp_id; // same as pthread_t
+ pthread_t pthread_id; //
struct reg regs; // not for process, core uses for caching regset
- struct thread_info* next;
-} thread_info;
+ struct sa_thread_info* next;
+} sa_thread_info;
// list of virtual memory maps
typedef struct map_info {
@@ -91,6 +145,7 @@ struct core_data {
// part of the class sharing workaround
map_info* class_share_maps;// class share maps in a linked list
map_info** map_array; // sorted (by vaddr) array of map_info pointers
+ char exec_path[4096]; // file name java
};
struct ps_prochandle {
@@ -100,12 +155,11 @@ struct ps_prochandle {
lib_info* libs; // head of lib list
lib_info* lib_tail; // tail of lib list - to append at the end
int num_threads;
- thread_info* threads; // head of thread list
+ sa_thread_info* threads; // head of thread list
struct core_data* core; // data only used for core dumps, NULL for process
};
int pathmap_open(const char* name);
-
void print_debug(const char* format,...);
void print_error(const char* format,...);
bool is_debug();
@@ -122,10 +176,45 @@ lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t
lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd,
uintptr_t base);
-// adds a new thread to threads list, returns NULL on failure
-thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id);
-
+sa_thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id);
// a test for ELF signature without using libelf
+
+#ifdef __APPLE__
+// a test for Mach-O signature
+bool is_macho_file(int fd);
+// skip fat head to get image start offset of cpu_type_t
+// return false if any error happens, else value in offset.
+bool get_arch_off(int fd, cpu_type_t cputype, off_t *offset);
+#else
bool is_elf_file(int fd);
+#endif // __APPLE__
+
+lwpid_t get_lwp_id(struct ps_prochandle* ph, int index);
+bool set_lwp_id(struct ps_prochandle* ph, int index, lwpid_t lwpid);
+bool get_nth_lwp_regs(struct ps_prochandle* ph, int index, struct reg* regs);
+
+// ps_pglobal_lookup() looks up the symbol sym_name in the symbol table
+// of the load object object_name in the target process identified by ph.
+// It returns the symbol's value as an address in the target process in
+// *sym_addr.
+
+ps_err_e ps_pglobal_lookup(struct ps_prochandle *ph, const char *object_name,
+ const char *sym_name, psaddr_t *sym_addr);
+
+// read "size" bytes info "buf" from address "addr"
+ps_err_e ps_pread(struct ps_prochandle *ph, psaddr_t addr,
+ void *buf, size_t size);
+
+// write "size" bytes of data to debuggee at address "addr"
+ps_err_e ps_pwrite(struct ps_prochandle *ph, psaddr_t addr,
+ const void *buf, size_t size);
+
+// fill in ptrace_lwpinfo for lid
+ps_err_e ps_linfo(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo);
+
+// needed for when libthread_db is compiled with TD_DEBUG defined
+void ps_plog (const char *format, ...);
+// untility, tells the position in file
+off_t ltell(int fd);
#endif //_LIBPROC_IMPL_H_
diff --git a/agent/src/os/bsd/ps_core.c b/agent/src/os/bsd/ps_core.c
index b00a03c57..974e01a6a 100644
--- a/agent/src/os/bsd/ps_core.c
+++ b/agent/src/os/bsd/ps_core.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,10 +28,11 @@
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
-#include <elf.h>
-#include <link.h>
#include "libproc_impl.h"
-#include "salibelf.h"
+
+#ifdef __APPLE__
+#include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h"
+#endif
// This file has the libproc implementation to read core files.
// For live processes, refer to ps_proc.c. Portions of this is adapted
@@ -41,156 +42,158 @@
// ps_prochandle cleanup helper functions
// close all file descriptors
-static void close_elf_files(struct ps_prochandle* ph) {
- lib_info* lib = NULL;
-
- // close core file descriptor
- if (ph->core->core_fd >= 0)
- close(ph->core->core_fd);
-
- // close exec file descriptor
- if (ph->core->exec_fd >= 0)
- close(ph->core->exec_fd);
-
- // close interp file descriptor
- if (ph->core->interp_fd >= 0)
- close(ph->core->interp_fd);
-
- // close class share archive file
- if (ph->core->classes_jsa_fd >= 0)
- close(ph->core->classes_jsa_fd);
-
- // close all library file descriptors
- lib = ph->libs;
- while (lib) {
- int fd = lib->fd;
- if (fd >= 0 && fd != ph->core->exec_fd) close(fd);
- lib = lib->next;
- }
+static void close_files(struct ps_prochandle* ph) {
+ lib_info* lib = NULL;
+ // close core file descriptor
+ if (ph->core->core_fd >= 0)
+ close(ph->core->core_fd);
+
+ // close exec file descriptor
+ if (ph->core->exec_fd >= 0)
+ close(ph->core->exec_fd);
+
+ // close interp file descriptor
+ if (ph->core->interp_fd >= 0)
+ close(ph->core->interp_fd);
+
+ // close class share archive file
+ if (ph->core->classes_jsa_fd >= 0)
+ close(ph->core->classes_jsa_fd);
+
+ // close all library file descriptors
+ lib = ph->libs;
+ while (lib) {
+ int fd = lib->fd;
+ if (fd >= 0 && fd != ph->core->exec_fd) {
+ close(fd);
+ }
+ lib = lib->next;
+ }
}
// clean all map_info stuff
static void destroy_map_info(struct ps_prochandle* ph) {
map_info* map = ph->core->maps;
while (map) {
- map_info* next = map->next;
- free(map);
- map = next;
+ map_info* next = map->next;
+ free(map);
+ map = next;
}
if (ph->core->map_array) {
- free(ph->core->map_array);
+ free(ph->core->map_array);
}
// Part of the class sharing workaround
map = ph->core->class_share_maps;
while (map) {
- map_info* next = map->next;
- free(map);
- map = next;
+ map_info* next = map->next;
+ free(map);
+ map = next;
}
}
// ps_prochandle operations
static void core_release(struct ps_prochandle* ph) {
- if (ph->core) {
- close_elf_files(ph);
- destroy_map_info(ph);
- free(ph->core);
- }
+ if (ph->core) {
+ close_files(ph);
+ destroy_map_info(ph);
+ free(ph->core);
+ }
}
static map_info* allocate_init_map(int fd, off_t offset, uintptr_t vaddr, size_t memsz) {
- map_info* map;
- if ( (map = (map_info*) calloc(1, sizeof(map_info))) == NULL) {
- print_debug("can't allocate memory for map_info\n");
- return NULL;
- }
+ map_info* map;
+ if ( (map = (map_info*) calloc(1, sizeof(map_info))) == NULL) {
+ print_debug("can't allocate memory for map_info\n");
+ return NULL;
+ }
- // initialize map
- map->fd = fd;
- map->offset = offset;
- map->vaddr = vaddr;
- map->memsz = memsz;
- return map;
+ // initialize map
+ map->fd = fd;
+ map->offset = offset;
+ map->vaddr = vaddr;
+ map->memsz = memsz;
+ return map;
}
// add map info with given fd, offset, vaddr and memsz
static map_info* add_map_info(struct ps_prochandle* ph, int fd, off_t offset,
uintptr_t vaddr, size_t memsz) {
- map_info* map;
- if ((map = allocate_init_map(fd, offset, vaddr, memsz)) == NULL) {
- return NULL;
- }
+ map_info* map;
+ if ((map = allocate_init_map(fd, offset, vaddr, memsz)) == NULL) {
+ return NULL;
+ }
- // add this to map list
- map->next = ph->core->maps;
- ph->core->maps = map;
- ph->core->num_maps++;
+ // add this to map list
+ map->next = ph->core->maps;
+ ph->core->maps = map;
+ ph->core->num_maps++;
- return map;
+ return map;
}
// Part of the class sharing workaround
static map_info* add_class_share_map_info(struct ps_prochandle* ph, off_t offset,
uintptr_t vaddr, size_t memsz) {
- map_info* map;
- if ((map = allocate_init_map(ph->core->classes_jsa_fd,
- offset, vaddr, memsz)) == NULL) {
- return NULL;
- }
+ map_info* map;
+ if ((map = allocate_init_map(ph->core->classes_jsa_fd,
+ offset, vaddr, memsz)) == NULL) {
+ return NULL;
+ }
- map->next = ph->core->class_share_maps;
- ph->core->class_share_maps = map;
- return map;
+ map->next = ph->core->class_share_maps;
+ ph->core->class_share_maps = map;
+ return map;
}
// Return the map_info for the given virtual address. We keep a sorted
// array of pointers in ph->map_array, so we can binary search.
static map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr)
{
- int mid, lo = 0, hi = ph->core->num_maps - 1;
- map_info *mp;
-
- while (hi - lo > 1) {
- mid = (lo + hi) / 2;
- if (addr >= ph->core->map_array[mid]->vaddr)
- lo = mid;
- else
- hi = mid;
- }
+ int mid, lo = 0, hi = ph->core->num_maps - 1;
+ map_info *mp;
+
+ while (hi - lo > 1) {
+ mid = (lo + hi) / 2;
+ if (addr >= ph->core->map_array[mid]->vaddr) {
+ lo = mid;
+ } else {
+ hi = mid;
+ }
+ }
- if (addr < ph->core->map_array[hi]->vaddr)
- mp = ph->core->map_array[lo];
- else
- mp = ph->core->map_array[hi];
+ if (addr < ph->core->map_array[hi]->vaddr) {
+ mp = ph->core->map_array[lo];
+ } else {
+ mp = ph->core->map_array[hi];
+ }
- if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz)
- return (mp);
+ if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) {
+ return (mp);
+ }
- // Part of the class sharing workaround
- // Unfortunately, we have no way of detecting -Xshare state.
- // Check out the share maps atlast, if we don't find anywhere.
- // This is done this way so to avoid reading share pages
- // ahead of other normal maps. For eg. with -Xshare:off we don't
- // want to prefer class sharing data to data from core.
- mp = ph->core->class_share_maps;
- if (mp) {
- print_debug("can't locate map_info at 0x%lx, trying class share maps\n",
- addr);
- }
- while (mp) {
- if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) {
- print_debug("located map_info at 0x%lx from class share maps\n",
- addr);
- return (mp);
- }
- mp = mp->next;
- }
+ // Part of the class sharing workaround
+ // Unfortunately, we have no way of detecting -Xshare state.
+ // Check out the share maps atlast, if we don't find anywhere.
+ // This is done this way so to avoid reading share pages
+ // ahead of other normal maps. For eg. with -Xshare:off we don't
+ // want to prefer class sharing data to data from core.
+ mp = ph->core->class_share_maps;
+ if (mp) {
+ print_debug("can't locate map_info at 0x%lx, trying class share maps\n", addr);
+ }
+ while (mp) {
+ if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) {
+ print_debug("located map_info at 0x%lx from class share maps\n", addr);
+ return (mp);
+ }
+ mp = mp->next;
+ }
- print_debug("can't locate map_info at 0x%lx\n", addr);
- return (NULL);
+ print_debug("can't locate map_info at 0x%lx\n", addr);
+ return (NULL);
}
//---------------------------------------------------------------
@@ -239,157 +242,171 @@ struct FileMapHeader {
};
static bool read_jboolean(struct ps_prochandle* ph, uintptr_t addr, jboolean* pvalue) {
- jboolean i;
- if (ps_pread(ph, (psaddr_t) addr, &i, sizeof(i)) == PS_OK) {
- *pvalue = i;
- return true;
- } else {
- return false;
- }
+ jboolean i;
+ if (ps_pread(ph, (psaddr_t) addr, &i, sizeof(i)) == PS_OK) {
+ *pvalue = i;
+ return true;
+ } else {
+ return false;
+ }
}
static bool read_pointer(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* pvalue) {
- uintptr_t uip;
- if (ps_pread(ph, (psaddr_t) addr, &uip, sizeof(uip)) == PS_OK) {
- *pvalue = uip;
- return true;
- } else {
- return false;
- }
+ uintptr_t uip;
+ if (ps_pread(ph, (psaddr_t) addr, (char *)&uip, sizeof(uip)) == PS_OK) {
+ *pvalue = uip;
+ return true;
+ } else {
+ return false;
+ }
}
// used to read strings from debuggee
static bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, size_t size) {
- size_t i = 0;
- char c = ' ';
-
- while (c != '\0') {
- if (ps_pread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK)
- return false;
- if (i < size - 1)
- buf[i] = c;
- else // smaller buffer
- return false;
- i++; addr++;
- }
+ size_t i = 0;
+ char c = ' ';
- buf[i] = '\0';
- return true;
+ while (c != '\0') {
+ if (ps_pread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK) {
+ return false;
+ }
+ if (i < size - 1) {
+ buf[i] = c;
+ } else {
+ // smaller buffer
+ return false;
+ }
+ i++; addr++;
+ }
+ buf[i] = '\0';
+ return true;
}
-#define USE_SHARED_SPACES_SYM "UseSharedSpaces"
+#ifdef __APPLE__
+#define USE_SHARED_SPACES_SYM "_UseSharedSpaces"
// mangled name of Arguments::SharedArchivePath
#define SHARED_ARCHIVE_PATH_SYM "_ZN9Arguments17SharedArchivePathE"
+#else
+#define USE_SHARED_SPACES_SYM "UseSharedSpaces"
+// mangled name of Arguments::SharedArchivePath
+#define SHARED_ARCHIVE_PATH_SYM "__ZN9Arguments17SharedArchivePathE"
+#endif // __APPLE_
static bool init_classsharing_workaround(struct ps_prochandle* ph) {
- lib_info* lib = ph->libs;
- while (lib != NULL) {
- // we are iterating over shared objects from the core dump. look for
- // libjvm[_g].so.
- const char *jvm_name = 0;
- if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0 ||
- (jvm_name = strstr(lib->name, "/libjvm_g.so")) != 0) {
- char classes_jsa[PATH_MAX];
- struct FileMapHeader header;
- size_t n = 0;
- int fd = -1, m = 0;
- uintptr_t base = 0, useSharedSpacesAddr = 0;
- uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0;
- jboolean useSharedSpaces = 0;
-
- memset(classes_jsa, 0, sizeof(classes_jsa));
- jvm_name = lib->name;
- useSharedSpacesAddr = lookup_symbol(ph, jvm_name, USE_SHARED_SPACES_SYM);
- if (useSharedSpacesAddr == 0) {
- print_debug("can't lookup 'UseSharedSpaces' flag\n");
- return false;
- }
+ int m;
+ size_t n;
+ lib_info* lib = ph->libs;
+ while (lib != NULL) {
+ // we are iterating over shared objects from the core dump. look for
+ // libjvm[_g].so.
+ const char *jvm_name = 0;
+#ifdef __APPLE__
+ if ((jvm_name = strstr(lib->name, "/libjvm.dylib")) != 0 ||
+ (jvm_name = strstr(lib->name, "/libjvm_g.dylib")) != 0)
+#else
+ if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0 ||
+ (jvm_name = strstr(lib->name, "/libjvm_g.so")) != 0)
+#endif // __APPLE__
+ {
+ char classes_jsa[PATH_MAX];
+ struct FileMapHeader header;
+ int fd = -1;
+ uintptr_t base = 0, useSharedSpacesAddr = 0;
+ uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0;
+ jboolean useSharedSpaces = 0;
+
+ memset(classes_jsa, 0, sizeof(classes_jsa));
+ jvm_name = lib->name;
+ useSharedSpacesAddr = lookup_symbol(ph, jvm_name, USE_SHARED_SPACES_SYM);
+ if (useSharedSpacesAddr == 0) {
+ print_debug("can't lookup 'UseSharedSpaces' flag\n");
+ return false;
+ }
- // Hotspot vm types are not exported to build this library. So
- // using equivalent type jboolean to read the value of
- // UseSharedSpaces which is same as hotspot type "bool".
- if (read_jboolean(ph, useSharedSpacesAddr, &useSharedSpaces) != true) {
- print_debug("can't read the value of 'UseSharedSpaces' flag\n");
- return false;
- }
+ // Hotspot vm types are not exported to build this library. So
+ // using equivalent type jboolean to read the value of
+ // UseSharedSpaces which is same as hotspot type "bool".
+ if (read_jboolean(ph, useSharedSpacesAddr, &useSharedSpaces) != true) {
+ print_debug("can't read the value of 'UseSharedSpaces' flag\n");
+ return false;
+ }
- if ((int)useSharedSpaces == 0) {
- print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n");
- return true;
- }
+ if ((int)useSharedSpaces == 0) {
+ print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n");
+ return true;
+ }
- sharedArchivePathAddrAddr = lookup_symbol(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM);
- if (sharedArchivePathAddrAddr == 0) {
- print_debug("can't lookup shared archive path symbol\n");
- return false;
- }
+ sharedArchivePathAddrAddr = lookup_symbol(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM);
+ if (sharedArchivePathAddrAddr == 0) {
+ print_debug("can't lookup shared archive path symbol\n");
+ return false;
+ }
- if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) {
- print_debug("can't read shared archive path pointer\n");
- return false;
- }
+ if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) {
+ print_debug("can't read shared archive path pointer\n");
+ return false;
+ }
- if (read_string(ph, sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) {
- print_debug("can't read shared archive path value\n");
- return false;
- }
+ if (read_string(ph, sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) {
+ print_debug("can't read shared archive path value\n");
+ return false;
+ }
- print_debug("looking for %s\n", classes_jsa);
- // open the class sharing archive file
- fd = pathmap_open(classes_jsa);
- if (fd < 0) {
- print_debug("can't open %s!\n", classes_jsa);
- ph->core->classes_jsa_fd = -1;
- return false;
- } else {
- print_debug("opened %s\n", classes_jsa);
- }
+ print_debug("looking for %s\n", classes_jsa);
+ // open the class sharing archive file
+ fd = pathmap_open(classes_jsa);
+ if (fd < 0) {
+ print_debug("can't open %s!\n", classes_jsa);
+ ph->core->classes_jsa_fd = -1;
+ return false;
+ } else {
+ print_debug("opened %s\n", classes_jsa);
+ }
- // read FileMapHeader from the file
- memset(&header, 0, sizeof(struct FileMapHeader));
- if ((n = read(fd, &header, sizeof(struct FileMapHeader)))
- != sizeof(struct FileMapHeader)) {
- print_debug("can't read shared archive file map header from %s\n", classes_jsa);
- close(fd);
- return false;
- }
+ // read FileMapHeader from the file
+ memset(&header, 0, sizeof(struct FileMapHeader));
+ if ((n = read(fd, &header, sizeof(struct FileMapHeader)))
+ != sizeof(struct FileMapHeader)) {
+ print_debug("can't read shared archive file map header from %s\n", classes_jsa);
+ close(fd);
+ return false;
+ }
- // check file magic
- if (header._magic != 0xf00baba2) {
- print_debug("%s has bad shared archive file magic number 0x%x, expecing 0xf00baba2\n",
- classes_jsa, header._magic);
- close(fd);
- return false;
- }
+ // check file magic
+ if (header._magic != 0xf00baba2) {
+ print_debug("%s has bad shared archive file magic number 0x%x, expecing 0xf00baba2\n",
+ classes_jsa, header._magic);
+ close(fd);
+ return false;
+ }
- // check version
- if (header._version != CURRENT_ARCHIVE_VERSION) {
- print_debug("%s has wrong shared archive file version %d, expecting %d\n",
- classes_jsa, header._version, CURRENT_ARCHIVE_VERSION);
- close(fd);
- return false;
- }
+ // check version
+ if (header._version != CURRENT_ARCHIVE_VERSION) {
+ print_debug("%s has wrong shared archive file version %d, expecting %d\n",
+ classes_jsa, header._version, CURRENT_ARCHIVE_VERSION);
+ close(fd);
+ return false;
+ }
- ph->core->classes_jsa_fd = fd;
- // add read-only maps from classes[_g].jsa to the list of maps
- for (m = 0; m < NUM_SHARED_MAPS; m++) {
- if (header._space[m]._read_only) {
- base = (uintptr_t) header._space[m]._base;
- // no need to worry about the fractional pages at-the-end.
- // possible fractional pages are handled by core_read_data.
- add_class_share_map_info(ph, (off_t) header._space[m]._file_offset,
- base, (size_t) header._space[m]._used);
- print_debug("added a share archive map at 0x%lx\n", base);
- }
- }
- return true;
+ ph->core->classes_jsa_fd = fd;
+ // add read-only maps from classes[_g].jsa to the list of maps
+ for (m = 0; m < NUM_SHARED_MAPS; m++) {
+ if (header._space[m]._read_only) {
+ base = (uintptr_t) header._space[m]._base;
+ // no need to worry about the fractional pages at-the-end.
+ // possible fractional pages are handled by core_read_data.
+ add_class_share_map_info(ph, (off_t) header._space[m]._file_offset,
+ base, (size_t) header._space[m]._used);
+ print_debug("added a share archive map at 0x%lx\n", base);
+ }
}
- lib = lib->next;
- }
- return true;
+ return true;
+ }
+ lib = lib->next;
+ }
+ return true;
}
-
//---------------------------------------------------------------------------
// functions to handle map_info
@@ -397,54 +414,57 @@ static bool init_classsharing_workaround(struct ps_prochandle* ph) {
// callback for sorting the array of map_info pointers.
static int core_cmp_mapping(const void *lhsp, const void *rhsp)
{
- const map_info *lhs = *((const map_info **)lhsp);
- const map_info *rhs = *((const map_info **)rhsp);
+ const map_info *lhs = *((const map_info **)lhsp);
+ const map_info *rhs = *((const map_info **)rhsp);
- if (lhs->vaddr == rhs->vaddr)
- return (0);
+ if (lhs->vaddr == rhs->vaddr) {
+ return (0);
+ }
- return (lhs->vaddr < rhs->vaddr ? -1 : 1);
+ return (lhs->vaddr < rhs->vaddr ? -1 : 1);
}
// we sort map_info by starting virtual address so that we can do
// binary search to read from an address.
static bool sort_map_array(struct ps_prochandle* ph) {
- size_t num_maps = ph->core->num_maps;
- map_info* map = ph->core->maps;
- int i = 0;
-
- // allocate map_array
- map_info** array;
- if ( (array = (map_info**) malloc(sizeof(map_info*) * num_maps)) == NULL) {
- print_debug("can't allocate memory for map array\n");
- return false;
- }
+ size_t num_maps = ph->core->num_maps;
+ map_info* map = ph->core->maps;
+ int i = 0;
- // add maps to array
- while (map) {
- array[i] = map;
- i++;
- map = map->next;
- }
+ // allocate map_array
+ map_info** array;
+ if ( (array = (map_info**) malloc(sizeof(map_info*) * num_maps)) == NULL) {
+ print_debug("can't allocate memory for map array\n");
+ return false;
+ }
- // sort is called twice. If this is second time, clear map array
- if (ph->core->map_array) free(ph->core->map_array);
- ph->core->map_array = array;
- // sort the map_info array by base virtual address.
- qsort(ph->core->map_array, ph->core->num_maps, sizeof (map_info*),
- core_cmp_mapping);
+ // add maps to array
+ while (map) {
+ array[i] = map;
+ i++;
+ map = map->next;
+ }
- // print map
- if (is_debug()) {
- int j = 0;
- print_debug("---- sorted virtual address map ----\n");
- for (j = 0; j < ph->core->num_maps; j++) {
- print_debug("base = 0x%lx\tsize = %d\n", ph->core->map_array[j]->vaddr,
- ph->core->map_array[j]->memsz);
- }
- }
+ // sort is called twice. If this is second time, clear map array
+ if (ph->core->map_array) {
+ free(ph->core->map_array);
+ }
+ ph->core->map_array = array;
+ // sort the map_info array by base virtual address.
+ qsort(ph->core->map_array, ph->core->num_maps, sizeof (map_info*),
+ core_cmp_mapping);
+
+ // print map
+ if (is_debug()) {
+ int j = 0;
+ print_debug("---- sorted virtual address map ----\n");
+ for (j = 0; j < ph->core->num_maps; j++) {
+ print_debug("base = 0x%lx\tsize = %d\n", ph->core->map_array[j]->vaddr,
+ ph->core->map_array[j]->memsz);
+ }
+ }
- return true;
+ return true;
}
#ifndef MIN
@@ -461,16 +481,18 @@ static bool core_read_data(struct ps_prochandle* ph, uintptr_t addr, char *buf,
off_t off;
int fd;
- if (mp == NULL)
+ if (mp == NULL) {
break; /* No mapping for this address */
+ }
fd = mp->fd;
mapoff = addr - mp->vaddr;
len = MIN(resid, mp->memsz - mapoff);
off = mp->offset + mapoff;
- if ((len = pread(fd, buf, len, off)) <= 0)
+ if ((len = pread(fd, buf, len, off)) <= 0) {
break;
+ }
resid -= len;
addr += len;
@@ -507,8 +529,8 @@ static bool core_write_data(struct ps_prochandle* ph,
static bool core_get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id,
struct reg* regs) {
- // for core we have cached the lwp regs from NOTE section
- thread_info* thr = ph->threads;
+ // for core we have cached the lwp regs after segment parsed
+ sa_thread_info* thr = ph->threads;
while (thr) {
if (thr->lwp_id == lwp_id) {
memcpy(regs, &thr->regs, sizeof(struct reg));
@@ -519,7 +541,7 @@ static bool core_get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id,
return false;
}
-static bool core_get_lwp_info(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo) {
+static bool core_get_lwp_info(struct ps_prochandle *ph, lwpid_t id, void *info) {
print_debug("core_get_lwp_info not implemented\n");
return false;
}
@@ -532,12 +554,451 @@ static ps_prochandle_ops core_ops = {
.get_lwp_info= core_get_lwp_info
};
-// read regs and create thread from NT_PRSTATUS entries from core file
+// from this point, mainly two blocks divided by def __APPLE__
+// one for Macosx, the other for regular Bsd
+
+#ifdef __APPLE__
+
+void print_thread(sa_thread_info *threadinfo) {
+ print_debug("thread added: %d\n", threadinfo->lwp_id);
+ print_debug("registers:\n");
+ print_debug(" r_r15: 0x%" PRIx64 "\n", threadinfo->regs.r_r15);
+ print_debug(" r_r14: 0x%" PRIx64 "\n", threadinfo->regs.r_r14);
+ print_debug(" r_r13: 0x%" PRIx64 "\n", threadinfo->regs.r_r13);
+ print_debug(" r_r12: 0x%" PRIx64 "\n", threadinfo->regs.r_r12);
+ print_debug(" r_r11: 0x%" PRIx64 "\n", threadinfo->regs.r_r11);
+ print_debug(" r_r10: 0x%" PRIx64 "\n", threadinfo->regs.r_r10);
+ print_debug(" r_r9: 0x%" PRIx64 "\n", threadinfo->regs.r_r9);
+ print_debug(" r_r8: 0x%" PRIx64 "\n", threadinfo->regs.r_r8);
+ print_debug(" r_rdi: 0x%" PRIx64 "\n", threadinfo->regs.r_rdi);
+ print_debug(" r_rsi: 0x%" PRIx64 "\n", threadinfo->regs.r_rsi);
+ print_debug(" r_rbp: 0x%" PRIx64 "\n", threadinfo->regs.r_rbp);
+ print_debug(" r_rbx: 0x%" PRIx64 "\n", threadinfo->regs.r_rbx);
+ print_debug(" r_rdx: 0x%" PRIx64 "\n", threadinfo->regs.r_rdx);
+ print_debug(" r_rcx: 0x%" PRIx64 "\n", threadinfo->regs.r_rcx);
+ print_debug(" r_rax: 0x%" PRIx64 "\n", threadinfo->regs.r_rax);
+ print_debug(" r_fs: 0x%" PRIx32 "\n", threadinfo->regs.r_fs);
+ print_debug(" r_gs: 0x%" PRIx32 "\n", threadinfo->regs.r_gs);
+ print_debug(" r_rip 0x%" PRIx64 "\n", threadinfo->regs.r_rip);
+ print_debug(" r_cs: 0x%" PRIx64 "\n", threadinfo->regs.r_cs);
+ print_debug(" r_rsp: 0x%" PRIx64 "\n", threadinfo->regs.r_rsp);
+ print_debug(" r_rflags: 0x%" PRIx64 "\n", threadinfo->regs.r_rflags);
+}
+
+// read all segments64 commands from core file
+// read all thread commands from core file
+static bool read_core_segments(struct ps_prochandle* ph) {
+ int i = 0;
+ int num_threads = 0;
+ int fd = ph->core->core_fd;
+ off_t offset = 0;
+ mach_header_64 fhead;
+ load_command lcmd;
+ segment_command_64 segcmd;
+ // thread_command thrcmd;
+
+ lseek(fd, offset, SEEK_SET);
+ if(read(fd, (void *)&fhead, sizeof(mach_header_64)) != sizeof(mach_header_64)) {
+ goto err;
+ }
+ print_debug("total commands: %d\n", fhead.ncmds);
+ offset += sizeof(mach_header_64);
+ for (i = 0; i < fhead.ncmds; i++) {
+ lseek(fd, offset, SEEK_SET);
+ if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) {
+ goto err;
+ }
+ offset += lcmd.cmdsize; // next command position
+ if (lcmd.cmd == LC_SEGMENT_64) {
+ lseek(fd, -sizeof(load_command), SEEK_CUR);
+ if (read(fd, (void *)&segcmd, sizeof(segment_command_64)) != sizeof(segment_command_64)) {
+ print_debug("failed to read LC_SEGMENT_64 i = %d!\n", i);
+ goto err;
+ }
+ if (add_map_info(ph, fd, segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize) == NULL) {
+ print_debug("Failed to add map_info at i = %d\n", i);
+ goto err;
+ }
+ print_debug("segment added: %" PRIu64 " 0x%" PRIx64 " %d\n",
+ segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize);
+ } else if (lcmd.cmd == LC_THREAD || lcmd.cmd == LC_UNIXTHREAD) {
+ typedef struct thread_fc {
+ uint32_t flavor;
+ uint32_t count;
+ } thread_fc;
+ thread_fc fc;
+ uint32_t size = sizeof(load_command);
+ while (size < lcmd.cmdsize) {
+ if (read(fd, (void *)&fc, sizeof(thread_fc)) != sizeof(thread_fc)) {
+ printf("Reading flavor, count failed.\n");
+ goto err;
+ }
+ size += sizeof(thread_fc);
+ if (fc.flavor == x86_THREAD_STATE) {
+ x86_thread_state_t thrstate;
+ if (read(fd, (void *)&thrstate, sizeof(x86_thread_state_t)) != sizeof(x86_thread_state_t)) {
+ printf("Reading flavor, count failed.\n");
+ goto err;
+ }
+ size += sizeof(x86_thread_state_t);
+ // create thread info list, update lwp_id later
+ sa_thread_info* newthr = add_thread_info(ph, (pthread_t) -1, (lwpid_t) num_threads++);
+ if (newthr == NULL) {
+ printf("create thread_info failed\n");
+ goto err;
+ }
+
+ // note __DARWIN_UNIX03 depengs on other definitions
+#if __DARWIN_UNIX03
+#define get_register_v(regst, regname) \
+ regst.uts.ts64.__##regname
+#else
+#define get_register_v(regst, regname) \
+ regst.uts.ts64.##regname
+#endif // __DARWIN_UNIX03
+ newthr->regs.r_rax = get_register_v(thrstate, rax);
+ newthr->regs.r_rbx = get_register_v(thrstate, rbx);
+ newthr->regs.r_rcx = get_register_v(thrstate, rcx);
+ newthr->regs.r_rdx = get_register_v(thrstate, rdx);
+ newthr->regs.r_rdi = get_register_v(thrstate, rdi);
+ newthr->regs.r_rsi = get_register_v(thrstate, rsi);
+ newthr->regs.r_rbp = get_register_v(thrstate, rbp);
+ newthr->regs.r_rsp = get_register_v(thrstate, rsp);
+ newthr->regs.r_r8 = get_register_v(thrstate, r8);
+ newthr->regs.r_r9 = get_register_v(thrstate, r9);
+ newthr->regs.r_r10 = get_register_v(thrstate, r10);
+ newthr->regs.r_r11 = get_register_v(thrstate, r11);
+ newthr->regs.r_r12 = get_register_v(thrstate, r12);
+ newthr->regs.r_r13 = get_register_v(thrstate, r13);
+ newthr->regs.r_r14 = get_register_v(thrstate, r14);
+ newthr->regs.r_r15 = get_register_v(thrstate, r15);
+ newthr->regs.r_rip = get_register_v(thrstate, rip);
+ newthr->regs.r_rflags = get_register_v(thrstate, rflags);
+ newthr->regs.r_cs = get_register_v(thrstate, cs);
+ newthr->regs.r_fs = get_register_v(thrstate, fs);
+ newthr->regs.r_gs = get_register_v(thrstate, gs);
+ print_thread(newthr);
+ } else if (fc.flavor == x86_FLOAT_STATE) {
+ x86_float_state_t flstate;
+ if (read(fd, (void *)&flstate, sizeof(x86_float_state_t)) != sizeof(x86_float_state_t)) {
+ print_debug("Reading flavor, count failed.\n");
+ goto err;
+ }
+ size += sizeof(x86_float_state_t);
+ } else if (fc.flavor == x86_EXCEPTION_STATE) {
+ x86_exception_state_t excpstate;
+ if (read(fd, (void *)&excpstate, sizeof(x86_exception_state_t)) != sizeof(x86_exception_state_t)) {
+ printf("Reading flavor, count failed.\n");
+ goto err;
+ }
+ size += sizeof(x86_exception_state_t);
+ }
+ }
+ }
+ }
+ return true;
+err:
+ return false;
+}
+
+/**local function **/
+bool exists(const char *fname)
+{
+ int fd;
+ if ((fd = open(fname, O_RDONLY)) > 0) {
+ close(fd);
+ return true;
+ }
+ return false;
+}
+
+// we check: 1. lib
+// 2. lib/server
+// 3. jre/lib
+// 4. jre/lib/server
+// from: 1. exe path
+// 2. JAVA_HOME
+// 3. DYLD_LIBRARY_PATH
+static bool get_real_path(struct ps_prochandle* ph, char *rpath) {
+ /** check if they exist in JAVA ***/
+ char* execname = ph->core->exec_path;
+ char filepath[4096];
+ char* filename = strrchr(rpath, '/'); // like /libjvm.dylib
+ if (filename == NULL) {
+ return false;
+ }
+
+ char* posbin = strstr(execname, "/bin/java");
+ if (posbin != NULL) {
+ memcpy(filepath, execname, posbin - execname); // not include trailing '/'
+ filepath[posbin - execname] = '\0';
+ } else {
+ char* java_home = getenv("JAVA_HOME");
+ if (java_home != NULL) {
+ strcpy(filepath, java_home);
+ } else {
+ char* dyldpath = getenv("DYLD_LIBRARY_PATH");
+ char* dypath = strtok(dyldpath, ":");
+ while (dypath != NULL) {
+ strcpy(filepath, dypath);
+ strcat(filepath, filename);
+ if (exists(filepath)) {
+ strcpy(rpath, filepath);
+ return true;
+ }
+ dypath = strtok(dyldpath, ":");
+ }
+ // not found
+ return false;
+ }
+ }
+ // for exec and java_home, jdkpath now is filepath
+ size_t filepath_base_size = strlen(filepath);
+
+ // first try /lib/ and /lib/server
+ strcat(filepath, "/lib");
+ strcat(filepath, filename);
+ if (exists(filepath)) {
+ strcpy(rpath, filepath);
+ return true;
+ }
+ char* pos = strstr(filepath, filename); // like /libjvm.dylib
+ *pos = '\0';
+ strcat(filepath, "/server");
+ strcat(filepath, filename);
+ if (exists(filepath)) {
+ strcpy(rpath, filepath);
+ return true;
+ }
+
+ // then try /jre/lib/ and /jre/lib/server
+ filepath[filepath_base_size] = '\0';
+ strcat(filepath, "/jre/lib");
+ strcat(filepath, filename);
+ if (exists(filepath)) {
+ strcpy(rpath, filepath);
+ return true;
+ }
+ pos = strstr(filepath, filename);
+ *pos = '\0';
+ strcat(filepath, "/server");
+ strcat(filepath, filename);
+ if (exists(filepath)) {
+ strcpy(rpath, filepath);
+ return true;
+ }
+
+ return false;
+}
+
+static bool read_shared_lib_info(struct ps_prochandle* ph) {
+ static int pagesize = 0;
+ int fd = ph->core->core_fd;
+ int i = 0, j;
+ uint32_t v;
+ mach_header_64 header; // used to check if a file header in segment
+ load_command lcmd;
+ dylib_command dylibcmd;
+
+ char name[BUF_SIZE]; // use to store name
+
+ if (pagesize == 0) {
+ pagesize = getpagesize();
+ print_debug("page size is %d\n", pagesize);
+ }
+ for (j = 0; j < ph->core->num_maps; j++) {
+ map_info *iter = ph->core->map_array[j]; // head
+ off_t fpos = iter->offset;
+ if (iter->fd != fd) {
+ // only search core file!
+ continue;
+ }
+ print_debug("map_info %d: vmaddr = 0x%016" PRIx64 " fileoff = %" PRIu64 " vmsize = %" PRIu64 "\n",
+ j, iter->vaddr, iter->offset, iter->memsz);
+ lseek(fd, fpos, SEEK_SET);
+ // we assume .dylib loaded at segment address --- which is true for JVM libraries
+ // multiple files may be loaded in one segment.
+ // if first word is not a magic word, means this segment does not contain lib file.
+ if (read(fd, (void *)&v, sizeof(uint32_t)) == sizeof(uint32_t)) {
+ if (v != MH_MAGIC_64) {
+ continue;
+ }
+ } else {
+ // may be encountered last map, which is not readable
+ continue;
+ }
+ while (ltell(fd) - iter->offset < iter->memsz) {
+ lseek(fd, fpos, SEEK_SET);
+ if (read(fd, (void *)&v, sizeof(uint32_t)) != sizeof(uint32_t)) {
+ break;
+ }
+ if (v != MH_MAGIC_64) {
+ fpos = (ltell(fd) + pagesize -1)/pagesize * pagesize;
+ continue;
+ }
+ lseek(fd, -sizeof(uint32_t), SEEK_CUR);
+ // this is the file begining to core file.
+ if (read(fd, (void *)&header, sizeof(mach_header_64)) != sizeof(mach_header_64)) {
+ goto err;
+ }
+ fpos = ltell(fd);
+
+ // found a mach-o file in this segment
+ for (i = 0; i < header.ncmds; i++) {
+ // read commands in this "file"
+ // LC_ID_DYLIB is the file itself for a .dylib
+ lseek(fd, fpos, SEEK_SET);
+ if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) {
+ return false; // error
+ }
+ fpos += lcmd.cmdsize; // next command position
+ // make sure still within seg size.
+ if (fpos - lcmd.cmdsize - iter->offset > iter->memsz) {
+ print_debug("Warning: out of segement limit: %ld \n", fpos - lcmd.cmdsize - iter->offset);
+ break; // no need to iterate all commands
+ }
+ if (lcmd.cmd == LC_ID_DYLIB) {
+ lseek(fd, -sizeof(load_command), SEEK_CUR);
+ if (read(fd, (void *)&dylibcmd, sizeof(dylib_command)) != sizeof(dylib_command)) {
+ return false;
+ }
+ /**** name stored at dylib_command.dylib.name.offset, is a C string */
+ lseek(fd, dylibcmd.dylib.name.offset - sizeof(dylib_command), SEEK_CUR);
+ int j = 0;
+ while (j < BUF_SIZE) {
+ read(fd, (void *)(name + j), sizeof(char));
+ if (name[j] == '\0') break;
+ j++;
+ }
+ print_debug("%s\n", name);
+ // changed name from @rpath/xxxx.dylib to real path
+ if (strrchr(name, '@')) {
+ get_real_path(ph, name);
+ print_debug("get_real_path returned: %s\n", name);
+ }
+ add_lib_info(ph, name, iter->vaddr);
+ break;
+ }
+ }
+ // done with the file, advanced to next page to search more files
+ fpos = (ltell(fd) + pagesize - 1) / pagesize * pagesize;
+ }
+ }
+ return true;
+err:
+ return false;
+}
+
+bool read_macho64_header(int fd, mach_header_64* core_header) {
+ bool is_macho = false;
+ if (fd < 0) return false;
+ off_t pos = ltell(fd);
+ lseek(fd, 0, SEEK_SET);
+ if (read(fd, (void *)core_header, sizeof(mach_header_64)) != sizeof(mach_header_64)) {
+ is_macho = false;
+ } else {
+ is_macho = (core_header->magic == MH_MAGIC_64 || core_header->magic == MH_CIGAM_64);
+ }
+ lseek(fd, pos, SEEK_SET);
+ return is_macho;
+}
+
+// the one and only one exposed stuff from this file
+struct ps_prochandle* Pgrab_core(const char* exec_file, const char* core_file) {
+ mach_header_64 core_header;
+ mach_header_64 exec_header;
+
+ struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle));
+ if (ph == NULL) {
+ print_debug("cant allocate ps_prochandle\n");
+ return NULL;
+ }
+
+ if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) {
+ free(ph);
+ print_debug("can't allocate ps_prochandle\n");
+ return NULL;
+ }
+
+ // initialize ph
+ ph->ops = &core_ops;
+ ph->core->core_fd = -1;
+ ph->core->exec_fd = -1;
+ ph->core->interp_fd = -1;
+
+ print_debug("exec: %s core: %s", exec_file, core_file);
+
+ strncpy(ph->core->exec_path, exec_file, sizeof(ph->core->exec_path));
+
+ // open the core file
+ if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) {
+ print_error("can't open core file\n");
+ goto err;
+ }
+
+ // read core file header
+ if (read_macho64_header(ph->core->core_fd, &core_header) != true || core_header.filetype != MH_CORE) {
+ print_debug("core file is not a valid Mach-O file\n");
+ goto err;
+ }
+
+ if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) {
+ print_error("can't open executable file\n");
+ goto err;
+ }
+
+ if (read_macho64_header(ph->core->exec_fd, &exec_header) != true ||
+ exec_header.filetype != MH_EXECUTE) {
+ print_error("executable file is not a valid Mach-O file\n");
+ goto err;
+ }
+
+ // process core file segments
+ if (read_core_segments(ph) != true) {
+ print_error("failed to read core segments\n");
+ goto err;
+ }
+
+ // allocate and sort maps into map_array, we need to do this
+ // here because read_shared_lib_info needs to read from debuggee
+ // address space
+ if (sort_map_array(ph) != true) {
+ print_error("failed to sort segment map array\n");
+ goto err;
+ }
+
+ if (read_shared_lib_info(ph) != true) {
+ print_error("failed to read libraries\n");
+ goto err;
+ }
+
+ // sort again because we have added more mappings from shared objects
+ if (sort_map_array(ph) != true) {
+ print_error("failed to sort segment map array\n");
+ goto err;
+ }
+
+ if (init_classsharing_workaround(ph) != true) {
+ print_error("failed to workaround classshareing\n");
+ goto err;
+ }
+
+ print_debug("Leave Pgrab_core\n");
+ return ph;
+
+err:
+ Prelease(ph);
+ return NULL;
+}
+
+#else // __APPLE__ (none macosx)
+
+// read regs and create thread from core file
static bool core_handle_prstatus(struct ps_prochandle* ph, const char* buf, size_t nbytes) {
// we have to read prstatus_t from buf
// assert(nbytes == sizeof(prstaus_t), "size mismatch on prstatus_t");
prstatus_t* prstat = (prstatus_t*) buf;
- thread_info* newthr;
+ sa_thread_info* newthr;
print_debug("got integer regset for lwp %d\n", prstat->pr_pid);
// we set pthread_t to -1 for core dump
if((newthr = add_thread_info(ph, (pthread_t) -1, prstat->pr_pid)) == NULL)
@@ -632,8 +1093,9 @@ static bool core_handle_note(struct ps_prochandle* ph, ELF_PHDR* note_phdr) {
notep->n_type, notep->n_descsz);
if (notep->n_type == NT_PRSTATUS) {
- if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true)
+ if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true) {
return false;
+ }
}
p = descdata + ROUNDUP(notep->n_descsz, 4);
}
@@ -681,7 +1143,9 @@ static bool read_core_segments(struct ps_prochandle* ph, ELF_EHDR* core_ehdr) {
for (core_php = phbuf, i = 0; i < core_ehdr->e_phnum; i++) {
switch (core_php->p_type) {
case PT_NOTE:
- if (core_handle_note(ph, core_php) != true) goto err;
+ if (core_handle_note(ph, core_php) != true) {
+ goto err;
+ }
break;
case PT_LOAD: {
@@ -800,7 +1264,6 @@ err:
return false;
}
-
#define FIRST_LINK_MAP_OFFSET offsetof(struct r_debug, r_map)
#define LD_BASE_OFFSET offsetof(struct r_debug, r_ldbase)
#define LINK_MAP_ADDR_OFFSET offsetof(struct link_map, l_addr)
@@ -810,213 +1273,218 @@ err:
// read shared library info from runtime linker's data structures.
// This work is done by librtlb_db in Solaris
static bool read_shared_lib_info(struct ps_prochandle* ph) {
- uintptr_t addr = ph->core->dynamic_addr;
- uintptr_t debug_base;
- uintptr_t first_link_map_addr;
- uintptr_t ld_base_addr;
- uintptr_t link_map_addr;
- uintptr_t lib_base_diff;
- uintptr_t lib_base;
- uintptr_t lib_name_addr;
- char lib_name[BUF_SIZE];
- ELF_DYN dyn;
- ELF_EHDR elf_ehdr;
- int lib_fd;
-
- // _DYNAMIC has information of the form
- // [tag] [data] [tag] [data] .....
- // Both tag and data are pointer sized.
- // We look for dynamic info with DT_DEBUG. This has shared object info.
- // refer to struct r_debug in link.h
-
- dyn.d_tag = DT_NULL;
- while (dyn.d_tag != DT_DEBUG) {
- if (ps_pread(ph, (psaddr_t) addr, &dyn, sizeof(ELF_DYN)) != PS_OK) {
- print_debug("can't read debug info from _DYNAMIC\n");
- return false;
- }
- addr += sizeof(ELF_DYN);
- }
-
- // we have got Dyn entry with DT_DEBUG
- debug_base = dyn.d_un.d_ptr;
- // at debug_base we have struct r_debug. This has first link map in r_map field
- if (ps_pread(ph, (psaddr_t) debug_base + FIRST_LINK_MAP_OFFSET,
- &first_link_map_addr, sizeof(uintptr_t)) != PS_OK) {
- print_debug("can't read first link map address\n");
+ uintptr_t addr = ph->core->dynamic_addr;
+ uintptr_t debug_base;
+ uintptr_t first_link_map_addr;
+ uintptr_t ld_base_addr;
+ uintptr_t link_map_addr;
+ uintptr_t lib_base_diff;
+ uintptr_t lib_base;
+ uintptr_t lib_name_addr;
+ char lib_name[BUF_SIZE];
+ ELF_DYN dyn;
+ ELF_EHDR elf_ehdr;
+ int lib_fd;
+
+ // _DYNAMIC has information of the form
+ // [tag] [data] [tag] [data] .....
+ // Both tag and data are pointer sized.
+ // We look for dynamic info with DT_DEBUG. This has shared object info.
+ // refer to struct r_debug in link.h
+
+ dyn.d_tag = DT_NULL;
+ while (dyn.d_tag != DT_DEBUG) {
+ if (ps_pread(ph, (psaddr_t) addr, &dyn, sizeof(ELF_DYN)) != PS_OK) {
+ print_debug("can't read debug info from _DYNAMIC\n");
return false;
- }
+ }
+ addr += sizeof(ELF_DYN);
+ }
- // read ld_base address from struct r_debug
- // XXX: There is no r_ldbase member on BSD
-/*
- if (ps_pread(ph, (psaddr_t) debug_base + LD_BASE_OFFSET, &ld_base_addr,
- sizeof(uintptr_t)) != PS_OK) {
- print_debug("can't read ld base address\n");
- return false;
- }
- ph->core->ld_base_addr = ld_base_addr;
-*/
- ph->core->ld_base_addr = 0;
+ // we have got Dyn entry with DT_DEBUG
+ debug_base = dyn.d_un.d_ptr;
+ // at debug_base we have struct r_debug. This has first link map in r_map field
+ if (ps_pread(ph, (psaddr_t) debug_base + FIRST_LINK_MAP_OFFSET,
+ &first_link_map_addr, sizeof(uintptr_t)) != PS_OK) {
+ print_debug("can't read first link map address\n");
+ return false;
+ }
- print_debug("interpreter base address is 0x%lx\n", ld_base_addr);
+ // read ld_base address from struct r_debug
+ // XXX: There is no r_ldbase member on BSD
+ /*
+ if (ps_pread(ph, (psaddr_t) debug_base + LD_BASE_OFFSET, &ld_base_addr,
+ sizeof(uintptr_t)) != PS_OK) {
+ print_debug("can't read ld base address\n");
+ return false;
+ }
+ ph->core->ld_base_addr = ld_base_addr;
+ */
+ ph->core->ld_base_addr = 0;
- // now read segments from interp (i.e ld-elf.so.1)
- if (read_interp_segments(ph) != true)
- return false;
+ print_debug("interpreter base address is 0x%lx\n", ld_base_addr);
- // after adding interpreter (ld.so) mappings sort again
- if (sort_map_array(ph) != true)
- return false;
+ // now read segments from interp (i.e ld-elf.so.1)
+ if (read_interp_segments(ph) != true)
+ return false;
- print_debug("first link map is at 0x%lx\n", first_link_map_addr);
+ // after adding interpreter (ld.so) mappings sort again
+ if (sort_map_array(ph) != true)
+ return false;
- link_map_addr = first_link_map_addr;
- while (link_map_addr != 0) {
- // read library base address of the .so. Note that even though <sys/link.h> calls
- // link_map->l_addr as "base address", this is * not * really base virtual
- // address of the shared object. This is actually the difference b/w the virtual
- // address mentioned in shared object and the actual virtual base where runtime
- // linker loaded it. We use "base diff" in read_lib_segments call below.
+ print_debug("first link map is at 0x%lx\n", first_link_map_addr);
- if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_ADDR_OFFSET,
- &lib_base_diff, sizeof(uintptr_t)) != PS_OK) {
- print_debug("can't read shared object base address diff\n");
- return false;
- }
+ link_map_addr = first_link_map_addr;
+ while (link_map_addr != 0) {
+ // read library base address of the .so. Note that even though <sys/link.h> calls
+ // link_map->l_addr as "base address", this is * not * really base virtual
+ // address of the shared object. This is actually the difference b/w the virtual
+ // address mentioned in shared object and the actual virtual base where runtime
+ // linker loaded it. We use "base diff" in read_lib_segments call below.
- // read address of the name
- if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NAME_OFFSET,
- &lib_name_addr, sizeof(uintptr_t)) != PS_OK) {
- print_debug("can't read address of shared object name\n");
- return false;
- }
+ if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_ADDR_OFFSET,
+ &lib_base_diff, sizeof(uintptr_t)) != PS_OK) {
+ print_debug("can't read shared object base address diff\n");
+ return false;
+ }
- // read name of the shared object
- if (read_string(ph, (uintptr_t) lib_name_addr, lib_name, sizeof(lib_name)) != true) {
- print_debug("can't read shared object name\n");
- return false;
- }
+ // read address of the name
+ if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NAME_OFFSET,
+ &lib_name_addr, sizeof(uintptr_t)) != PS_OK) {
+ print_debug("can't read address of shared object name\n");
+ return false;
+ }
- if (lib_name[0] != '\0') {
- // ignore empty lib names
- lib_fd = pathmap_open(lib_name);
-
- if (lib_fd < 0) {
- print_debug("can't open shared object %s\n", lib_name);
- // continue with other libraries...
- } else {
- if (read_elf_header(lib_fd, &elf_ehdr)) {
- lib_base = lib_base_diff + find_base_address(lib_fd, &elf_ehdr);
- print_debug("reading library %s @ 0x%lx [ 0x%lx ]\n",
- lib_name, lib_base, lib_base_diff);
- // while adding library mappings we need to use "base difference".
- if (! read_lib_segments(ph, lib_fd, &elf_ehdr, lib_base_diff)) {
- print_debug("can't read shared object's segments\n");
- close(lib_fd);
- return false;
- }
- add_lib_info_fd(ph, lib_name, lib_fd, lib_base);
- // Map info is added for the library (lib_name) so
- // we need to re-sort it before calling the p_pdread.
- if (sort_map_array(ph) != true)
- return false;
- } else {
- print_debug("can't read ELF header for shared object %s\n", lib_name);
- close(lib_fd);
- // continue with other libraries...
- }
- }
+ // read name of the shared object
+ if (read_string(ph, (uintptr_t) lib_name_addr, lib_name, sizeof(lib_name)) != true) {
+ print_debug("can't read shared object name\n");
+ return false;
+ }
+
+ if (lib_name[0] != '\0') {
+ // ignore empty lib names
+ lib_fd = pathmap_open(lib_name);
+
+ if (lib_fd < 0) {
+ print_debug("can't open shared object %s\n", lib_name);
+ // continue with other libraries...
+ } else {
+ if (read_elf_header(lib_fd, &elf_ehdr)) {
+ lib_base = lib_base_diff + find_base_address(lib_fd, &elf_ehdr);
+ print_debug("reading library %s @ 0x%lx [ 0x%lx ]\n",
+ lib_name, lib_base, lib_base_diff);
+ // while adding library mappings we need to use "base difference".
+ if (! read_lib_segments(ph, lib_fd, &elf_ehdr, lib_base_diff)) {
+ print_debug("can't read shared object's segments\n");
+ close(lib_fd);
+ return false;
+ }
+ add_lib_info_fd(ph, lib_name, lib_fd, lib_base);
+ // Map info is added for the library (lib_name) so
+ // we need to re-sort it before calling the p_pdread.
+ if (sort_map_array(ph) != true)
+ return false;
+ } else {
+ print_debug("can't read ELF header for shared object %s\n", lib_name);
+ close(lib_fd);
+ // continue with other libraries...
+ }
}
+ }
- // read next link_map address
- if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NEXT_OFFSET,
- &link_map_addr, sizeof(uintptr_t)) != PS_OK) {
- print_debug("can't read next link in link_map\n");
- return false;
- }
- }
+ // read next link_map address
+ if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NEXT_OFFSET,
+ &link_map_addr, sizeof(uintptr_t)) != PS_OK) {
+ print_debug("can't read next link in link_map\n");
+ return false;
+ }
+ }
- return true;
+ return true;
}
// the one and only one exposed stuff from this file
struct ps_prochandle* Pgrab_core(const char* exec_file, const char* core_file) {
- ELF_EHDR core_ehdr;
- ELF_EHDR exec_ehdr;
+ ELF_EHDR core_ehdr;
+ ELF_EHDR exec_ehdr;
- struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle));
- if (ph == NULL) {
- print_debug("can't allocate ps_prochandle\n");
- return NULL;
- }
+ struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle));
+ if (ph == NULL) {
+ print_debug("cant allocate ps_prochandle\n");
+ return NULL;
+ }
- if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) {
- free(ph);
- print_debug("can't allocate ps_prochandle\n");
- return NULL;
- }
+ if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) {
+ free(ph);
+ print_debug("can't allocate ps_prochandle\n");
+ return NULL;
+ }
- // initialize ph
- ph->ops = &core_ops;
- ph->core->core_fd = -1;
- ph->core->exec_fd = -1;
- ph->core->interp_fd = -1;
+ // initialize ph
+ ph->ops = &core_ops;
+ ph->core->core_fd = -1;
+ ph->core->exec_fd = -1;
+ ph->core->interp_fd = -1;
- // open the core file
- if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) {
- print_debug("can't open core file\n");
- goto err;
- }
+ print_debug("exec: %s core: %s", exec_file, core_file);
- // read core file ELF header
- if (read_elf_header(ph->core->core_fd, &core_ehdr) != true || core_ehdr.e_type != ET_CORE) {
- print_debug("core file is not a valid ELF ET_CORE file\n");
- goto err;
- }
+ // open the core file
+ if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) {
+ print_debug("can't open core file\n");
+ goto err;
+ }
- if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) {
- print_debug("can't open executable file\n");
- goto err;
- }
+ // read core file ELF header
+ if (read_elf_header(ph->core->core_fd, &core_ehdr) != true || core_ehdr.e_type != ET_CORE) {
+ print_debug("core file is not a valid ELF ET_CORE file\n");
+ goto err;
+ }
- if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true || exec_ehdr.e_type != ET_EXEC) {
- print_debug("executable file is not a valid ELF ET_EXEC file\n");
- goto err;
- }
+ if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) {
+ print_debug("can't open executable file\n");
+ goto err;
+ }
- // process core file segments
- if (read_core_segments(ph, &core_ehdr) != true)
- goto err;
+ if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true || exec_ehdr.e_type != ET_EXEC) {
+ print_debug("executable file is not a valid ELF ET_EXEC file\n");
+ goto err;
+ }
- // process exec file segments
- if (read_exec_segments(ph, &exec_ehdr) != true)
- goto err;
+ // process core file segments
+ if (read_core_segments(ph, &core_ehdr) != true)
+ goto err;
- // exec file is also treated like a shared object for symbol search
- if (add_lib_info_fd(ph, exec_file, ph->core->exec_fd,
- (uintptr_t)0 + find_base_address(ph->core->exec_fd, &exec_ehdr)) == NULL)
- goto err;
+ // process exec file segments
+ if (read_exec_segments(ph, &exec_ehdr) != true)
+ goto err;
- // allocate and sort maps into map_array, we need to do this
- // here because read_shared_lib_info needs to read from debuggee
- // address space
- if (sort_map_array(ph) != true)
- goto err;
+ // exec file is also treated like a shared object for symbol search
+ if (add_lib_info_fd(ph, exec_file, ph->core->exec_fd,
+ (uintptr_t)0 + find_base_address(ph->core->exec_fd, &exec_ehdr)) == NULL)
+ goto err;
- if (read_shared_lib_info(ph) != true)
- goto err;
+ // allocate and sort maps into map_array, we need to do this
+ // here because read_shared_lib_info needs to read from debuggee
+ // address space
+ if (sort_map_array(ph) != true)
+ goto err;
- // sort again because we have added more mappings from shared objects
- if (sort_map_array(ph) != true)
- goto err;
+ if (read_shared_lib_info(ph) != true)
+ goto err;
- if (init_classsharing_workaround(ph) != true)
- goto err;
+ // sort again because we have added more mappings from shared objects
+ if (sort_map_array(ph) != true)
+ goto err;
+
+ if (init_classsharing_workaround(ph) != true)
+ goto err;
- return ph;
+ print_debug("Leave Pgrab_core\n");
+ return ph;
err:
- Prelease(ph);
- return NULL;
+ Prelease(ph);
+ return NULL;
}
+
+#endif // __APPLE__
diff --git a/agent/src/os/bsd/symtab.c b/agent/src/os/bsd/symtab.c
index 9a9fbd234..0299cb2b7 100644
--- a/agent/src/os/bsd/symtab.c
+++ b/agent/src/os/bsd/symtab.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,32 +28,182 @@
#include <string.h>
#include <db.h>
#include <fcntl.h>
+
+#include "libproc_impl.h"
#include "symtab.h"
+#ifndef __APPLE__
#include "salibelf.h"
+#endif // __APPLE__
// ----------------------------------------------------
// functions for symbol lookups
// ----------------------------------------------------
-struct elf_section {
- ELF_SHDR *c_shdr;
- void *c_data;
-};
-
-struct elf_symbol {
- char *name;
- uintptr_t offset;
- uintptr_t size;
-};
+typedef struct symtab_symbol {
+ char *name; // name like __ZThread_...
+ uintptr_t offset; // to loaded address
+ uintptr_t size; // size strlen
+} symtab_symbol;
typedef struct symtab {
- char *strs;
+ char *strs; // all symbols "__symbol1__'\0'__symbol2__...."
size_t num_symbols;
- struct elf_symbol *symbols;
DB* hash_table;
+ symtab_symbol* symbols;
} symtab_t;
+#ifdef __APPLE__
+
+void build_search_table(symtab_t *symtab) {
+ int i;
+ for (i = 0; i < symtab->num_symbols; i++) {
+ DBT key, value;
+ key.data = symtab->symbols[i].name;
+ key.size = strlen(key.data) + 1;
+ value.data = &(symtab->symbols[i]);
+ value.size = sizeof(symtab_symbol);
+ (*symtab->hash_table->put)(symtab->hash_table, &key, &value, 0);
+
+ // check result
+ if (is_debug()) {
+ DBT rkey, rvalue;
+ char* tmp = (char *)malloc(strlen(symtab->symbols[i].name) + 1);
+ strcpy(tmp, symtab->symbols[i].name);
+ rkey.data = tmp;
+ rkey.size = strlen(tmp) + 1;
+ (*symtab->hash_table->get)(symtab->hash_table, &rkey, &rvalue, 0);
+ // we may get a copy back so compare contents
+ symtab_symbol *res = (symtab_symbol *)rvalue.data;
+ if (strcmp(res->name, symtab->symbols[i].name) ||
+ res->offset != symtab->symbols[i].offset ||
+ res->size != symtab->symbols[i].size) {
+ print_debug("error to get hash_table value!\n");
+ }
+ free(tmp);
+ }
+ }
+}
+
+// read symbol table from given fd.
+struct symtab* build_symtab(int fd) {
+ symtab_t* symtab = NULL;
+ int i;
+ mach_header_64 header;
+ off_t image_start;
+
+ if (!get_arch_off(fd, CPU_TYPE_X86_64, &image_start)) {
+ print_debug("failed in get fat header\n");
+ return NULL;
+ }
+ lseek(fd, image_start, SEEK_SET);
+ if (read(fd, (void *)&header, sizeof(mach_header_64)) != sizeof(mach_header_64)) {
+ print_debug("reading header failed!\n");
+ return NULL;
+ }
+ // header
+ if (header.magic != MH_MAGIC_64) {
+ print_debug("not a valid .dylib file\n");
+ return NULL;
+ }
+
+ load_command lcmd;
+ symtab_command symtabcmd;
+ nlist_64 lentry;
+
+ bool lcsymtab_exist = false;
+
+ long filepos = ltell(fd);
+ for (i = 0; i < header.ncmds; i++) {
+ lseek(fd, filepos, SEEK_SET);
+ if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) {
+ print_debug("read load_command failed for file\n");
+ return NULL;
+ }
+ filepos += lcmd.cmdsize; // next command position
+ if (lcmd.cmd == LC_SYMTAB) {
+ lseek(fd, -sizeof(load_command), SEEK_CUR);
+ lcsymtab_exist = true;
+ break;
+ }
+ }
+ if (!lcsymtab_exist) {
+ print_debug("No symtab command found!\n");
+ return NULL;
+ }
+ if (read(fd, (void *)&symtabcmd, sizeof(symtab_command)) != sizeof(symtab_command)) {
+ print_debug("read symtab_command failed for file");
+ return NULL;
+ }
+ symtab = (symtab_t *)malloc(sizeof(symtab_t));
+ if (symtab == NULL) {
+ print_debug("out of memory: allocating symtab\n");
+ return NULL;
+ }
+
+ // create hash table, we use berkeley db to
+ // manipulate the hash table.
+ symtab->hash_table = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL);
+ if (symtab->hash_table == NULL)
+ goto quit;
+
+ symtab->num_symbols = symtabcmd.nsyms;
+ symtab->symbols = (symtab_symbol *)malloc(sizeof(symtab_symbol) * symtab->num_symbols);
+ symtab->strs = (char *)malloc(sizeof(char) * symtabcmd.strsize);
+ if (symtab->symbols == NULL || symtab->strs == NULL) {
+ print_debug("out of memory: allocating symtab.symbol or symtab.strs\n");
+ goto quit;
+ }
+ lseek(fd, image_start + symtabcmd.symoff, SEEK_SET);
+ for (i = 0; i < symtab->num_symbols; i++) {
+ if (read(fd, (void *)&lentry, sizeof(nlist_64)) != sizeof(nlist_64)) {
+ print_debug("read nlist_64 failed at %i\n", i);
+ goto quit;
+ }
+ symtab->symbols[i].offset = lentry.n_value;
+ symtab->symbols[i].size = lentry.n_un.n_strx; // index
+ }
+
+ // string table
+ lseek(fd, image_start + symtabcmd.stroff, SEEK_SET);
+ int size = read(fd, (void *)(symtab->strs), symtabcmd.strsize * sizeof(char));
+ if (size != symtabcmd.strsize * sizeof(char)) {
+ print_debug("reading string table failed\n");
+ goto quit;
+ }
+
+ for (i = 0; i < symtab->num_symbols; i++) {
+ symtab->symbols[i].name = symtab->strs + symtab->symbols[i].size;
+ if (i > 0) {
+ // fix size
+ symtab->symbols[i - 1].size = symtab->symbols[i].size - symtab->symbols[i - 1].size;
+ print_debug("%s size = %d\n", symtab->symbols[i - 1].name, symtab->symbols[i - 1].size);
+
+ }
+
+ if (i == symtab->num_symbols - 1) {
+ // last index
+ symtab->symbols[i].size =
+ symtabcmd.strsize - symtab->symbols[i].size;
+ print_debug("%s size = %d\n", symtab->symbols[i].name, symtab->symbols[i].size);
+ }
+ }
+
+ // build a hashtable for fast query
+ build_search_table(symtab);
+ return symtab;
+quit:
+ if (symtab) destroy_symtab(symtab);
+ return NULL;
+}
+
+#else // __APPLE__
+
+struct elf_section {
+ ELF_SHDR *c_shdr;
+ void *c_data;
+};
+
// read symbol table from given fd.
struct symtab* build_symtab(int fd) {
ELF_EHDR ehdr;
@@ -176,7 +326,7 @@ struct symtab* build_symtab(int fd) {
key.data = sym_name;
key.size = strlen(sym_name) + 1;
value.data = &(symtab->symbols[j]);
- value.size = sizeof(void *);
+ value.size = sizeof(symtab_symbol);
(*symtab->hash_table->put)(symtab->hash_table, &key, &value, 0);
}
}
@@ -201,30 +351,29 @@ quit:
return symtab;
}
-void destroy_symtab(struct symtab* symtab) {
+#endif // __APPLE__
+
+void destroy_symtab(symtab_t* symtab) {
if (!symtab) return;
- if (symtab->strs) free(symtab->strs);
- if (symtab->symbols) free(symtab->symbols);
- if (symtab->hash_table) {
- (*symtab->hash_table->close)(symtab->hash_table);
- }
+ free(symtab->strs);
+ free(symtab->symbols);
free(symtab);
}
-uintptr_t search_symbol(struct symtab* symtab, uintptr_t base,
- const char *sym_name, int *sym_size) {
+uintptr_t search_symbol(struct symtab* symtab, uintptr_t base, const char *sym_name, int *sym_size) {
DBT key, value;
int ret;
// library does not have symbol table
- if (!symtab || !symtab->hash_table)
+ if (!symtab || !symtab->hash_table) {
return 0;
+ }
key.data = (char*)(uintptr_t)sym_name;
key.size = strlen(sym_name) + 1;
ret = (*symtab->hash_table->get)(symtab->hash_table, &key, &value, 0);
if (ret == 0) {
- struct elf_symbol *sym = value.data;
+ symtab_symbol *sym = value.data;
uintptr_t rslt = (uintptr_t) ((char*)base + sym->offset);
if (sym_size) *sym_size = sym->size;
return rslt;
@@ -238,7 +387,7 @@ const char* nearest_symbol(struct symtab* symtab, uintptr_t offset,
int n = 0;
if (!symtab) return NULL;
for (; n < symtab->num_symbols; n++) {
- struct elf_symbol* sym = &(symtab->symbols[n]);
+ symtab_symbol* sym = &(symtab->symbols[n]);
if (sym->name != NULL &&
offset >= sym->offset && offset < sym->offset + sym->size) {
if (poffset) *poffset = (offset - sym->offset);
diff --git a/agent/src/os/bsd/symtab.h b/agent/src/os/bsd/symtab.h
index 9b7eef77d..f5f8645da 100644
--- a/agent/src/os/bsd/symtab.h
+++ b/agent/src/os/bsd/symtab.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,11 +27,11 @@
#include <stdint.h>
-// interface to manage ELF symbol tables
+// interface to manage ELF or MachO symbol tables
struct symtab;
-// build symbol table for a given ELF file descriptor
+// build symbol table for a given ELF or MachO file escriptor
struct symtab* build_symtab(int fd);
// destroy the symbol table
diff --git a/agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java b/agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java
index ed688758d..6d422f62a 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,11 +34,18 @@ public class BsdVtblAccess extends BasicVtblAccess {
public BsdVtblAccess(SymbolLookup symbolLookup,
String[] dllNames) {
super(symbolLookup, dllNames);
-
- if (symbolLookup.lookup("libjvm.so", "__vt_10JavaThread") != null ||
- symbolLookup.lookup("libjvm_g.so", "__vt_10JavaThread") != null) {
+ boolean oldVT = false;
+ boolean isDarwin = dllNames[0].lastIndexOf(".dylib") != -1;
+ String vtJavaThread = isDarwin ? "_vt_10JavaThread" : "__vt_10JavaThread";
+ for (String dllName : dllNames) {
+ if (symbolLookup.lookup(dllName, vtJavaThread) != null) {
+ oldVT = true;
+ break;
+ }
+ }
+ if (oldVT) {
// old C++ ABI
- vt = "__vt_";
+ vt = isDarwin ? "_vt_" : "__vt_";
} else {
// new C++ ABI
vt = "_ZTV";
diff --git a/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java b/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java
index 23058f428..223384426 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java
@@ -24,36 +24,81 @@
package sun.jvm.hotspot;
-import java.io.*;
-import java.math.*;
-import java.util.*;
-import java.util.regex.*;
-
-import sun.jvm.hotspot.types.Type;
-import sun.jvm.hotspot.types.Field;
-import sun.jvm.hotspot.HotSpotTypeDataBase;
-import sun.jvm.hotspot.types.basic.BasicType;
-import sun.jvm.hotspot.types.basic.BasicTypeDataBase;
-import sun.jvm.hotspot.types.CIntegerType;
-import sun.jvm.hotspot.code.*;
-import sun.jvm.hotspot.compiler.*;
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.interpreter.*;
-import sun.jvm.hotspot.memory.*;
-import sun.jvm.hotspot.oops.*;
-import sun.jvm.hotspot.opto.*;
-import sun.jvm.hotspot.ci.*;
-import sun.jvm.hotspot.asm.*;
-import sun.jvm.hotspot.runtime.*;
-import sun.jvm.hotspot.utilities.*;
-import sun.jvm.hotspot.utilities.soql.*;
-import sun.jvm.hotspot.ui.classbrowser.*;
-import sun.jvm.hotspot.ui.tree.*;
-import sun.jvm.hotspot.tools.*;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Stack;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import sun.jvm.hotspot.ci.ciEnv;
+import sun.jvm.hotspot.code.CodeBlob;
+import sun.jvm.hotspot.code.CodeCacheVisitor;
+import sun.jvm.hotspot.code.NMethod;
+import sun.jvm.hotspot.debugger.Address;
+import sun.jvm.hotspot.debugger.OopHandle;
+import sun.jvm.hotspot.memory.SymbolTable;
+import sun.jvm.hotspot.memory.SystemDictionary;
+import sun.jvm.hotspot.memory.Universe;
+import sun.jvm.hotspot.oops.DefaultHeapVisitor;
+import sun.jvm.hotspot.oops.HeapVisitor;
+import sun.jvm.hotspot.oops.InstanceKlass;
+import sun.jvm.hotspot.oops.Klass;
+import sun.jvm.hotspot.oops.Metadata;
+import sun.jvm.hotspot.oops.Method;
+import sun.jvm.hotspot.oops.MethodData;
+import sun.jvm.hotspot.oops.Oop;
+import sun.jvm.hotspot.oops.RawHeapVisitor;
+import sun.jvm.hotspot.oops.Symbol;
+import sun.jvm.hotspot.oops.UnknownOopException;
+import sun.jvm.hotspot.opto.Compile;
+import sun.jvm.hotspot.opto.InlineTree;
+import sun.jvm.hotspot.runtime.CompiledVFrame;
+import sun.jvm.hotspot.runtime.CompilerThread;
+import sun.jvm.hotspot.runtime.JavaThread;
+import sun.jvm.hotspot.runtime.JavaVFrame;
+import sun.jvm.hotspot.runtime.Threads;
+import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.tools.ObjectHistogram;
+import sun.jvm.hotspot.tools.PMap;
+import sun.jvm.hotspot.tools.PStack;
import sun.jvm.hotspot.tools.StackTrace;
import sun.jvm.hotspot.tools.jcore.ClassDump;
import sun.jvm.hotspot.tools.jcore.ClassFilter;
+import sun.jvm.hotspot.types.CIntegerType;
+import sun.jvm.hotspot.types.Field;
+import sun.jvm.hotspot.types.Type;
+import sun.jvm.hotspot.types.basic.BasicType;
+import sun.jvm.hotspot.ui.classbrowser.HTMLGenerator;
+import sun.jvm.hotspot.ui.tree.CTypeTreeNodeAdapter;
+import sun.jvm.hotspot.ui.tree.OopTreeNodeAdapter;
+import sun.jvm.hotspot.ui.tree.SimpleTreeNode;
+import sun.jvm.hotspot.utilities.AddressOps;
+import sun.jvm.hotspot.utilities.Assert;
+import sun.jvm.hotspot.utilities.HeapProgressThunk;
+import sun.jvm.hotspot.utilities.LivenessPathElement;
+import sun.jvm.hotspot.utilities.MethodArray;
+import sun.jvm.hotspot.utilities.ObjectReader;
+import sun.jvm.hotspot.utilities.PointerFinder;
+import sun.jvm.hotspot.utilities.PointerLocation;
+import sun.jvm.hotspot.utilities.ReversePtrs;
+import sun.jvm.hotspot.utilities.ReversePtrsAnalysis;
+import sun.jvm.hotspot.utilities.RobustOopDeterminator;
+import sun.jvm.hotspot.utilities.SystemDictionaryHelper;
+import sun.jvm.hotspot.utilities.soql.JSJavaFactory;
+import sun.jvm.hotspot.utilities.soql.JSJavaFactoryImpl;
+import sun.jvm.hotspot.utilities.soql.JSJavaScriptEngine;
public class CommandProcessor {
public abstract static class DebuggerInterface {
@@ -1132,6 +1177,10 @@ public class CommandProcessor {
Klass klass = null;
if (t.countTokens() == 1) {
klass = SystemDictionaryHelper.findInstanceKlass(t.nextToken());
+ if (klass == null) {
+ out.println("No such type.");
+ return;
+ }
}
while (base != null && base.lessThan(end)) {
long step = stride;
@@ -1517,7 +1566,7 @@ public class CommandProcessor {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
thread.printThreadIDOn(new PrintStream(bos));
if (all || bos.toString().equals(name)) {
- out.println(bos.toString() + " = " + thread.getAddress());
+ out.println("Thread " + bos.toString() + " Address: " + thread.getAddress());
HTMLGenerator gen = new HTMLGenerator(false);
try {
out.println(gen.genHTMLForJavaStackTrace(thread));
@@ -1546,7 +1595,7 @@ public class CommandProcessor {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
thread.printThreadIDOn(new PrintStream(bos));
if (all || bos.toString().equals(name)) {
- out.println(bos.toString() + " = " + thread.getAddress());
+ out.println("Thread " + bos.toString() + " Address " + thread.getAddress());
if (!all) return;
}
}
diff --git a/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java b/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java
index bb718d9f7..8abd084c8 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -311,6 +311,8 @@ public class HotSpotAgent {
setupDebuggerLinux();
} else if (os.equals("bsd")) {
setupDebuggerBsd();
+ } else if (os.equals("darwin")) {
+ setupDebuggerDarwin();
} else {
// Add support for more operating systems here
throw new DebuggerException("Operating system " + os + " not yet supported");
@@ -370,6 +372,10 @@ public class HotSpotAgent {
db = new HotSpotTypeDataBase(machDesc,
new BsdVtblAccess(debugger, jvmLibNames),
debugger, jvmLibNames);
+ } else if (os.equals("darwin")) {
+ db = new HotSpotTypeDataBase(machDesc,
+ new BsdVtblAccess(debugger, jvmLibNames),
+ debugger, jvmLibNames);
} else {
throw new DebuggerException("OS \"" + os + "\" not yet supported (no VtblAccess yet)");
}
@@ -459,6 +465,8 @@ public class HotSpotAgent {
setupJVMLibNamesLinux();
} else if (os.equals("bsd")) {
setupJVMLibNamesBsd();
+ } else if (os.equals("darwin")) {
+ setupJVMLibNamesDarwin();
} else {
throw new RuntimeException("Unknown OS type");
}
@@ -567,6 +575,29 @@ public class HotSpotAgent {
jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" };
}
+ //
+ // Darwin
+ //
+
+ private void setupDebuggerDarwin() {
+ setupJVMLibNamesDarwin();
+
+ if (cpu.equals("amd64") || cpu.equals("x86_64")) {
+ machDesc = new MachineDescriptionAMD64();
+ } else {
+ throw new DebuggerException("Darwin only supported on x86_64. Current arch: " + cpu);
+ }
+
+ BsdDebuggerLocal dbg = new BsdDebuggerLocal(machDesc, !isServer);
+ debugger = dbg;
+
+ attachDebugger();
+ }
+
+ private void setupJVMLibNamesDarwin() {
+ jvmLibNames = new String[] { "libjvm.dylib", "libjvm_g.dylib" };
+ }
+
/** Convenience routine which should be called by per-platform
debugger setup. Should not be called when startupMode is
REMOTE_MODE. */
diff --git a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java
index c6fbb7dab..9a26584e3 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,9 @@ import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.x86.*;
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.utilities.*;
+import sun.jvm.hotspot.runtime.VM;
+import sun.jvm.hotspot.runtime.Threads;
+import sun.jvm.hotspot.runtime.JavaThread;
import java.lang.reflect.*;
/** <P> An implementation of the JVMDebugger interface. The basic debug
@@ -51,10 +54,11 @@ import java.lang.reflect.*;
public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
private boolean useGCC32ABI;
private boolean attached;
- private long p_ps_prochandle; // native debugger handle
- private long symbolicator; // macosx symbolicator handle
- private long task; // macosx task handle
+ private long p_ps_prochandle; // native debugger handle
+ private long symbolicator; // macosx symbolicator handle
+ private long task; // macosx task handle
private boolean isCore;
+ private boolean isDarwin; // variant for bsd
// CDebugger support
private BsdCDebugger cdbg;
@@ -208,6 +212,7 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
}
}
+ isDarwin = getOS().equals("darwin");
workerThread = new BsdDebuggerLocalWorkerThread(this);
workerThread.start();
}
@@ -240,8 +245,11 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
/* called from attach methods */
private void findABIVersion() throws DebuggerException {
- if (lookupByName0("libjvm.so", "__vt_10JavaThread") != 0 ||
- lookupByName0("libjvm_g.so", "__vt_10JavaThread") != 0) {
+ String libjvmName = isDarwin ? "libjvm.dylib" : "libjvm.so";
+ String libjvm_gName = isDarwin? "libjvm_g.dylib" : "libjvm_g.so";
+ String javaThreadVt = isDarwin ? "_vt_10JavaThread" : "__vt_10JavaThread";
+ if (lookupByName0(libjvmName, javaThreadVt) != 0 ||
+ lookupByName0(libjvm_gName, javaThreadVt) != 0) {
// old C++ ABI
useGCC32ABI = false;
} else {
@@ -360,7 +368,8 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
}
if (isCore) {
- long addr = lookupByName0(objectName, symbol);
+ // MacOSX symbol with "_" as leading
+ long addr = lookupByName0(objectName, isDarwin ? "_" + symbol : symbol);
return (addr == 0)? null : new BsdAddress(this, handleGCC32ABI(addr, symbol));
} else {
class LookupByNameTask implements WorkerThreadTask {
@@ -403,12 +412,12 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
public ThreadProxy getThreadForIdentifierAddress(Address threadIdAddr, Address uniqueThreadIdAddr) {
return new BsdThread(this, threadIdAddr, uniqueThreadIdAddr);
}
+
@Override
public ThreadProxy getThreadForIdentifierAddress(Address addr) {
throw new RuntimeException("unimplemented");
}
-
/** From the ThreadAccess interface via Debugger and JVMDebugger */
public ThreadProxy getThreadForThreadId(long id) {
return new BsdThread(this, id);
@@ -601,6 +610,33 @@ public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger {
throw new DebuggerException("Unimplemented");
}
+ /** this functions used for core file reading and called from native attach0,
+ it returns an array of long integers as
+ [thread_id, stack_start, stack_end, thread_id, stack_start, stack_end, ....] for
+ all java threads recorded in Threads. Also adds the ThreadProxy to threadList */
+ public long[] getJavaThreadsInfo() {
+ requireAttach();
+ Threads threads = VM.getVM().getThreads();
+ int len = threads.getNumberOfThreads();
+ long[] result = new long[len * 3]; // triple
+ JavaThread t = threads.first();
+ long beg, end;
+ int i = 0;
+ while (t != null) {
+ end = t.getStackBaseValue();
+ beg = end - t.getStackSize();
+ BsdThread bsdt = (BsdThread)t.getThreadProxy();
+ long uid = bsdt.getUniqueThreadId();
+ if (threadList != null) threadList.add(bsdt);
+ result[i] = uid;
+ result[i + 1] = beg;
+ result[i + 2] = end;
+ t = t.next();
+ i += 3;
+ }
+ return result;
+ }
+
static {
System.loadLibrary("saproc");
init0();
diff --git a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java
index f3351fb9c..0d637f30f 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -44,7 +44,8 @@ class BsdThread implements ThreadProxy {
BsdThread(BsdDebugger debugger, long id) {
this.debugger = debugger;
- this.thread_id = (int) id;
+ // use unique_thread_id to identify thread
+ this.unique_thread_id = id;
}
public boolean equals(Object obj) {
@@ -52,7 +53,7 @@ class BsdThread implements ThreadProxy {
return false;
}
- return (((BsdThread) obj).thread_id == thread_id);
+ return (((BsdThread) obj).unique_thread_id == unique_thread_id);
}
public int hashCode() {
@@ -80,4 +81,9 @@ class BsdThread implements ThreadProxy {
throws IllegalThreadStateException, DebuggerException {
throw new DebuggerException("Unimplemented");
}
+
+ /** this is not interface function, used in core file to get unique thread id on Macosx*/
+ public long getUniqueThreadId() {
+ return unique_thread_id;
+ }
}
diff --git a/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java b/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java
index ab81252d4..241e5be37 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -148,7 +148,7 @@ public class Oop {
if (doVMFields) {
visitor.doCInt(mark, true);
if (VM.getVM().isCompressedKlassPointersEnabled()) {
- throw new InternalError("unimplemented");
+ visitor.doMetadata(compressedKlass, true);
} else {
visitor.doMetadata(klass, true);
}
diff --git a/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java b/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
index 153d51bb0..926c11c4b 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -320,6 +320,10 @@ public class JavaThread extends Thread {
return stackBaseField.getValue(addr);
}
+ public long getStackBaseValue() {
+ return VM.getVM().getAddressValue(getStackBase());
+ }
+
public long getStackSize() {
return stackSizeField.getValue(addr);
}
diff --git a/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java b/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java
index 8e259e3a1..b4b5903d1 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -42,6 +42,7 @@ import sun.jvm.hotspot.utilities.*;
public class Threads {
private static JavaThreadFactory threadFactory;
private static AddressField threadListField;
+ private static CIntegerField numOfThreadsField;
private static VirtualConstructor virtualConstructor;
private static JavaThreadPDAccess access;
@@ -57,6 +58,7 @@ public class Threads {
Type type = db.lookupType("Threads");
threadListField = type.getAddressField("_thread_list");
+ numOfThreadsField = type.getCIntegerField("_number_of_threads");
// Instantiate appropriate platform-specific JavaThreadFactory
String os = VM.getVM().getOS();
@@ -102,6 +104,10 @@ public class Threads {
} else if (cpu.equals("amd64") || cpu.equals("x86_64")) {
access = new BsdAMD64JavaThreadPDAccess();
}
+ } else if (os.equals("darwin")) {
+ if (cpu.equals("amd64") || cpu.equals("x86_64")) {
+ access = new BsdAMD64JavaThreadPDAccess();
+ }
}
if (access == null) {
@@ -144,6 +150,10 @@ public class Threads {
return createJavaThreadWrapper(threadAddr);
}
+ public int getNumberOfThreads() {
+ return (int) numOfThreadsField.getValue();
+ }
+
/** Routine for instantiating appropriately-typed wrapper for a
JavaThread. Currently needs to be public for OopUtilities to
access it. */
diff --git a/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java b/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java
index 54aa0e0de..0b3720ff5 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@ import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.oops.*;
import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.utilities.PlatformInfo;
public class PStack extends Tool {
// in non-verbose mode, Method*s are not printed in java frames
@@ -54,6 +55,11 @@ public class PStack extends Tool {
}
public void run(PrintStream out, Debugger dbg) {
+ if (PlatformInfo.getOS().equals("darwin")) {
+ out.println("Not available on Darwin");
+ return;
+ }
+
CDebugger cdbg = dbg.getCDebugger();
if (cdbg != null) {
ConcurrentLocksPrinter concLocksPrinter = null;
diff --git a/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java b/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java
index f88335c1b..123258631 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java
@@ -24,10 +24,15 @@
package sun.jvm.hotspot.types.basic;
-import java.util.*;
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.types.*;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import sun.jvm.hotspot.debugger.Address;
+import sun.jvm.hotspot.debugger.MachineDescription;
import sun.jvm.hotspot.runtime.VM;
+import sun.jvm.hotspot.types.Type;
+import sun.jvm.hotspot.types.TypeDataBase;
/** <P> This is a basic implementation of the TypeDataBase interface.
It allows an external type database builder to add types to be
@@ -150,7 +155,7 @@ public class BasicTypeDataBase implements TypeDataBase {
return VM.getVM().getOopSize();
}
- static HashMap typeToVtbl = new HashMap();
+ HashMap typeToVtbl = new HashMap();
private Address vtblForType(Type type) {
Address vtblAddr = (Address)typeToVtbl.get(type);
diff --git a/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java b/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java
index 9a5dc144a..afe81ef57 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -43,8 +43,8 @@ public class PlatformInfo {
return "bsd";
} else if (os.equals("OpenBSD")) {
return "bsd";
- } else if (os.equals("Darwin") || os.contains("OS X")) {
- return "bsd";
+ } else if (os.contains("Darwin") || os.contains("OS X")) {
+ return "darwin";
} else if (os.startsWith("Windows")) {
return "win32";
} else {
diff --git a/agent/src/share/native/sadis.c b/agent/src/share/native/sadis.c
index f8bd9adbd..926b4e5fd 100644
--- a/agent/src/share/native/sadis.c
+++ b/agent/src/share/native/sadis.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -48,7 +48,10 @@
#include <string.h>
#include <dlfcn.h>
+
+#ifndef __APPLE__
#include <link.h>
+#endif
#endif
@@ -109,9 +112,7 @@ JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_asm_Disassembler_load_1library(JNIE
jstring libname_s) {
uintptr_t func = 0;
const char* error_message = NULL;
- const char* java_home;
jboolean isCopy;
- uintptr_t *handle = NULL;
const char * jrepath = (*env)->GetStringUTFChars(env, jrepath_s, &isCopy); // like $JAVA_HOME/jre/lib/sparc/
const char * libname = (*env)->GetStringUTFChars(env, libname_s, &isCopy);
@@ -167,7 +168,8 @@ typedef void* (*decode_func)(uintptr_t start_va, uintptr_t end_va,
void* event_stream,
int (*printf_callback)(void*, const char*, ...),
void* printf_stream,
- const char* options);
+ const char* options,
+ int newline);
/* container for call back state when decoding instructions */
typedef struct {
@@ -281,7 +283,7 @@ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_asm_Disassembler_decode(JNIEnv * env
end - start,
&event_to_env, (void*) &denv,
&printf_to_env, (void*) &denv,
- options);
+ options, 0 /* newline */);
/* cleanup */
(*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT);
diff --git a/make/Makefile b/make/Makefile
index c55574d82..8dad67f07 100644
--- a/make/Makefile
+++ b/make/Makefile
@@ -532,6 +532,39 @@ $(JDK_IMAGE_DIR)/jre/lib/rt.jar:
$(TAR) -cf - *) | \
($(CD) $(JDK_IMAGE_DIR) && $(TAR) -xf -)
+
+# Testing the built JVM
+RUN_JVM=JAVA_HOME=$(JDK_IMPORT_PATH) $(JDK_IMPORT_PATH)/bin/java -d$(ARCH_DATA_MODEL) -Dsun.java.launcher=gamma
+generic_test:
+ @$(ECHO) "Running with: $(ALTJVM_DIR)"
+ @$(RUN_JVM) -XXaltjvm=$(ALTJVM_DIR) -Xinternalversion
+ @$(RUN_JVM) -XXaltjvm=$(ALTJVM_DIR) -showversion -help
+
+# C2 test targets
+test_product test_optimized test_fastdebug test_jvmg:
+ @$(MAKE) generic_test ALTJVM_DIR="$(C2_DIR)/$(@:test_%=%)"
+
+# C1 test targets
+test_product1 test_optimized1 test_fastdebug1 test_jvmg1:
+ ifeq ($(ARCH_DATA_MODEL), 32)
+ @$(MAKE) generic_test ALTJVM_DIR="$(C1_DIR)/$(@:test_%1=%)"
+ else
+ @$(ECHO) "No compiler1 ($(@:test_%=%)) for ARCH_DATA_MODEL=$(ARCH_DATA_MODEL)"
+ endif
+
+# Zero test targets
+test_productzero test_optimizedzero test_fastdebugzero test_jvmgzero:
+ @$(MAKE) generic_test ALTJVM_DIR="$(ZERO_DIR)/$(@:test_%zero=%)"
+
+# Shark test targets
+test_productshark test_optimizedshark test_fastdebugshark test_jvmgshark:
+ @$(MAKE) generic_test ALTJVM_DIR="$(SHARK_DIR)/$(@:test_%shark=%)"
+
+# Minimal1 test targets
+test_productminimal1 test_optimizedminimal1 test_fastdebugminimal1 test_jvmgminimal1:
+ @$(MAKE) generic_test ALTJVM_DIR="$(MINIMAL1_DIR)/$(@:test_%minimal1=%)"
+
+
test_jdk:
ifeq ($(JVM_VARIANT_CLIENT), true)
$(JDK_IMAGE_DIR)/bin/java -d$(ARCH_DATA_MODEL) -client -Xinternalversion
diff --git a/make/bsd/Makefile b/make/bsd/Makefile
index e95bb0550..024aef9cb 100644
--- a/make/bsd/Makefile
+++ b/make/bsd/Makefile
@@ -299,63 +299,42 @@ platform_zero: $(GAMMADIR)/make/$(OSNAME)/platform_zero.in
$(TARGETS_C2): $(SUBDIRS_C2)
cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS) install
endif
$(TARGETS_TIERED): $(SUBDIRS_TIERED)
cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS) install
endif
$(TARGETS_C1): $(SUBDIRS_C1)
cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS) install
endif
$(TARGETS_CORE): $(SUBDIRS_CORE)
cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS) install
endif
$(TARGETS_ZERO): $(SUBDIRS_ZERO)
cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && $(MAKE) $(MFLAGS) install
endif
$(TARGETS_SHARK): $(SUBDIRS_SHARK)
cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && $(MAKE) $(MFLAGS) install
endif
$(TARGETS_MINIMAL1): $(SUBDIRS_MINIMAL1)
cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && $(MAKE) $(MFLAGS) install
endif
diff --git a/make/bsd/makefiles/buildtree.make b/make/bsd/makefiles/buildtree.make
index b8d92f6a4..71bb04b98 100644
--- a/make/bsd/makefiles/buildtree.make
+++ b/make/bsd/makefiles/buildtree.make
@@ -50,7 +50,6 @@
# jvmti.make - generate JVMTI bindings from the spec (JSR-163)
# sa.make - generate SA jar file and natives
# env.[ck]sh - environment settings
-# test_gamma - script to run the Queens program
#
# The makefiles are split this way so that "make foo" will run faster by not
# having to read the dependency files for the vm.
@@ -67,9 +66,6 @@ include $(GAMMADIR)/make/altsrc.make
# 'gmake MAKE_VERBOSE=y' or 'gmake QUIETLY=' gives all the gory details.
QUIETLY$(MAKE_VERBOSE) = @
-# For now, until the compiler is less wobbly:
-TESTFLAGS = -Xbatch -showversion
-
ifeq ($(findstring true, $(JVM_VARIANT_ZERO) $(JVM_VARIANT_ZEROSHARK)), true)
PLATFORM_FILE = $(shell dirname $(shell dirname $(shell pwd)))/platform_zero
else
@@ -135,7 +131,7 @@ BUILDTREE_MAKE = $(GAMMADIR)/make/$(OS_FAMILY)/makefiles/buildtree.make
# dtrace.make is used on BSD versions that implement Dtrace (like MacOS X)
BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make \
jvmti.make sa.make dtrace.make \
- env.sh env.csh jdkpath.sh .dbxrc test_gamma
+ env.sh env.csh jdkpath.sh
BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OS_FAMILY) \
SRCARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT)
@@ -352,7 +348,7 @@ env.sh: $(BUILDTREE_MAKE)
@echo Creating $@ ...
$(QUIETLY) ( \
$(BUILDTREE_COMMENT); \
- [ -n "$$JAVA_HOME" ] && { echo ": \$${JAVA_HOME:=$${JAVA_HOME}}"; }; \
+ { echo "JAVA_HOME=$(JDK_IMPORT_PATH)"; }; \
{ \
echo "CLASSPATH=$${CLASSPATH:+$$CLASSPATH:}.:\$${JAVA_HOME}/jre/lib/rt.jar:\$${JAVA_HOME}/jre/lib/i18n.jar"; \
} | sed s:$${JAVA_HOME:--------}:\$${JAVA_HOME}:g; \
@@ -364,8 +360,7 @@ env.csh: env.sh
@echo Creating $@ ...
$(QUIETLY) ( \
$(BUILDTREE_COMMENT); \
- [ -n "$$JAVA_HOME" ] && \
- { echo "if (! \$$?JAVA_HOME) setenv JAVA_HOME \"$$JAVA_HOME\""; }; \
+ { echo "setenv JAVA_HOME \"$(JDK_IMPORT_PATH)\""; }; \
sed -n 's/^\([A-Za-z_][A-Za-z0-9_]*\)=/setenv \1 /p' $?; \
) > $@
@@ -376,119 +371,6 @@ jdkpath.sh: $(BUILDTREE_MAKE)
echo "JDK=${JAVA_HOME}"; \
) > $@
-.dbxrc: $(BUILDTREE_MAKE)
- @echo Creating $@ ...
- $(QUIETLY) ( \
- echo "echo '# Loading $(PLATFORM_DIR)/$(TARGET)/.dbxrc'"; \
- echo "if [ -f \"\$${HOTSPOT_DBXWARE}\" ]"; \
- echo "then"; \
- echo " source \"\$${HOTSPOT_DBXWARE}\""; \
- echo "elif [ -f \"\$$HOME/.dbxrc\" ]"; \
- echo "then"; \
- echo " source \"\$$HOME/.dbxrc\""; \
- echo "fi"; \
- ) > $@
-
-# Skip the test for product builds (which only work when installed in a JDK), to
-# avoid exiting with an error and causing make to halt.
-NO_TEST_MSG = \
- echo "$@: skipping the test--this build must be tested in a JDK."
-
-NO_JAVA_HOME_MSG = \
- echo "JAVA_HOME must be set to run this test."
-
-DATA_MODE = $(DATA_MODE/$(BUILDARCH))
-JAVA_FLAG = $(JAVA_FLAG/$(DATA_MODE))
-
-DATA_MODE/i486 = 32
-DATA_MODE/sparc = 32
-DATA_MODE/sparcv9 = 64
-DATA_MODE/amd64 = 64
-DATA_MODE/ia64 = 64
-DATA_MODE/zero = $(ARCH_DATA_MODEL)
-
-JAVA_FLAG/32 = -d32
-JAVA_FLAG/64 = -d64
-
-WRONG_DATA_MODE_MSG = \
- echo "JAVA_HOME must point to a $(DATA_MODE)-bit OpenJDK."
-
-CROSS_COMPILING_MSG = \
- echo "Cross compiling for ARCH $(CROSS_COMPILE_ARCH), skipping gamma run."
-
-test_gamma: $(BUILDTREE_MAKE) $(GAMMADIR)/make/test/Queens.java
- @echo Creating $@ ...
- $(QUIETLY) ( \
- echo "#!/bin/sh"; \
- echo ""; \
- $(BUILDTREE_COMMENT); \
- echo ""; \
- echo "# Include environment settings for gamma run"; \
- echo ""; \
- echo ". ./env.sh"; \
- echo ""; \
- echo "# Do not run gamma test for cross compiles"; \
- echo ""; \
- echo "if [ -n \"$(CROSS_COMPILE_ARCH)\" ]; then "; \
- echo " $(CROSS_COMPILING_MSG)"; \
- echo " exit 0"; \
- echo "fi"; \
- echo ""; \
- echo "# Make sure JAVA_HOME is set as it is required for gamma"; \
- echo ""; \
- echo "if [ -z \"\$${JAVA_HOME}\" ]; then "; \
- echo " $(NO_JAVA_HOME_MSG)"; \
- echo " exit 0"; \
- echo "fi"; \
- echo ""; \
- echo "# Check JAVA_HOME version to be used for the test"; \
- echo ""; \
- echo "\$${JAVA_HOME}/bin/java $(JAVA_FLAG) -fullversion > /dev/null 2>&1"; \
- echo "if [ \$$? -ne 0 ]; then "; \
- echo " $(WRONG_DATA_MODE_MSG)"; \
- echo " exit 0"; \
- echo "fi"; \
- echo ""; \
- echo "GAMMA_PROG=gamma"; \
- echo ""; \
- echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \
- echo " # Ensure architecture for gamma and JAVA_HOME is the same."; \
- echo " # NOTE: gamma assumes the OpenJDK directory layout."; \
- echo ""; \
- echo " GAMMA_ARCH=\"\`file \$${GAMMA_PROG} | awk '{print \$$NF}'\`\""; \
- echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/libjava.$(LIBRARY_SUFFIX)\""; \
- echo " if [ ! -f \$${JVM_LIB} ]; then"; \
- echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/$${LIBARCH}/libjava.$(LIBRARY_SUFFIX)\""; \
- echo " fi"; \
- echo " if [ ! -f \$${JVM_LIB} ] || [ -z \"\`file \$${JVM_LIB} | grep \$${GAMMA_ARCH}\`\" ]; then "; \
- echo " $(WRONG_DATA_MODE_MSG)"; \
- echo " exit 0"; \
- echo " fi"; \
- echo "fi"; \
- echo ""; \
- echo "# Compile Queens program for test"; \
- echo ""; \
- echo "rm -f Queens.class"; \
- echo "\$${JAVA_HOME}/bin/javac -d . $(GAMMADIR)/make/test/Queens.java"; \
- echo ""; \
- echo "# Set library path solely for gamma launcher test run"; \
- echo ""; \
- echo "LD_LIBRARY_PATH=.:$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \
- echo "export LD_LIBRARY_PATH"; \
- echo "unset LD_LIBRARY_PATH_32"; \
- echo "unset LD_LIBRARY_PATH_64"; \
- echo ""; \
- echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \
- echo " DYLD_LIBRARY_PATH=.:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/native_threads:\$${JAVA_HOME}/jre/lib:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \
- echo " export DYLD_LIBRARY_PATH"; \
- echo "fi"; \
- echo ""; \
- echo "# Use the gamma launcher and JAVA_HOME to run the test"; \
- echo ""; \
- echo "./\$${GAMMA_PROG} $(TESTFLAGS) Queens < /dev/null"; \
- ) > $@
- $(QUIETLY) chmod +x $@
-
FORCE:
.PHONY: all FORCE
diff --git a/make/bsd/makefiles/saproc.make b/make/bsd/makefiles/saproc.make
index 4fb216b41..62e31a63d 100644
--- a/make/bsd/makefiles/saproc.make
+++ b/make/bsd/makefiles/saproc.make
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -24,7 +24,7 @@
# Rules to build serviceability agent library, used by vm.make
-# libsaproc.so: serviceability agent
+# libsaproc.so(dylib): serviceability agent
SAPROC = saproc
ifeq ($(OS_VENDOR), Darwin)
@@ -37,7 +37,7 @@ AGENT_DIR = $(GAMMADIR)/agent
SASRCDIR = $(AGENT_DIR)/src/os/$(Platform_os_family)
-NON_STUB_SASRCFILES = $(SASRCDIR)/salibelf.c \
+BSD_NON_STUB_SASRCFILES = $(SASRCDIR)/salibelf.c \
$(SASRCDIR)/symtab.c \
$(SASRCDIR)/libproc_impl.c \
$(SASRCDIR)/ps_proc.c \
@@ -45,13 +45,19 @@ NON_STUB_SASRCFILES = $(SASRCDIR)/salibelf.c \
$(SASRCDIR)/BsdDebuggerLocal.c \
$(AGENT_DIR)/src/share/native/sadis.c
+DARWIN_NON_STUB_SASRCFILES = $(SASRCDIR)/symtab.c \
+ $(SASRCDIR)/libproc_impl.c \
+ $(SASRCDIR)/ps_core.c \
+ $(SASRCDIR)/MacosxDebuggerLocal.m \
+ $(AGENT_DIR)/src/share/native/sadis.c
+
ifeq ($(OS_VENDOR), FreeBSD)
- SASRCFILES = $(NON_STUB_SASRCFILES)
+ SASRCFILES = $(BSD_NON_STUB_SASRCFILES)
SALIBS = -lutil -lthread_db
SAARCH = $(ARCHFLAG)
else
ifeq ($(OS_VENDOR), Darwin)
- SASRCFILES = $(SASRCDIR)/MacosxDebuggerLocal.m
+ SASRCFILES = $(DARWIN_NON_STUB_SASRCFILES)
SALIBS = -g -framework Foundation -F/System/Library/Frameworks/JavaVM.framework/Frameworks -framework JavaNativeFoundation -framework Security -framework CoreFoundation
#objc compiler blows up on -march=i586, perhaps it should not be included in the macosx intel 32-bit C++ compiles?
SAARCH = $(subst -march=i586,,$(ARCHFLAG))
@@ -102,7 +108,7 @@ $(LIBSAPROC): $(SASRCFILES) $(SAMAPFILE)
fi
@echo Making SA debugger back-end...
$(QUIETLY) $(CC) -D$(BUILDARCH) -D_GNU_SOURCE \
- $(SYMFLAG) $(SAARCH) $(SHARED_FLAG) $(PICFLAG) \
+ $(SYMFLAG) $(SAARCH) $(SHARED_FLAG) $(PICFLAG) \
-I$(SASRCDIR) \
-I$(GENERATED) \
$(BOOT_JAVA_INCLUDES) \
diff --git a/make/defs.make b/make/defs.make
index 3d86ed70e..4e4c2cb01 100644
--- a/make/defs.make
+++ b/make/defs.make
@@ -302,7 +302,7 @@ ifneq ($(OSNAME),windows)
endif
# Required make macro settings for all platforms
-MAKE_ARGS += JAVA_HOME=$(ABS_BOOTDIR)
+MAKE_ARGS += BOOTDIR=$(ABS_BOOTDIR)
MAKE_ARGS += OUTPUTDIR=$(ABS_OUTPUTDIR)
MAKE_ARGS += GAMMADIR=$(ABS_GAMMADIR)
MAKE_ARGS += MAKE_VERBOSE=$(MAKE_VERBOSE)
@@ -337,9 +337,6 @@ EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jni.h
EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/$(JDK_INCLUDE_SUBDIR)/jni_md.h
EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jmm.h
-# By default, run Queens test after building
-TEST_IN_BUILD ?= true
-
ifndef JAVASE_EMBEDDED
EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jfr.h
endif
diff --git a/make/hotspot_version b/make/hotspot_version
index 28b5a9a11..69b8ad849 100644
--- a/make/hotspot_version
+++ b/make/hotspot_version
@@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2013
HS_MAJOR_VER=25
HS_MINOR_VER=0
-HS_BUILD_NUMBER=23
+HS_BUILD_NUMBER=24
JDK_MAJOR_VER=1
JDK_MINOR_VER=8
diff --git a/make/jprt.properties b/make/jprt.properties
index fa65aa1bc..8bf107758 100644
--- a/make/jprt.properties
+++ b/make/jprt.properties
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -97,15 +97,18 @@ jprt.my.linux.ppcsflt.jdk7=linux_ppcsflt_2.6
jprt.my.linux.ppcsflt.jdk7u8=${jprt.my.linux.ppcsflt.jdk7}
jprt.my.linux.ppcsflt=${jprt.my.linux.ppcsflt.${jprt.tools.default.release}}
-jprt.my.linux.armvfp.jdk8=linux_armvfp_2.6
-jprt.my.linux.armvfp.jdk7=linux_armvfp_2.6
-jprt.my.linux.armvfp.jdk7u8=${jprt.my.linux.armvfp.jdk7}
-jprt.my.linux.armvfp=${jprt.my.linux.armvfp.${jprt.tools.default.release}}
+jprt.my.linux.armvfpsflt.jdk8=linux_armvfpsflt_2.6
+jprt.my.linux.armvfpsflt=${jprt.my.linux.armvfpsflt.${jprt.tools.default.release}}
-jprt.my.linux.armv6.jdk8=linux_armv6_2.6
-jprt.my.linux.armv6.jdk7=linux_armv6_2.6
-jprt.my.linux.armv6.jdk7u8=${jprt.my.linux.armv6.jdk7}
-jprt.my.linux.armv6=${jprt.my.linux.armv6.${jprt.tools.default.release}}
+jprt.my.linux.armvfphflt.jdk8=linux_armvfphflt_2.6
+jprt.my.linux.armvfphflt=${jprt.my.linux.armvfphflt.${jprt.tools.default.release}}
+
+# The ARM GP vfp-sflt build is not currently supported
+#jprt.my.linux.armvs.jdk8=linux_armvs_2.6
+#jprt.my.linux.armvs=${jprt.my.linux.armvs.${jprt.tools.default.release}}
+
+jprt.my.linux.armvh.jdk8=linux_armvh_2.6
+jprt.my.linux.armvh=${jprt.my.linux.armvh.${jprt.tools.default.release}}
jprt.my.linux.armsflt.jdk8=linux_armsflt_2.6
jprt.my.linux.armsflt.jdk7=linux_armsflt_2.6
@@ -139,7 +142,7 @@ jprt.build.targets.standard= \
${jprt.my.macosx.x64}-{product|fastdebug|debug}, \
${jprt.my.windows.i586}-{product|fastdebug|debug}, \
${jprt.my.windows.x64}-{product|fastdebug|debug}, \
- ${jprt.my.linux.armv6}-{product|fastdebug}
+ ${jprt.my.linux.armvh}-{product|fastdebug}
jprt.build.targets.open= \
${jprt.my.solaris.i586}-{productOpen}, \
@@ -151,7 +154,8 @@ jprt.build.targets.embedded= \
${jprt.my.linux.ppc}-{productEmb|fastdebugEmb}, \
${jprt.my.linux.ppcv2}-{productEmb|fastdebugEmb}, \
${jprt.my.linux.ppcsflt}-{productEmb|fastdebugEmb}, \
- ${jprt.my.linux.armvfp}-{productEmb|fastdebugEmb}, \
+ ${jprt.my.linux.armvfpsflt}-{productEmb|fastdebugEmb}, \
+ ${jprt.my.linux.armvfphflt}-{productEmb|fastdebugEmb}, \
${jprt.my.linux.armsflt}-{productEmb|fastdebugEmb}
jprt.build.targets.all=${jprt.build.targets.standard}, \
diff --git a/make/linux/Makefile b/make/linux/Makefile
index e8ef90718..04d0b8e5c 100644
--- a/make/linux/Makefile
+++ b/make/linux/Makefile
@@ -300,63 +300,42 @@ platform_zero: $(GAMMADIR)/make/$(OSNAME)/platform_zero.in
$(TARGETS_C2): $(SUBDIRS_C2)
cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS) install
endif
$(TARGETS_TIERED): $(SUBDIRS_TIERED)
cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS) install
endif
$(TARGETS_C1): $(SUBDIRS_C1)
cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS) install
endif
$(TARGETS_CORE): $(SUBDIRS_CORE)
cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS) install
endif
$(TARGETS_ZERO): $(SUBDIRS_ZERO)
cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && $(MAKE) $(MFLAGS) install
endif
$(TARGETS_SHARK): $(SUBDIRS_SHARK)
cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && $(MAKE) $(MFLAGS) install
endif
$(TARGETS_MINIMAL1): $(SUBDIRS_MINIMAL1)
cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && $(MAKE) $(MFLAGS) install
endif
diff --git a/make/linux/makefiles/buildtree.make b/make/linux/makefiles/buildtree.make
index 960b8f316..b75b4d578 100644
--- a/make/linux/makefiles/buildtree.make
+++ b/make/linux/makefiles/buildtree.make
@@ -50,7 +50,6 @@
# jvmti.make - generate JVMTI bindings from the spec (JSR-163)
# sa.make - generate SA jar file and natives
# env.[ck]sh - environment settings
-# test_gamma - script to run the Queens program
#
# The makefiles are split this way so that "make foo" will run faster by not
# having to read the dependency files for the vm.
@@ -64,9 +63,6 @@ include $(GAMMADIR)/make/altsrc.make
# 'gmake MAKE_VERBOSE=y' or 'gmake QUIETLY=' gives all the gory details.
QUIETLY$(MAKE_VERBOSE) = @
-# For now, until the compiler is less wobbly:
-TESTFLAGS = -Xbatch -showversion
-
ifeq ($(findstring true, $(JVM_VARIANT_ZERO) $(JVM_VARIANT_ZEROSHARK)), true)
PLATFORM_FILE = $(shell dirname $(shell dirname $(shell pwd)))/platform_zero
else
@@ -128,7 +124,7 @@ SUBMAKE_DIRS = $(addprefix $(PLATFORM_DIR)/,$(TARGETS))
BUILDTREE_MAKE = $(GAMMADIR)/make/$(OS_FAMILY)/makefiles/buildtree.make
BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make sa.make \
- env.sh env.csh jdkpath.sh .dbxrc test_gamma
+ env.sh env.csh jdkpath.sh
BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OS_FAMILY) \
SRCARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT)
@@ -345,7 +341,7 @@ env.sh: $(BUILDTREE_MAKE)
@echo Creating $@ ...
$(QUIETLY) ( \
$(BUILDTREE_COMMENT); \
- [ -n "$$JAVA_HOME" ] && { echo ": \$${JAVA_HOME:=$${JAVA_HOME}}"; }; \
+ { echo "JAVA_HOME=$(JDK_IMPORT_PATH)"; }; \
{ \
echo "CLASSPATH=$${CLASSPATH:+$$CLASSPATH:}.:\$${JAVA_HOME}/jre/lib/rt.jar:\$${JAVA_HOME}/jre/lib/i18n.jar"; \
} | sed s:$${JAVA_HOME:--------}:\$${JAVA_HOME}:g; \
@@ -357,8 +353,7 @@ env.csh: env.sh
@echo Creating $@ ...
$(QUIETLY) ( \
$(BUILDTREE_COMMENT); \
- [ -n "$$JAVA_HOME" ] && \
- { echo "if (! \$$?JAVA_HOME) setenv JAVA_HOME \"$$JAVA_HOME\""; }; \
+ { echo "setenv JAVA_HOME \"$(JDK_IMPORT_PATH)\""; }; \
sed -n 's/^\([A-Za-z_][A-Za-z0-9_]*\)=/setenv \1 /p' $?; \
) > $@
@@ -369,119 +364,6 @@ jdkpath.sh: $(BUILDTREE_MAKE)
echo "JDK=${JAVA_HOME}"; \
) > $@
-.dbxrc: $(BUILDTREE_MAKE)
- @echo Creating $@ ...
- $(QUIETLY) ( \
- echo "echo '# Loading $(PLATFORM_DIR)/$(TARGET)/.dbxrc'"; \
- echo "if [ -f \"\$${HOTSPOT_DBXWARE}\" ]"; \
- echo "then"; \
- echo " source \"\$${HOTSPOT_DBXWARE}\""; \
- echo "elif [ -f \"\$$HOME/.dbxrc\" ]"; \
- echo "then"; \
- echo " source \"\$$HOME/.dbxrc\""; \
- echo "fi"; \
- ) > $@
-
-# Skip the test for product builds (which only work when installed in a JDK), to
-# avoid exiting with an error and causing make to halt.
-NO_TEST_MSG = \
- echo "$@: skipping the test--this build must be tested in a JDK."
-
-NO_JAVA_HOME_MSG = \
- echo "JAVA_HOME must be set to run this test."
-
-DATA_MODE = $(DATA_MODE/$(BUILDARCH))
-JAVA_FLAG = $(JAVA_FLAG/$(DATA_MODE))
-
-DATA_MODE/i486 = 32
-DATA_MODE/sparc = 32
-DATA_MODE/sparcv9 = 64
-DATA_MODE/amd64 = 64
-DATA_MODE/ia64 = 64
-DATA_MODE/zero = $(ARCH_DATA_MODEL)
-
-JAVA_FLAG/32 = -d32
-JAVA_FLAG/64 = -d64
-
-WRONG_DATA_MODE_MSG = \
- echo "JAVA_HOME must point to a $(DATA_MODE)-bit OpenJDK."
-
-CROSS_COMPILING_MSG = \
- echo "Cross compiling for ARCH $(CROSS_COMPILE_ARCH), skipping gamma run."
-
-test_gamma: $(BUILDTREE_MAKE) $(GAMMADIR)/make/test/Queens.java
- @echo Creating $@ ...
- $(QUIETLY) ( \
- echo "#!/bin/sh"; \
- echo ""; \
- $(BUILDTREE_COMMENT); \
- echo ""; \
- echo "# Include environment settings for gamma run"; \
- echo ""; \
- echo ". ./env.sh"; \
- echo ""; \
- echo "# Do not run gamma test for cross compiles"; \
- echo ""; \
- echo "if [ -n \"$(CROSS_COMPILE_ARCH)\" ]; then "; \
- echo " $(CROSS_COMPILING_MSG)"; \
- echo " exit 0"; \
- echo "fi"; \
- echo ""; \
- echo "# Make sure JAVA_HOME is set as it is required for gamma"; \
- echo ""; \
- echo "if [ -z \"\$${JAVA_HOME}\" ]; then "; \
- echo " $(NO_JAVA_HOME_MSG)"; \
- echo " exit 0"; \
- echo "fi"; \
- echo ""; \
- echo "# Check JAVA_HOME version to be used for the test"; \
- echo ""; \
- echo "\$${JAVA_HOME}/bin/java $(JAVA_FLAG) -fullversion > /dev/null 2>&1"; \
- echo "if [ \$$? -ne 0 ]; then "; \
- echo " $(WRONG_DATA_MODE_MSG)"; \
- echo " exit 0"; \
- echo "fi"; \
- echo ""; \
- echo "GAMMA_PROG=gamma"; \
- echo ""; \
- echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \
- echo " # Ensure architecture for gamma and JAVA_HOME is the same."; \
- echo " # NOTE: gamma assumes the OpenJDK directory layout."; \
- echo ""; \
- echo " GAMMA_ARCH=\"\`file \$${GAMMA_PROG} | awk '{print \$$NF}'\`\""; \
- echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/libjava.$(LIBRARY_SUFFIX)\""; \
- echo " if [ ! -f \$${JVM_LIB} ]; then"; \
- echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/$${LIBARCH}/libjava.$(LIBRARY_SUFFIX)\""; \
- echo " fi"; \
- echo " if [ ! -f \$${JVM_LIB} ] || [ -z \"\`file \$${JVM_LIB} | grep \$${GAMMA_ARCH}\`\" ]; then "; \
- echo " $(WRONG_DATA_MODE_MSG)"; \
- echo " exit 0"; \
- echo " fi"; \
- echo "fi"; \
- echo ""; \
- echo "# Compile Queens program for test"; \
- echo ""; \
- echo "rm -f Queens.class"; \
- echo "\$${JAVA_HOME}/bin/javac -d . $(GAMMADIR)/make/test/Queens.java"; \
- echo ""; \
- echo "# Set library path solely for gamma launcher test run"; \
- echo ""; \
- echo "LD_LIBRARY_PATH=.:$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \
- echo "export LD_LIBRARY_PATH"; \
- echo "unset LD_LIBRARY_PATH_32"; \
- echo "unset LD_LIBRARY_PATH_64"; \
- echo ""; \
- echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \
- echo " DYLD_LIBRARY_PATH=.:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/native_threads:\$${JAVA_HOME}/jre/lib:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \
- echo " export DYLD_LIBRARY_PATH"; \
- echo "fi"; \
- echo ""; \
- echo "# Use the gamma launcher and JAVA_HOME to run the test"; \
- echo ""; \
- echo "./\$${GAMMA_PROG} $(TESTFLAGS) Queens < /dev/null"; \
- ) > $@
- $(QUIETLY) chmod +x $@
-
FORCE:
.PHONY: all FORCE
diff --git a/make/solaris/Makefile b/make/solaris/Makefile
index 83e4df665..7ae82d856 100644
--- a/make/solaris/Makefile
+++ b/make/solaris/Makefile
@@ -231,36 +231,24 @@ $(SUBDIRS_CORE): $(BUILDTREE_MAKE)
$(TARGETS_C2): $(SUBDIRS_C2)
cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS) install
endif
$(TARGETS_TIERED): $(SUBDIRS_TIERED)
cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS) install
endif
$(TARGETS_C1): $(SUBDIRS_C1)
cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS) install
endif
$(TARGETS_CORE): $(SUBDIRS_CORE)
cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS)
-ifeq ($(TEST_IN_BUILD),true)
- cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && ./test_gamma
-endif
ifdef INSTALL
cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS) install
endif
diff --git a/make/solaris/makefiles/buildtree.make b/make/solaris/makefiles/buildtree.make
index a9e5a401c..707d5f36a 100644
--- a/make/solaris/makefiles/buildtree.make
+++ b/make/solaris/makefiles/buildtree.make
@@ -50,21 +50,19 @@
# jvmti.make - generate JVMTI bindings from the spec (JSR-163)
# sa.make - generate SA jar file and natives
# env.[ck]sh - environment settings
-# test_gamma - script to run the Queens program
#
# The makefiles are split this way so that "make foo" will run faster by not
# having to read the dependency files for the vm.
-include $(SPEC)
include $(GAMMADIR)/make/scm.make
+include $(GAMMADIR)/make/defs.make
include $(GAMMADIR)/make/altsrc.make
+
# 'gmake MAKE_VERBOSE=y' or 'gmake QUIETLY=' gives all the gory details.
QUIETLY$(MAKE_VERBOSE) = @
-# For now, until the compiler is less wobbly:
-TESTFLAGS = -Xbatch -Xmx32m -showversion
-
### maye ARCH_XXX instead?
ifdef USE_GCC
PLATFORM_FILE = $(GAMMADIR)/make/$(OS_FAMILY)/platform_$(BUILDARCH).gcc
@@ -119,7 +117,7 @@ SUBMAKE_DIRS = $(addprefix $(PLATFORM_DIR)/,$(TARGETS))
BUILDTREE_MAKE = $(GAMMADIR)/make/$(OS_FAMILY)/makefiles/buildtree.make
BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make sa.make \
- env.sh env.csh jdkpath.sh .dbxrc test_gamma
+ env.sh env.csh jdkpath.sh
BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OS_FAMILY) \
ARCH=$(ARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT)
@@ -334,7 +332,7 @@ env.sh: $(BUILDTREE_MAKE)
@echo Creating $@ ...
$(QUIETLY) ( \
$(BUILDTREE_COMMENT); \
- [ -n "$$JAVA_HOME" ] && { echo ": \$${JAVA_HOME:=$${JAVA_HOME}}"; }; \
+ { echo "JAVA_HOME=$(JDK_IMPORT_PATH)"; }; \
{ \
echo "CLASSPATH=$${CLASSPATH:+$$CLASSPATH:}.:\$${JAVA_HOME}/jre/lib/rt.jar:\$${JAVA_HOME}/jre/lib/i18n.jar"; \
} | sed s:$${JAVA_HOME:--------}:\$${JAVA_HOME}:g; \
@@ -346,8 +344,7 @@ env.csh: env.sh
@echo Creating $@ ...
$(QUIETLY) ( \
$(BUILDTREE_COMMENT); \
- [ -n "$$JAVA_HOME" ] && \
- { echo "if (! \$$?JAVA_HOME) setenv JAVA_HOME \"$$JAVA_HOME\""; }; \
+ { echo "setenv JAVA_HOME \"$(JDK_IMPORT_PATH)\""; }; \
sed -n 's/^\([A-Za-z_][A-Za-z0-9_]*\)=/setenv \1 /p' $?; \
) > $@
@@ -358,124 +355,6 @@ jdkpath.sh: $(BUILDTREE_MAKE)
echo "JDK=${JAVA_HOME}"; \
) > $@
-.dbxrc: $(BUILDTREE_MAKE)
- @echo Creating $@ ...
- $(QUIETLY) ( \
- echo "echo '# Loading $(PLATFORM_DIR)/$(TARGET)/.dbxrc'"; \
- echo "if [ -f \"\$${HOTSPOT_DBXWARE}\" ]"; \
- echo "then"; \
- echo " source \"\$${HOTSPOT_DBXWARE}\""; \
- echo "elif [ -f \"\$$HOME/.dbxrc\" ]"; \
- echo "then"; \
- echo " source \"\$$HOME/.dbxrc\""; \
- echo "fi"; \
- ) > $@
-
-# Skip the test for product builds (which only work when installed in a JDK), to
-# avoid exiting with an error and causing make to halt.
-NO_TEST_MSG = \
- echo "$@: skipping the test--this build must be tested in a JDK."
-
-NO_JAVA_HOME_MSG = \
- echo "JAVA_HOME must be set to run this test."
-
-DATA_MODE = $(DATA_MODE/$(BUILDARCH))
-JAVA_FLAG = $(JAVA_FLAG/$(DATA_MODE))
-
-DATA_MODE/i486 = 32
-DATA_MODE/sparc = 32
-DATA_MODE/sparcv9 = 64
-DATA_MODE/amd64 = 64
-DATA_MODE/ia64 = 64
-
-# This bit is needed to enable local rebuilds.
-# Unless the makefile itself sets LP64, any environmental
-# setting of LP64 will interfere with the build.
-LP64_SETTING/32 = LP64 = \#empty
-LP64_SETTING/64 = LP64 = 1
-
-JAVA_FLAG/32 = -d32
-JAVA_FLAG/64 = -d64
-
-WRONG_DATA_MODE_MSG = \
- echo "JAVA_HOME must point to a $(DATA_MODE)-bit OpenJDK."
-
-CROSS_COMPILING_MSG = \
- echo "Cross compiling for ARCH $(CROSS_COMPILE_ARCH), skipping gamma run."
-
-test_gamma: $(BUILDTREE_MAKE) $(GAMMADIR)/make/test/Queens.java
- @echo Creating $@ ...
- $(QUIETLY) ( \
- echo "#!/bin/sh"; \
- echo ""; \
- $(BUILDTREE_COMMENT); \
- echo ""; \
- echo "# Include environment settings for gamma run"; \
- echo ""; \
- echo ". ./env.sh"; \
- echo ""; \
- echo "# Do not run gamma test for cross compiles"; \
- echo ""; \
- echo "if [ -n \"$(CROSS_COMPILE_ARCH)\" ]; then "; \
- echo " $(CROSS_COMPILING_MSG)"; \
- echo " exit 0"; \
- echo "fi"; \
- echo ""; \
- echo "# Make sure JAVA_HOME is set as it is required for gamma"; \
- echo ""; \
- echo "if [ -z \"\$${JAVA_HOME}\" ]; then "; \
- echo " $(NO_JAVA_HOME_MSG)"; \
- echo " exit 0"; \
- echo "fi"; \
- echo ""; \
- echo "# Check JAVA_HOME version to be used for the test"; \
- echo ""; \
- echo "\$${JAVA_HOME}/bin/java $(JAVA_FLAG) -fullversion > /dev/null 2>&1"; \
- echo "if [ \$$? -ne 0 ]; then "; \
- echo " $(WRONG_DATA_MODE_MSG)"; \
- echo " exit 0"; \
- echo "fi"; \
- echo ""; \
- echo "GAMMA_PROG=gamma"; \
- echo ""; \
- echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \
- echo " # Ensure architecture for gamma and JAVA_HOME is the same."; \
- echo " # NOTE: gamma assumes the OpenJDK directory layout."; \
- echo ""; \
- echo " GAMMA_ARCH=\"\`file \$${GAMMA_PROG} | awk '{print \$$NF}'\`\""; \
- echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/libjava.$(LIBRARY_SUFFIX)\""; \
- echo " if [ ! -f \$${JVM_LIB} ]; then"; \
- echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/$${LIBARCH}/libjava.$(LIBRARY_SUFFIX)\""; \
- echo " fi"; \
- echo " if [ ! -f \$${JVM_LIB} ] || [ -z \"\`file \$${JVM_LIB} | grep \$${GAMMA_ARCH}\`\" ]; then "; \
- echo " $(WRONG_DATA_MODE_MSG)"; \
- echo " exit 0"; \
- echo " fi"; \
- echo "fi"; \
- echo ""; \
- echo "# Compile Queens program for test"; \
- echo ""; \
- echo "rm -f Queens.class"; \
- echo "\$${JAVA_HOME}/bin/javac -d . $(GAMMADIR)/make/test/Queens.java"; \
- echo ""; \
- echo "# Set library path solely for gamma launcher test run"; \
- echo ""; \
- echo "LD_LIBRARY_PATH=.:$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \
- echo "export LD_LIBRARY_PATH"; \
- echo "unset LD_LIBRARY_PATH_32"; \
- echo "unset LD_LIBRARY_PATH_64"; \
- echo ""; \
- echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \
- echo " DYLD_LIBRARY_PATH=.:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/native_threads:\$${JAVA_HOME}/jre/lib:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \
- echo " export DYLD_LIBRARY_PATH"; \
- echo "fi"; \
- echo ""; \
- echo "# Use the gamma launcher and JAVA_HOME to run the test"; \
- echo ""; \
- echo "./\$${GAMMA_PROG} $(TESTFLAGS) Queens < /dev/null"; \
- ) > $@
- $(QUIETLY) chmod +x $@
-
FORCE:
.PHONY: all FORCE
diff --git a/make/test/Queens.java b/make/test/Queens.java
deleted file mode 100644
index ab7a9e2c1..000000000
--- a/make/test/Queens.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2006, 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-import java.util.*;
-
-// Copyright 1996, Animorphic Systems
-// gri 28 Aug 92 / 15 Jan 93 / 8 Dec 95
-
-class Queens {
-
- static void try_i(boolean a[], boolean b[], boolean c[], int x[], int i) {
- int adj = 7;
-
- for (int j = 1; j <= 8; j++) {
- if (b[j] && a[i+j] && c[adj+i-j]) {
- x[i] = j;
- b[j] = false;
- a[i+j] = false;
- c[adj+i-j] = false;
- if (i < 8) try_i(a, b, c, x, i+1);
- else print(x);
- b[j] = true;
- a[i+j] = true;
- c[adj+i-j] = true;
- }
- }
- }
-
- public static void main(String s[]) {
- boolean a[] = new boolean[16+1];
- boolean b[] = new boolean[ 8+1];
- boolean c[] = new boolean[14+1];
- int x[] = new int[8+1];
- int adj = 7;
-
- for (int i = -7; i <= 16; i++) {
- if (i >= 1 && i <= 8) b[i] = true;
- if (i >= 2) a[i] = true;
- if (i <= 7) c[adj+i] = true;
- }
-
- x[0] = 0; // solution counter
-
- try_i(a, b, c, x, 1);
- }
-
- static void print(int x[]) {
- // first correct solution: A1 B5 C8 D6 E3 F7 G2 H4
-
- char LF = (char)0xA;
- char CR = (char)0xD;
-
- x[0]++;
- if (x[0] < 10)
- System.out.print(" ");
- System.out.print(x[0] + ". ");
- for (int i = 1; i <= 8; i++) {
- char p = (char)('A' + i - 1);
- System.out.print(p);
- System.out.print (x[i] + " ");
- }
- System.out.println();
- }
-
-};
diff --git a/src/cpu/sparc/vm/macroAssembler_sparc.cpp b/src/cpu/sparc/vm/macroAssembler_sparc.cpp
index 251e42cd6..578650a34 100644
--- a/src/cpu/sparc/vm/macroAssembler_sparc.cpp
+++ b/src/cpu/sparc/vm/macroAssembler_sparc.cpp
@@ -1385,13 +1385,13 @@ void MacroAssembler::_verify_oop(Register reg, const char* msg, const char * fil
}
#endif
- int len = strlen(file) + strlen(msg) + 1 + 4;
- sprintf(buffer, "%d", line);
- len += strlen(buffer);
- sprintf(buffer, " at offset %d ", offset());
- len += strlen(buffer);
- char * real_msg = new char[len];
- sprintf(real_msg, "%s%s(%s:%d)", msg, buffer, file, line);
+ const char* real_msg = NULL;
+ {
+ ResourceMark rm;
+ stringStream ss;
+ ss.print("%s at offset %d (%s:%d)", msg, offset(), file, line);
+ real_msg = code_string(ss.as_string());
+ }
// Call indirectly to solve generation ordering problem
AddressLiteral a(StubRoutines::verify_oop_subroutine_entry_address());
@@ -1423,13 +1423,13 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* msg, const char
// plausibility check for oops
if (!VerifyOops) return;
- char buffer[64];
- sprintf(buffer, "%d", line);
- int len = strlen(file) + strlen(msg) + 1 + 4 + strlen(buffer);
- sprintf(buffer, " at SP+%d ", addr.disp());
- len += strlen(buffer);
- char * real_msg = new char[len];
- sprintf(real_msg, "%s at SP+%d (%s:%d)", msg, addr.disp(), file, line);
+ const char* real_msg = NULL;
+ {
+ ResourceMark rm;
+ stringStream ss;
+ ss.print("%s at SP+%d (%s:%d)", msg, addr.disp(), file, line);
+ real_msg = code_string(ss.as_string());
+ }
// Call indirectly to solve generation ordering problem
AddressLiteral a(StubRoutines::verify_oop_subroutine_entry_address());
@@ -1622,9 +1622,13 @@ void MacroAssembler::untested(const char* what) {
// in order to run automated test scripts on the VM
// Use the flag ShowMessageBoxOnError
- char* b = new char[1024];
- sprintf(b, "untested: %s", what);
-
+ const char* b = NULL;
+ {
+ ResourceMark rm;
+ stringStream ss;
+ ss.print("untested: %s", what);
+ b = code_string(ss.as_string());
+ }
if (ShowMessageBoxOnError) { STOP(b); }
else { warn(b); }
}
diff --git a/src/cpu/x86/vm/frame_x86.inline.hpp b/src/cpu/x86/vm/frame_x86.inline.hpp
index ea8111b9f..b15b00be5 100644
--- a/src/cpu/x86/vm/frame_x86.inline.hpp
+++ b/src/cpu/x86/vm/frame_x86.inline.hpp
@@ -295,14 +295,18 @@ inline bool frame::volatile_across_calls(Register reg) {
return true;
}
+inline oop frame::saved_oop_result(RegisterMap* map) const {
+ oop* result_adr = (oop *)map->location(rax->as_VMReg());
+ guarantee(result_adr != NULL, "bad register save location");
-
-inline oop frame::saved_oop_result(RegisterMap* map) const {
- return *((oop*) map->location(rax->as_VMReg()));
+ return (*result_adr);
}
inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) {
- *((oop*) map->location(rax->as_VMReg())) = obj;
+ oop* result_adr = (oop *)map->location(rax->as_VMReg());
+ guarantee(result_adr != NULL, "bad register save location");
+
+ *result_adr = obj;
}
#endif // CPU_X86_VM_FRAME_X86_INLINE_HPP
diff --git a/src/cpu/x86/vm/macroAssembler_x86.cpp b/src/cpu/x86/vm/macroAssembler_x86.cpp
index bda1550ac..b64518a7b 100644
--- a/src/cpu/x86/vm/macroAssembler_x86.cpp
+++ b/src/cpu/x86/vm/macroAssembler_x86.cpp
@@ -4262,8 +4262,13 @@ void MacroAssembler::verify_oop(Register reg, const char* s) {
if (!VerifyOops) return;
// Pass register number to verify_oop_subroutine
- char* b = new char[strlen(s) + 50];
- sprintf(b, "verify_oop: %s: %s", reg->name(), s);
+ const char* b = NULL;
+ {
+ ResourceMark rm;
+ stringStream ss;
+ ss.print("verify_oop: %s: %s", reg->name(), s);
+ b = code_string(ss.as_string());
+ }
BLOCK_COMMENT("verify_oop {");
#ifdef _LP64
push(rscratch1); // save r10, trashed by movptr()
@@ -4297,9 +4302,14 @@ RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_ad
{ Label L;
testptr(tmp, tmp);
if (WizardMode) {
+ const char* buf = NULL;
+ {
+ ResourceMark rm;
+ stringStream ss;
+ ss.print("DelayedValue="INTPTR_FORMAT, delayed_value_addr[1]);
+ buf = code_string(ss.as_string());
+ }
jcc(Assembler::notZero, L);
- char* buf = new char[40];
- sprintf(buf, "DelayedValue="INTPTR_FORMAT, delayed_value_addr[1]);
STOP(buf);
} else {
jccb(Assembler::notZero, L);
@@ -4343,9 +4353,13 @@ void MacroAssembler::verify_oop_addr(Address addr, const char* s) {
// Address adjust(addr.base(), addr.index(), addr.scale(), addr.disp() + BytesPerWord);
// Pass register number to verify_oop_subroutine
- char* b = new char[strlen(s) + 50];
- sprintf(b, "verify_oop_addr: %s", s);
-
+ const char* b = NULL;
+ {
+ ResourceMark rm;
+ stringStream ss;
+ ss.print("verify_oop_addr: %s", s);
+ b = code_string(ss.as_string());
+ }
#ifdef _LP64
push(rscratch1); // save r10, trashed by movptr()
#endif
diff --git a/src/cpu/x86/vm/relocInfo_x86.cpp b/src/cpu/x86/vm/relocInfo_x86.cpp
index d4a929613..e16c66539 100644
--- a/src/cpu/x86/vm/relocInfo_x86.cpp
+++ b/src/cpu/x86/vm/relocInfo_x86.cpp
@@ -145,12 +145,9 @@ address* Relocation::pd_address_in_code() {
assert(which == Assembler::disp32_operand ||
which == Assembler::call32_operand ||
which == Assembler::imm_operand, "format unpacks ok");
- if (which != Assembler::imm_operand) {
- // The "address" in the code is a displacement can't return it as
- // and address* since it is really a jint*
- ShouldNotReachHere();
- return NULL;
- }
+ // The "address" in the code is a displacement can't return it as
+ // and address* since it is really a jint*
+ guarantee(which == Assembler::imm_operand, "must be immediate operand");
#else
assert(which == Assembler::disp32_operand || which == Assembler::imm_operand, "format unpacks ok");
#endif // AMD64
diff --git a/src/os_cpu/linux_x86/vm/os_linux_x86.cpp b/src/os_cpu/linux_x86/vm/os_linux_x86.cpp
index 4c9d3dbed..5cdab45d4 100644
--- a/src/os_cpu/linux_x86/vm/os_linux_x86.cpp
+++ b/src/os_cpu/linux_x86/vm/os_linux_x86.cpp
@@ -340,7 +340,7 @@ JVM_handle_linux_signal(int sig,
// here if the underlying file has been truncated.
// Do not crash the VM in such a case.
CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
- nmethod* nm = cb->is_nmethod() ? (nmethod*)cb : NULL;
+ nmethod* nm = (cb != NULL && cb->is_nmethod()) ? (nmethod*)cb : NULL;
if (nm != NULL && nm->has_unsafe_access()) {
stub = StubRoutines::handler_for_unsafe_access();
}
diff --git a/src/share/vm/asm/assembler.cpp b/src/share/vm/asm/assembler.cpp
index 669f49039..d23c0f50f 100644
--- a/src/share/vm/asm/assembler.cpp
+++ b/src/share/vm/asm/assembler.cpp
@@ -284,15 +284,19 @@ void AbstractAssembler::update_delayed_values() {
DelayedConstant::update_all();
}
-
-
-
void AbstractAssembler::block_comment(const char* comment) {
if (sect() == CodeBuffer::SECT_INSTS) {
code_section()->outer()->block_comment(offset(), comment);
}
}
+const char* AbstractAssembler::code_string(const char* str) {
+ if (sect() == CodeBuffer::SECT_INSTS || sect() == CodeBuffer::SECT_STUBS) {
+ return code_section()->outer()->code_string(str);
+ }
+ return NULL;
+}
+
bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
// Exception handler checks the nmethod's implicit null checks table
// only when this method returns false.
diff --git a/src/share/vm/asm/assembler.hpp b/src/share/vm/asm/assembler.hpp
index 0a55dc90e..8a9e2758a 100644
--- a/src/share/vm/asm/assembler.hpp
+++ b/src/share/vm/asm/assembler.hpp
@@ -336,6 +336,8 @@ class AbstractAssembler : public ResourceObj {
// along with the disassembly when printing nmethods. Currently
// only supported in the instruction section of the code buffer.
void block_comment(const char* comment);
+ // Copy str to a buffer that has the same lifetime as the CodeBuffer
+ const char* code_string(const char* str);
// Label functions
void bind(Label& L); // binds an unbound label L to the current code position
diff --git a/src/share/vm/asm/codeBuffer.cpp b/src/share/vm/asm/codeBuffer.cpp
index 2a4a8f298..f885c4153 100644
--- a/src/share/vm/asm/codeBuffer.cpp
+++ b/src/share/vm/asm/codeBuffer.cpp
@@ -703,8 +703,8 @@ void CodeBuffer::copy_code_to(CodeBlob* dest_blob) {
this->compute_final_layout(&dest);
relocate_code_to(&dest);
- // transfer comments from buffer to blob
- dest_blob->set_comments(_comments);
+ // transfer strings and comments from buffer to blob
+ dest_blob->set_strings(_strings);
// Done moving code bytes; were they the right size?
assert(round_to(dest.total_content_size(), oopSize) == dest_blob->content_size(), "sanity");
@@ -1003,58 +1003,78 @@ void CodeSection::decode() {
void CodeBuffer::block_comment(intptr_t offset, const char * comment) {
- _comments.add_comment(offset, comment);
+ _strings.add_comment(offset, comment);
}
-class CodeComment: public CHeapObj<mtCode> {
+const char* CodeBuffer::code_string(const char* str) {
+ return _strings.add_string(str);
+}
+
+class CodeString: public CHeapObj<mtCode> {
private:
- friend class CodeComments;
+ friend class CodeStrings;
+ const char * _string;
+ CodeString* _next;
intptr_t _offset;
- const char * _comment;
- CodeComment* _next;
- ~CodeComment() {
+ ~CodeString() {
assert(_next == NULL, "wrong interface for freeing list");
- os::free((void*)_comment, mtCode);
+ os::free((void*)_string, mtCode);
}
+ bool is_comment() const { return _offset >= 0; }
+
public:
- CodeComment(intptr_t offset, const char * comment) {
- _offset = offset;
- _comment = os::strdup(comment, mtCode);
- _next = NULL;
+ CodeString(const char * string, intptr_t offset = -1)
+ : _next(NULL), _offset(offset) {
+ _string = os::strdup(string, mtCode);
}
- intptr_t offset() const { return _offset; }
- const char * comment() const { return _comment; }
- CodeComment* next() { return _next; }
+ const char * string() const { return _string; }
+ intptr_t offset() const { assert(_offset >= 0, "offset for non comment?"); return _offset; }
+ CodeString* next() const { return _next; }
- void set_next(CodeComment* next) { _next = next; }
+ void set_next(CodeString* next) { _next = next; }
- CodeComment* find(intptr_t offset) {
- CodeComment* a = this;
- while (a != NULL && a->_offset != offset) {
- a = a->_next;
+ CodeString* first_comment() {
+ if (is_comment()) {
+ return this;
+ } else {
+ return next_comment();
}
- return a;
}
-
- // Convenience for add_comment.
- CodeComment* find_last(intptr_t offset) {
- CodeComment* a = find(offset);
- if (a != NULL) {
- while ((a->_next != NULL) && (a->_next->_offset == offset)) {
- a = a->_next;
- }
+ CodeString* next_comment() const {
+ CodeString* s = _next;
+ while (s != NULL && !s->is_comment()) {
+ s = s->_next;
}
- return a;
+ return s;
}
};
+CodeString* CodeStrings::find(intptr_t offset) const {
+ CodeString* a = _strings->first_comment();
+ while (a != NULL && a->offset() != offset) {
+ a = a->next_comment();
+ }
+ return a;
+}
+
+// Convenience for add_comment.
+CodeString* CodeStrings::find_last(intptr_t offset) const {
+ CodeString* a = find(offset);
+ if (a != NULL) {
+ CodeString* c = NULL;
+ while (((c = a->next_comment()) != NULL) && (c->offset() == offset)) {
+ a = c;
+ }
+ }
+ return a;
+}
-void CodeComments::add_comment(intptr_t offset, const char * comment) {
- CodeComment* c = new CodeComment(offset, comment);
- CodeComment* inspos = (_comments == NULL) ? NULL : _comments->find_last(offset);
+void CodeStrings::add_comment(intptr_t offset, const char * comment) {
+ CodeString* c = new CodeString(comment, offset);
+ CodeString* inspos = (_strings == NULL) ? NULL : find_last(offset);
if (inspos) {
// insert after already existing comments with same offset
@@ -1062,43 +1082,47 @@ void CodeComments::add_comment(intptr_t offset, const char * comment) {
inspos->set_next(c);
} else {
// no comments with such offset, yet. Insert before anything else.
- c->set_next(_comments);
- _comments = c;
+ c->set_next(_strings);
+ _strings = c;
}
}
-
-void CodeComments::assign(CodeComments& other) {
- _comments = other._comments;
+void CodeStrings::assign(CodeStrings& other) {
+ _strings = other._strings;
}
-
-void CodeComments::print_block_comment(outputStream* stream, intptr_t offset) const {
- if (_comments != NULL) {
- CodeComment* c = _comments->find(offset);
+void CodeStrings::print_block_comment(outputStream* stream, intptr_t offset) const {
+ if (_strings != NULL) {
+ CodeString* c = find(offset);
while (c && c->offset() == offset) {
stream->bol();
stream->print(" ;; ");
- stream->print_cr(c->comment());
- c = c->next();
+ stream->print_cr(c->string());
+ c = c->next_comment();
}
}
}
-void CodeComments::free() {
- CodeComment* n = _comments;
+void CodeStrings::free() {
+ CodeString* n = _strings;
while (n) {
// unlink the node from the list saving a pointer to the next
- CodeComment* p = n->_next;
- n->_next = NULL;
+ CodeString* p = n->next();
+ n->set_next(NULL);
delete n;
n = p;
}
- _comments = NULL;
+ _strings = NULL;
}
-
+const char* CodeStrings::add_string(const char * string) {
+ CodeString* s = new CodeString(string);
+ s->set_next(_strings);
+ _strings = s;
+ assert(s->string() != NULL, "should have a string");
+ return s->string();
+}
void CodeBuffer::decode() {
ttyLocker ttyl;
diff --git a/src/share/vm/asm/codeBuffer.hpp b/src/share/vm/asm/codeBuffer.hpp
index d13697ef4..8ce94646d 100644
--- a/src/share/vm/asm/codeBuffer.hpp
+++ b/src/share/vm/asm/codeBuffer.hpp
@@ -28,7 +28,7 @@
#include "code/oopRecorder.hpp"
#include "code/relocInfo.hpp"
-class CodeComments;
+class CodeStrings;
class PhaseCFG;
class Compile;
class BufferBlob;
@@ -240,27 +240,31 @@ class CodeSection VALUE_OBJ_CLASS_SPEC {
#endif //PRODUCT
};
-class CodeComment;
-class CodeComments VALUE_OBJ_CLASS_SPEC {
+class CodeString;
+class CodeStrings VALUE_OBJ_CLASS_SPEC {
private:
#ifndef PRODUCT
- CodeComment* _comments;
+ CodeString* _strings;
#endif
+ CodeString* find(intptr_t offset) const;
+ CodeString* find_last(intptr_t offset) const;
+
public:
- CodeComments() {
+ CodeStrings() {
#ifndef PRODUCT
- _comments = NULL;
+ _strings = NULL;
#endif
}
+ const char* add_string(const char * string) PRODUCT_RETURN_(return NULL;);
+
void add_comment(intptr_t offset, const char * comment) PRODUCT_RETURN;
void print_block_comment(outputStream* stream, intptr_t offset) const PRODUCT_RETURN;
- void assign(CodeComments& other) PRODUCT_RETURN;
+ void assign(CodeStrings& other) PRODUCT_RETURN;
void free() PRODUCT_RETURN;
};
-
// A CodeBuffer describes a memory space into which assembly
// code is generated. This memory space usually occupies the
// interior of a single BufferBlob, but in some cases it may be
@@ -326,7 +330,7 @@ class CodeBuffer: public StackObj {
csize_t _total_size; // size in bytes of combined memory buffer
OopRecorder* _oop_recorder;
- CodeComments _comments;
+ CodeStrings _strings;
OopRecorder _default_oop_recorder; // override with initialize_oop_recorder
Arena* _overflow_arena;
@@ -527,7 +531,7 @@ class CodeBuffer: public StackObj {
void initialize_oop_recorder(OopRecorder* r);
OopRecorder* oop_recorder() const { return _oop_recorder; }
- CodeComments& comments() { return _comments; }
+ CodeStrings& strings() { return _strings; }
// Code generation
void relocate(address at, RelocationHolder const& rspec, int format = 0) {
@@ -556,6 +560,7 @@ class CodeBuffer: public StackObj {
address transform_address(const CodeBuffer &cb, address addr) const;
void block_comment(intptr_t offset, const char * comment) PRODUCT_RETURN;
+ const char* code_string(const char* str) PRODUCT_RETURN_(return NULL;);
// Log a little info about section usage in the CodeBuffer
void log_section_sizes(const char* name);
diff --git a/src/share/vm/ci/ciEnv.cpp b/src/share/vm/ci/ciEnv.cpp
index a9a3706df..6dff1e939 100644
--- a/src/share/vm/ci/ciEnv.cpp
+++ b/src/share/vm/ci/ciEnv.cpp
@@ -802,6 +802,7 @@ ciInstanceKlass* ciEnv::get_instance_klass_for_declared_method_holder(ciKlass* m
// require checks to make sure the expected type was found. Given that this
// only occurs for clone() the more extensive fix seems like overkill so
// instead we simply smear the array type into Object.
+ guarantee(method_holder != NULL, "no method holder");
if (method_holder->is_instance_klass()) {
return method_holder->as_instance_klass();
} else if (method_holder->is_array_klass()) {
diff --git a/src/share/vm/classfile/classLoaderData.cpp b/src/share/vm/classfile/classLoaderData.cpp
index e74a88d7d..f74f8f1ce 100644
--- a/src/share/vm/classfile/classLoaderData.cpp
+++ b/src/share/vm/classfile/classLoaderData.cpp
@@ -105,6 +105,7 @@ void ClassLoaderData::oops_do(OopClosure* f, KlassClosure* klass_closure, bool m
void ClassLoaderData::classes_do(KlassClosure* klass_closure) {
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
klass_closure->do_klass(k);
+ assert(k != k->next_link(), "no loops!");
}
}
@@ -113,6 +114,7 @@ void ClassLoaderData::classes_do(void f(InstanceKlass*)) {
if (k->oop_is_instance()) {
f(InstanceKlass::cast(k));
}
+ assert(k != k->next_link(), "no loops!");
}
}
@@ -258,6 +260,7 @@ void ClassLoaderData::remove_class(Klass* scratch_class) {
return;
}
prev = k;
+ assert(k != k->next_link(), "no loops!");
}
ShouldNotReachHere(); // should have found this class!!
}
@@ -439,6 +442,7 @@ void ClassLoaderData::dump(outputStream * const out) {
while (k != NULL) {
out->print_cr("klass "PTR_FORMAT", %s, CT: %d, MUT: %d", k, k->name()->as_C_string(),
k->has_modified_oops(), k->has_accumulated_modified_oops());
+ assert(k != k->next_link(), "no loops!");
k = k->next_link();
}
}
@@ -465,6 +469,7 @@ void ClassLoaderData::verify() {
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
guarantee(k->class_loader_data() == this, "Must be the same");
k->verify();
+ assert(k != k->next_link(), "no loops!");
}
}
diff --git a/src/share/vm/classfile/defaultMethods.cpp b/src/share/vm/classfile/defaultMethods.cpp
index 4e43d7fd3..1977b07ea 100644
--- a/src/share/vm/classfile/defaultMethods.cpp
+++ b/src/share/vm/classfile/defaultMethods.cpp
@@ -348,7 +348,7 @@ class MethodFamily : public ResourceObj {
void disqualify_method(Method* method) {
int* index = _member_index.get(method);
- assert(index != NULL && *index >= 0 && *index < _members.length(), "bad index");
+ guarantee(index != NULL && *index >= 0 && *index < _members.length(), "bad index");
_members.at(*index).second = DISQUALIFIED;
}
diff --git a/src/share/vm/classfile/systemDictionary.cpp b/src/share/vm/classfile/systemDictionary.cpp
index 002d781f9..edd310706 100644
--- a/src/share/vm/classfile/systemDictionary.cpp
+++ b/src/share/vm/classfile/systemDictionary.cpp
@@ -804,6 +804,32 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla
}
} // load_instance_class loop
+ if (HAS_PENDING_EXCEPTION) {
+ // An exception, such as OOM could have happened at various places inside
+ // load_instance_class. We might have partially initialized a shared class
+ // and need to clean it up.
+ if (class_loader.is_null()) {
+ // In some cases k may be null. Let's find the shared class again.
+ instanceKlassHandle ik(THREAD, find_shared_class(name));
+ if (ik.not_null()) {
+ if (ik->class_loader_data() == NULL) {
+ // We didn't go as far as Klass::restore_unshareable_info(),
+ // so nothing to clean up.
+ } else {
+ MutexLocker mu(SystemDictionary_lock, THREAD);
+ Klass* kk = find_class(name, ik->class_loader_data());
+ if (kk != NULL) {
+ // No clean up is needed if the shared class has been entered
+ // into system dictionary, as load_shared_class() won't be called
+ // again.
+ } else {
+ clean_up_shared_class(ik, class_loader, THREAD);
+ }
+ }
+ }
+ }
+ }
+
if (load_instance_added == true) {
// clean up placeholder entries for LOAD_INSTANCE success or error
// This brackets the SystemDictionary updates for both defining
@@ -1140,11 +1166,6 @@ instanceKlassHandle SystemDictionary::load_shared_class(
return load_shared_class(ik, class_loader, THREAD);
}
-// Note well! Changes to this method may affect oop access order
-// in the shared archive. Please take care to not make changes that
-// adversely affect cold start time by changing the oop access order
-// that is specified in dump.cpp MarkAndMoveOrderedReadOnly and
-// MarkAndMoveOrderedReadWrite closures.
instanceKlassHandle SystemDictionary::load_shared_class(
instanceKlassHandle ik, Handle class_loader, TRAPS) {
assert(class_loader.is_null(), "non-null classloader for shared class?");
@@ -1205,6 +1226,19 @@ instanceKlassHandle SystemDictionary::load_shared_class(
return ik;
}
+void SystemDictionary::clean_up_shared_class(instanceKlassHandle ik, Handle class_loader, TRAPS) {
+ // Updating methods must be done under a lock so multiple
+ // threads don't update these in parallel
+ // Shared classes are all currently loaded by the bootstrap
+ // classloader, so this will never cause a deadlock on
+ // a custom class loader lock.
+ {
+ Handle lockObject = compute_loader_lock_object(class_loader, THREAD);
+ check_loader_lock_contention(lockObject, THREAD);
+ ObjectLocker ol(lockObject, THREAD, true);
+ ik->remove_unshareable_info();
+ }
+}
instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) {
instanceKlassHandle nh = instanceKlassHandle(); // null Handle
diff --git a/src/share/vm/classfile/systemDictionary.hpp b/src/share/vm/classfile/systemDictionary.hpp
index d415c9b1e..d282fedfb 100644
--- a/src/share/vm/classfile/systemDictionary.hpp
+++ b/src/share/vm/classfile/systemDictionary.hpp
@@ -621,6 +621,7 @@ private:
Handle class_loader, TRAPS);
static instanceKlassHandle load_shared_class(instanceKlassHandle ik,
Handle class_loader, TRAPS);
+ static void clean_up_shared_class(instanceKlassHandle ik, Handle class_loader, TRAPS);
static instanceKlassHandle load_instance_class(Symbol* class_name, Handle class_loader, TRAPS);
static Handle compute_loader_lock_object(Handle class_loader, TRAPS);
static void check_loader_lock_contention(Handle loader_lock, TRAPS);
diff --git a/src/share/vm/code/codeBlob.cpp b/src/share/vm/code/codeBlob.cpp
index 779235f25..6120d3535 100644
--- a/src/share/vm/code/codeBlob.cpp
+++ b/src/share/vm/code/codeBlob.cpp
@@ -186,7 +186,7 @@ void CodeBlob::flush() {
FREE_C_HEAP_ARRAY(unsigned char, _oop_maps, mtCode);
_oop_maps = NULL;
}
- _comments.free();
+ _strings.free();
}
diff --git a/src/share/vm/code/codeBlob.hpp b/src/share/vm/code/codeBlob.hpp
index 1d47bd972..e59ae7f1f 100644
--- a/src/share/vm/code/codeBlob.hpp
+++ b/src/share/vm/code/codeBlob.hpp
@@ -66,7 +66,7 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC {
int _data_offset; // offset to where data region begins
int _frame_size; // size of stack frame
OopMapSet* _oop_maps; // OopMap for this CodeBlob
- CodeComments _comments;
+ CodeStrings _strings;
public:
// Returns the space needed for CodeBlob
@@ -186,12 +186,12 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC {
// Print the comment associated with offset on stream, if there is one
virtual void print_block_comment(outputStream* stream, address block_begin) const {
intptr_t offset = (intptr_t)(block_begin - code_begin());
- _comments.print_block_comment(stream, offset);
+ _strings.print_block_comment(stream, offset);
}
// Transfer ownership of comments to this CodeBlob
- void set_comments(CodeComments& comments) {
- _comments.assign(comments);
+ void set_strings(CodeStrings& strings) {
+ _strings.assign(strings);
}
};
diff --git a/src/share/vm/code/compiledIC.cpp b/src/share/vm/code/compiledIC.cpp
index 7677dae57..85eeda470 100644
--- a/src/share/vm/code/compiledIC.cpp
+++ b/src/share/vm/code/compiledIC.cpp
@@ -552,7 +552,7 @@ bool CompiledStaticCall::is_call_to_interpreted() const {
void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
address stub=find_stub();
- assert(stub!=NULL, "stub not found");
+ guarantee(stub != NULL, "stub not found");
if (TraceICs) {
ResourceMark rm;
diff --git a/src/share/vm/code/icBuffer.hpp b/src/share/vm/code/icBuffer.hpp
index 36d0c7616..47db2d6b2 100644
--- a/src/share/vm/code/icBuffer.hpp
+++ b/src/share/vm/code/icBuffer.hpp
@@ -50,7 +50,7 @@ class ICStub: public Stub {
friend class ICStubInterface;
// This will be called only by ICStubInterface
void initialize(int size,
- CodeComments comments) { _size = size; _ic_site = NULL; }
+ CodeStrings strings) { _size = size; _ic_site = NULL; }
void finalize(); // called when a method is removed
// General info
diff --git a/src/share/vm/code/stubs.cpp b/src/share/vm/code/stubs.cpp
index 245a2463a..930c637fa 100644
--- a/src/share/vm/code/stubs.cpp
+++ b/src/share/vm/code/stubs.cpp
@@ -101,8 +101,8 @@ Stub* StubQueue::stub_containing(address pc) const {
Stub* StubQueue::request_committed(int code_size) {
Stub* s = request(code_size);
- CodeComments comments;
- if (s != NULL) commit(code_size, comments);
+ CodeStrings strings;
+ if (s != NULL) commit(code_size, strings);
return s;
}
@@ -119,8 +119,8 @@ Stub* StubQueue::request(int requested_code_size) {
assert(_buffer_limit == _buffer_size, "buffer must be fully usable");
if (_queue_end + requested_size <= _buffer_size) {
// code fits in at the end => nothing to do
- CodeComments comments;
- stub_initialize(s, requested_size, comments);
+ CodeStrings strings;
+ stub_initialize(s, requested_size, strings);
return s;
} else {
// stub doesn't fit in at the queue end
@@ -137,8 +137,8 @@ Stub* StubQueue::request(int requested_code_size) {
// Queue: |XXX|.......|XXXXXXX|.......|
// ^0 ^end ^begin ^limit ^size
s = current_stub();
- CodeComments comments;
- stub_initialize(s, requested_size, comments);
+ CodeStrings strings;
+ stub_initialize(s, requested_size, strings);
return s;
}
// Not enough space left
@@ -147,12 +147,12 @@ Stub* StubQueue::request(int requested_code_size) {
}
-void StubQueue::commit(int committed_code_size, CodeComments& comments) {
+void StubQueue::commit(int committed_code_size, CodeStrings& strings) {
assert(committed_code_size > 0, "committed_code_size must be > 0");
int committed_size = round_to(stub_code_size_to_size(committed_code_size), CodeEntryAlignment);
Stub* s = current_stub();
assert(committed_size <= stub_size(s), "committed size must not exceed requested size");
- stub_initialize(s, committed_size, comments);
+ stub_initialize(s, committed_size, strings);
_queue_end += committed_size;
_number_of_stubs++;
if (_mutex != NULL) _mutex->unlock();
diff --git a/src/share/vm/code/stubs.hpp b/src/share/vm/code/stubs.hpp
index 36ada2a4c..233f43e2d 100644
--- a/src/share/vm/code/stubs.hpp
+++ b/src/share/vm/code/stubs.hpp
@@ -73,7 +73,7 @@ class Stub VALUE_OBJ_CLASS_SPEC {
public:
// Initialization/finalization
void initialize(int size,
- CodeComments& comments) { ShouldNotCallThis(); } // called to initialize/specify the stub's size
+ CodeStrings& strings) { ShouldNotCallThis(); } // called to initialize/specify the stub's size
void finalize() { ShouldNotCallThis(); } // called before the stub is deallocated
// General info/converters
@@ -107,7 +107,7 @@ class StubInterface: public CHeapObj<mtCode> {
public:
// Initialization/finalization
virtual void initialize(Stub* self, int size,
- CodeComments& comments) = 0; // called after creation (called twice if allocated via (request, commit))
+ CodeStrings& strings) = 0; // called after creation (called twice if allocated via (request, commit))
virtual void finalize(Stub* self) = 0; // called before deallocation
// General info/converters
@@ -136,7 +136,7 @@ class StubInterface: public CHeapObj<mtCode> {
public: \
/* Initialization/finalization */ \
virtual void initialize(Stub* self, int size, \
- CodeComments& comments) { cast(self)->initialize(size, comments); } \
+ CodeStrings& strings) { cast(self)->initialize(size, strings); } \
virtual void finalize(Stub* self) { cast(self)->finalize(); } \
\
/* General info */ \
@@ -176,7 +176,7 @@ class StubQueue: public CHeapObj<mtCode> {
// Stub functionality accessed via interface
void stub_initialize(Stub* s, int size,
- CodeComments& comments) { assert(size % CodeEntryAlignment == 0, "size not aligned"); _stub_interface->initialize(s, size, comments); }
+ CodeStrings& strings) { assert(size % CodeEntryAlignment == 0, "size not aligned"); _stub_interface->initialize(s, size, strings); }
void stub_finalize(Stub* s) { _stub_interface->finalize(s); }
int stub_size(Stub* s) const { return _stub_interface->size(s); }
bool stub_contains(Stub* s, address pc) const { return _stub_interface->code_begin(s) <= pc && pc < _stub_interface->code_end(s); }
@@ -206,7 +206,7 @@ class StubQueue: public CHeapObj<mtCode> {
Stub* request_committed(int code_size); // request a stub that provides exactly code_size space for code
Stub* request(int requested_code_size); // request a stub with a (maximum) code space - locks the queue
void commit (int committed_code_size,
- CodeComments& comments); // commit the previously requested stub - unlocks the queue
+ CodeStrings& strings); // commit the previously requested stub - unlocks the queue
// Stub deallocation
void remove_first(); // remove the first stub in the queue
diff --git a/src/share/vm/compiler/compileBroker.cpp b/src/share/vm/compiler/compileBroker.cpp
index 9214166e9..1b1e2d1cd 100644
--- a/src/share/vm/compiler/compileBroker.cpp
+++ b/src/share/vm/compiler/compileBroker.cpp
@@ -65,9 +65,8 @@ HS_DTRACE_PROBE_DECL8(hotspot, method__compile__begin,
HS_DTRACE_PROBE_DECL9(hotspot, method__compile__end,
char*, intptr_t, char*, intptr_t, char*, intptr_t, char*, intptr_t, bool);
-#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method) \
+#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method, comp_name) \
{ \
- char* comp_name = (char*)(compiler)->name(); \
Symbol* klass_name = (method)->klass_name(); \
Symbol* name = (method)->name(); \
Symbol* signature = (method)->signature(); \
@@ -78,9 +77,9 @@ HS_DTRACE_PROBE_DECL9(hotspot, method__compile__end,
signature->bytes(), signature->utf8_length()); \
}
-#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, success) \
+#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, \
+ comp_name, success) \
{ \
- char* comp_name = (char*)(compiler)->name(); \
Symbol* klass_name = (method)->klass_name(); \
Symbol* name = (method)->name(); \
Symbol* signature = (method)->signature(); \
@@ -93,22 +92,21 @@ HS_DTRACE_PROBE_DECL9(hotspot, method__compile__end,
#else /* USDT2 */
-#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method) \
+#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method, comp_name) \
{ \
- char* comp_name = (char*)(compiler)->name(); \
Symbol* klass_name = (method)->klass_name(); \
Symbol* name = (method)->name(); \
Symbol* signature = (method)->signature(); \
- HOTSPOT_METHOD_COMPILE_BEGIN( \
+ HOTSPOT_METHOD_COMPILE_BEGIN( \
comp_name, strlen(comp_name), \
- (char *) klass_name->bytes(), klass_name->utf8_length(), \
+ (char *) klass_name->bytes(), klass_name->utf8_length(), \
(char *) name->bytes(), name->utf8_length(), \
(char *) signature->bytes(), signature->utf8_length()); \
}
-#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, success) \
+#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, \
+ comp_name, success) \
{ \
- char* comp_name = (char*)(compiler)->name(); \
Symbol* klass_name = (method)->klass_name(); \
Symbol* name = (method)->name(); \
Symbol* signature = (method)->signature(); \
@@ -122,8 +120,8 @@ HS_DTRACE_PROBE_DECL9(hotspot, method__compile__end,
#else // ndef DTRACE_ENABLED
-#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method)
-#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, success)
+#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method, comp_name)
+#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, comp_name, success)
#endif // ndef DTRACE_ENABLED
@@ -359,7 +357,7 @@ void CompileTask::print() {
//
void CompileTask::print_line_on_error(outputStream* st, char* buf, int buflen) {
// print compiler name
- st->print("%s:", CompileBroker::compiler(comp_level())->name());
+ st->print("%s:", CompileBroker::compiler_name(comp_level()));
print_compilation(st);
}
@@ -368,7 +366,7 @@ void CompileTask::print_line_on_error(outputStream* st, char* buf, int buflen) {
void CompileTask::print_line() {
ttyLocker ttyl; // keep the following output all in one block
// print compiler name if requested
- if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler(comp_level())->name());
+ if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler_name(comp_level()));
print_compilation();
}
@@ -1217,8 +1215,9 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci,
// lock, make sure that the compilation
// isn't prohibited in a straightforward way.
-
- if (compiler(comp_level) == NULL || !compiler(comp_level)->can_compile_method(method) || compilation_is_prohibited(method, osr_bci, comp_level)) {
+ AbstractCompiler *comp = CompileBroker::compiler(comp_level);
+ if (comp == NULL || !comp->can_compile_method(method) ||
+ compilation_is_prohibited(method, osr_bci, comp_level)) {
return NULL;
}
@@ -1255,7 +1254,7 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci,
assert(!HAS_PENDING_EXCEPTION, "No exception should be present");
// some prerequisites that are compiler specific
- if (compiler(comp_level)->is_c2() || compiler(comp_level)->is_shark()) {
+ if (comp->is_c2() || comp->is_shark()) {
method->constants()->resolve_string_constants(CHECK_AND_CLEAR_NULL);
// Resolve all classes seen in the signature of the method
// we are compiling.
@@ -1372,8 +1371,9 @@ bool CompileBroker::compilation_is_in_queue(methodHandle method,
bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci, int comp_level) {
bool is_native = method->is_native();
// Some compilers may not support the compilation of natives.
+ AbstractCompiler *comp = compiler(comp_level);
if (is_native &&
- (!CICompileNatives || !compiler(comp_level)->supports_native())) {
+ (!CICompileNatives || comp == NULL || !comp->supports_native())) {
method->set_not_compilable_quietly(comp_level);
return true;
}
@@ -1381,7 +1381,7 @@ bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci,
bool is_osr = (osr_bci != standard_entry_bci);
// Some compilers may not support on stack replacement.
if (is_osr &&
- (!CICompileOSR || !compiler(comp_level)->supports_osr())) {
+ (!CICompileOSR || comp == NULL || !comp->supports_osr())) {
method->set_not_osr_compilable(comp_level);
return true;
}
@@ -1753,6 +1753,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
bool is_osr = (osr_bci != standard_entry_bci);
bool should_log = (thread->log() != NULL);
bool should_break = false;
+ int task_level = task->comp_level();
{
// create the handle inside it's own block so it can't
// accidentally be referenced once the thread transitions to
@@ -1766,9 +1767,10 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
assert(!method->is_native(), "no longer compile natives");
// Save information about this method in case of failure.
- set_last_compile(thread, method, is_osr, task->comp_level());
+ set_last_compile(thread, method, is_osr, task_level);
- DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler(task->comp_level()), method);
+ DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler(task_level), method,
+ compiler_name(task_level));
}
// Allocate a new set of JNI handles.
@@ -1805,7 +1807,12 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
TraceTime t1("compilation", &time);
- compiler(task->comp_level())->compile_method(&ci_env, target, osr_bci);
+ AbstractCompiler *comp = compiler(task_level);
+ if (comp == NULL) {
+ ci_env.record_method_not_compilable("no compiler", !TieredCompilation);
+ } else {
+ comp->compile_method(&ci_env, target, osr_bci);
+ }
if (!ci_env.failing() && task->code() == NULL) {
//assert(false, "compiler should always document failure");
@@ -1843,7 +1850,8 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
methodHandle method(thread, task->method());
- DTRACE_METHOD_COMPILE_END_PROBE(compiler(task->comp_level()), method, task->is_success());
+ DTRACE_METHOD_COMPILE_END_PROBE(compiler(task_level), method,
+ compiler_name(task_level), task->is_success());
collect_statistics(thread, time, task);
@@ -1868,9 +1876,9 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
break;
case ciEnv::MethodCompilable_not_at_tier:
if (is_osr)
- method->set_not_osr_compilable_quietly(task->comp_level());
+ method->set_not_osr_compilable_quietly(task_level);
else
- method->set_not_compilable_quietly(task->comp_level());
+ method->set_not_compilable_quietly(task_level);
break;
}
@@ -2128,7 +2136,14 @@ void CompileBroker::collect_statistics(CompilerThread* thread, elapsedTimer time
if (UsePerfData) counters->set_current_method("");
}
-
+const char* CompileBroker::compiler_name(int comp_level) {
+ AbstractCompiler *comp = CompileBroker::compiler(comp_level);
+ if (comp == NULL) {
+ return "no compiler";
+ } else {
+ return (comp->name());
+ }
+}
void CompileBroker::print_times() {
tty->cr();
@@ -2142,11 +2157,13 @@ void CompileBroker::print_times() {
CompileBroker::_t_standard_compilation.seconds() / CompileBroker::_total_standard_compile_count);
tty->print_cr(" On stack replacement : %6.3f s, Average : %2.3f", CompileBroker::_t_osr_compilation.seconds(), CompileBroker::_t_osr_compilation.seconds() / CompileBroker::_total_osr_compile_count);
- if (compiler(CompLevel_simple) != NULL) {
- compiler(CompLevel_simple)->print_timers();
+ AbstractCompiler *comp = compiler(CompLevel_simple);
+ if (comp != NULL) {
+ comp->print_timers();
}
- if (compiler(CompLevel_full_optimization) != NULL) {
- compiler(CompLevel_full_optimization)->print_timers();
+ comp = compiler(CompLevel_full_optimization);
+ if (comp != NULL) {
+ comp->print_timers();
}
tty->cr();
int tcb = CompileBroker::_sum_osr_bytes_compiled + CompileBroker::_sum_standard_bytes_compiled;
diff --git a/src/share/vm/compiler/compileBroker.hpp b/src/share/vm/compiler/compileBroker.hpp
index 7ba448b80..27fe52851 100644
--- a/src/share/vm/compiler/compileBroker.hpp
+++ b/src/share/vm/compiler/compileBroker.hpp
@@ -418,6 +418,9 @@ class CompileBroker: AllStatic {
static void print_last_compile();
static void print_compiler_threads_on(outputStream* st);
+
+ // compiler name for debugging
+ static const char* compiler_name(int comp_level);
};
#endif // SHARE_VM_COMPILER_COMPILEBROKER_HPP
diff --git a/src/share/vm/compiler/disassembler.cpp b/src/share/vm/compiler/disassembler.cpp
index 3efe07914..070e0321e 100644
--- a/src/share/vm/compiler/disassembler.cpp
+++ b/src/share/vm/compiler/disassembler.cpp
@@ -158,7 +158,7 @@ class decode_env {
private:
nmethod* _nm;
CodeBlob* _code;
- CodeComments _comments;
+ CodeStrings _strings;
outputStream* _output;
address _start, _end;
@@ -198,7 +198,7 @@ class decode_env {
void print_address(address value);
public:
- decode_env(CodeBlob* code, outputStream* output, CodeComments c = CodeComments());
+ decode_env(CodeBlob* code, outputStream* output, CodeStrings c = CodeStrings());
address decode_instructions(address start, address end);
@@ -242,13 +242,13 @@ class decode_env {
const char* options() { return _option_buf; }
};
-decode_env::decode_env(CodeBlob* code, outputStream* output, CodeComments c) {
+decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c) {
memset(this, 0, sizeof(*this));
_output = output ? output : tty;
_code = code;
if (code != NULL && code->is_nmethod())
_nm = (nmethod*) code;
- _comments.assign(c);
+ _strings.assign(c);
// by default, output pc but not bytes:
_print_pc = true;
@@ -370,7 +370,7 @@ void decode_env::print_insn_labels() {
if (cb != NULL) {
cb->print_block_comment(st, p);
}
- _comments.print_block_comment(st, (intptr_t)(p - _start));
+ _strings.print_block_comment(st, (intptr_t)(p - _start));
if (_print_pc) {
st->print(" " PTR_FORMAT ": ", p);
}
@@ -498,7 +498,7 @@ void Disassembler::decode(CodeBlob* cb, outputStream* st) {
env.decode_instructions(cb->code_begin(), cb->code_end());
}
-void Disassembler::decode(address start, address end, outputStream* st, CodeComments c) {
+void Disassembler::decode(address start, address end, outputStream* st, CodeStrings c) {
if (!load_library()) return;
decode_env env(CodeCache::find_blob_unsafe(start), st, c);
env.decode_instructions(start, end);
diff --git a/src/share/vm/compiler/disassembler.hpp b/src/share/vm/compiler/disassembler.hpp
index fd1f52eee..c81666ec2 100644
--- a/src/share/vm/compiler/disassembler.hpp
+++ b/src/share/vm/compiler/disassembler.hpp
@@ -100,7 +100,7 @@ class Disassembler {
}
static void decode(CodeBlob *cb, outputStream* st = NULL);
static void decode(nmethod* nm, outputStream* st = NULL);
- static void decode(address begin, address end, outputStream* st = NULL, CodeComments c = CodeComments());
+ static void decode(address begin, address end, outputStream* st = NULL, CodeStrings c = CodeStrings());
};
#endif // SHARE_VM_COMPILER_DISASSEMBLER_HPP
diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp
index 1d056338c..df6aabbb5 100644
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp
+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp
@@ -6068,6 +6068,10 @@ void CMSCollector::sweep(bool asynch) {
verify_work_stacks_empty();
verify_overflow_empty();
+ if (should_unload_classes()) {
+ ClassLoaderDataGraph::purge();
+ }
+
_intra_sweep_timer.stop();
_intra_sweep_estimate.sample(_intra_sweep_timer.seconds());
diff --git a/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/src/share/vm/gc_implementation/g1/concurrentMark.cpp
index 2a462481f..d9d70620e 100644
--- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp
+++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp
@@ -784,7 +784,7 @@ void ConcurrentMark::reset_marking_state(bool clear_overflow) {
}
}
-void ConcurrentMark::set_phase(uint active_tasks, bool concurrent) {
+void ConcurrentMark::set_concurrency(uint active_tasks) {
assert(active_tasks <= _max_worker_id, "we should not have more");
_active_tasks = active_tasks;
@@ -793,6 +793,10 @@ void ConcurrentMark::set_phase(uint active_tasks, bool concurrent) {
_terminator = ParallelTaskTerminator((int) active_tasks, _task_queues);
_first_overflow_barrier_sync.set_n_workers((int) active_tasks);
_second_overflow_barrier_sync.set_n_workers((int) active_tasks);
+}
+
+void ConcurrentMark::set_concurrency_and_phase(uint active_tasks, bool concurrent) {
+ set_concurrency(active_tasks);
_concurrent = concurrent;
// We propagate this to all tasks, not just the active ones.
@@ -806,7 +810,9 @@ void ConcurrentMark::set_phase(uint active_tasks, bool concurrent) {
// false before we start remark. At this point we should also be
// in a STW phase.
assert(!concurrent_marking_in_progress(), "invariant");
- assert(_finger == _heap_end, "only way to get here");
+ assert(_finger == _heap_end,
+ err_msg("only way to get here: _finger: "PTR_FORMAT", _heap_end: "PTR_FORMAT,
+ _finger, _heap_end));
update_g1_committed(true);
}
}
@@ -974,20 +980,28 @@ void ConcurrentMark::enter_first_sync_barrier(uint worker_id) {
gclog_or_tty->print_cr("[%u] leaving first barrier", worker_id);
}
- // let the task associated with with worker 0 do this
- if (worker_id == 0) {
- // task 0 is responsible for clearing the global data structures
- // We should be here because of an overflow. During STW we should
- // not clear the overflow flag since we rely on it being true when
- // we exit this method to abort the pause and restart concurent
- // marking.
- reset_marking_state(concurrent() /* clear_overflow */);
- force_overflow()->update();
-
- if (G1Log::fine()) {
- gclog_or_tty->date_stamp(PrintGCDateStamps);
- gclog_or_tty->stamp(PrintGCTimeStamps);
- gclog_or_tty->print_cr("[GC concurrent-mark-reset-for-overflow]");
+ // If we're executing the concurrent phase of marking, reset the marking
+ // state; otherwise the marking state is reset after reference processing,
+ // during the remark pause.
+ // If we reset here as a result of an overflow during the remark we will
+ // see assertion failures from any subsequent set_concurrency_and_phase()
+ // calls.
+ if (concurrent()) {
+ // let the task associated with with worker 0 do this
+ if (worker_id == 0) {
+ // task 0 is responsible for clearing the global data structures
+ // We should be here because of an overflow. During STW we should
+ // not clear the overflow flag since we rely on it being true when
+ // we exit this method to abort the pause and restart concurent
+ // marking.
+ reset_marking_state(true /* clear_overflow */);
+ force_overflow()->update();
+
+ if (G1Log::fine()) {
+ gclog_or_tty->date_stamp(PrintGCDateStamps);
+ gclog_or_tty->stamp(PrintGCTimeStamps);
+ gclog_or_tty->print_cr("[GC concurrent-mark-reset-for-overflow]");
+ }
}
}
@@ -1007,7 +1021,7 @@ void ConcurrentMark::enter_second_sync_barrier(uint worker_id) {
if (concurrent()) {
ConcurrentGCThread::stsJoin();
}
- // at this point everything should be re-initialised and ready to go
+ // at this point everything should be re-initialized and ready to go
if (verbose_low()) {
gclog_or_tty->print_cr("[%u] leaving second barrier", worker_id);
@@ -1065,8 +1079,8 @@ public:
double mark_step_duration_ms = G1ConcMarkStepDurationMillis;
the_task->do_marking_step(mark_step_duration_ms,
- true /* do_stealing */,
- true /* do_termination */);
+ true /* do_termination */,
+ false /* is_serial*/);
double end_time_sec = os::elapsedTime();
double end_vtime_sec = os::elapsedVTime();
@@ -1222,8 +1236,8 @@ void ConcurrentMark::markFromRoots() {
uint active_workers = MAX2(1U, parallel_marking_threads());
- // Parallel task terminator is set in "set_phase()"
- set_phase(active_workers, true /* concurrent */);
+ // Parallel task terminator is set in "set_concurrency_and_phase()"
+ set_concurrency_and_phase(active_workers, true /* concurrent */);
CMConcurrentMarkingTask markingTask(this, cmThread());
if (use_parallel_marking_threads()) {
@@ -1275,12 +1289,22 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) {
if (has_overflown()) {
// Oops. We overflowed. Restart concurrent marking.
_restart_for_overflow = true;
- // Clear the marking state because we will be restarting
- // marking due to overflowing the global mark stack.
- reset_marking_state();
if (G1TraceMarkStackOverflow) {
gclog_or_tty->print_cr("\nRemark led to restart for overflow.");
}
+
+ // Verify the heap w.r.t. the previous marking bitmap.
+ if (VerifyDuringGC) {
+ HandleMark hm; // handle scope
+ gclog_or_tty->print(" VerifyDuringGC:(overflow)");
+ Universe::heap()->prepare_for_verify();
+ Universe::verify(/* silent */ false,
+ /* option */ VerifyOption_G1UsePrevMarking);
+ }
+
+ // Clear the marking state because we will be restarting
+ // marking due to overflowing the global mark stack.
+ reset_marking_state();
} else {
// Aggregate the per-task counting data that we have accumulated
// while marking.
@@ -2184,14 +2208,17 @@ bool G1CMIsAliveClosure::do_object_b(oop obj) {
// operating on the global stack.
class G1CMKeepAliveAndDrainClosure: public OopClosure {
- ConcurrentMark* _cm;
- CMTask* _task;
- int _ref_counter_limit;
- int _ref_counter;
+ ConcurrentMark* _cm;
+ CMTask* _task;
+ int _ref_counter_limit;
+ int _ref_counter;
+ bool _is_serial;
public:
- G1CMKeepAliveAndDrainClosure(ConcurrentMark* cm, CMTask* task) :
- _cm(cm), _task(task), _ref_counter_limit(G1RefProcDrainInterval) {
+ G1CMKeepAliveAndDrainClosure(ConcurrentMark* cm, CMTask* task, bool is_serial) :
+ _cm(cm), _task(task), _is_serial(is_serial),
+ _ref_counter_limit(G1RefProcDrainInterval) {
assert(_ref_counter_limit > 0, "sanity");
+ assert(!_is_serial || _task->worker_id() == 0, "only task 0 for serial code");
_ref_counter = _ref_counter_limit;
}
@@ -2230,8 +2257,8 @@ class G1CMKeepAliveAndDrainClosure: public OopClosure {
do {
double mark_step_duration_ms = G1ConcMarkStepDurationMillis;
_task->do_marking_step(mark_step_duration_ms,
- false /* do_stealing */,
- false /* do_termination */);
+ false /* do_termination */,
+ _is_serial);
} while (_task->has_aborted() && !_cm->has_overflown());
_ref_counter = _ref_counter_limit;
}
@@ -2253,27 +2280,18 @@ class G1CMKeepAliveAndDrainClosure: public OopClosure {
class G1CMDrainMarkingStackClosure: public VoidClosure {
ConcurrentMark* _cm;
CMTask* _task;
- bool _do_stealing;
- bool _do_termination;
+ bool _is_serial;
public:
- G1CMDrainMarkingStackClosure(ConcurrentMark* cm, CMTask* task, bool is_par) :
- _cm(cm), _task(task) {
- assert(is_par || _task->worker_id() == 0,
- "Only task for worker 0 should be used if ref processing is single threaded");
- // We only allow stealing and only enter the termination protocol
- // in CMTask::do_marking_step() if this closure is being instantiated
- // for parallel reference processing.
- _do_stealing = _do_termination = is_par;
+ G1CMDrainMarkingStackClosure(ConcurrentMark* cm, CMTask* task, bool is_serial) :
+ _cm(cm), _task(task), _is_serial(is_serial) {
+ assert(!_is_serial || _task->worker_id() == 0, "only task 0 for serial code");
}
void do_void() {
do {
if (_cm->verbose_high()) {
- gclog_or_tty->print_cr("\t[%u] Drain: Calling do_marking_step - "
- "stealing: %s, termination: %s",
- _task->worker_id(),
- BOOL_TO_STR(_do_stealing),
- BOOL_TO_STR(_do_termination));
+ gclog_or_tty->print_cr("\t[%u] Drain: Calling do_marking_step - serial: %s",
+ _task->worker_id(), BOOL_TO_STR(_is_serial));
}
// We call CMTask::do_marking_step() to completely drain the local
@@ -2294,8 +2312,8 @@ class G1CMDrainMarkingStackClosure: public VoidClosure {
// has_aborted() flag that the marking step has completed.
_task->do_marking_step(1000000000.0 /* something very large */,
- _do_stealing,
- _do_termination);
+ true /* do_termination */,
+ _is_serial);
} while (_task->has_aborted() && !_cm->has_overflown());
}
};
@@ -2328,7 +2346,6 @@ class G1CMRefProcTaskProxy: public AbstractGangTask {
ProcessTask& _proc_task;
G1CollectedHeap* _g1h;
ConcurrentMark* _cm;
- bool _processing_is_mt;
public:
G1CMRefProcTaskProxy(ProcessTask& proc_task,
@@ -2336,15 +2353,15 @@ public:
ConcurrentMark* cm) :
AbstractGangTask("Process reference objects in parallel"),
_proc_task(proc_task), _g1h(g1h), _cm(cm) {
- ReferenceProcessor* rp = _g1h->ref_processor_cm();
- _processing_is_mt = rp->processing_is_mt();
- }
+ ReferenceProcessor* rp = _g1h->ref_processor_cm();
+ assert(rp->processing_is_mt(), "shouldn't be here otherwise");
+ }
virtual void work(uint worker_id) {
- CMTask* marking_task = _cm->task(worker_id);
+ CMTask* task = _cm->task(worker_id);
G1CMIsAliveClosure g1_is_alive(_g1h);
- G1CMKeepAliveAndDrainClosure g1_par_keep_alive(_cm, marking_task);
- G1CMDrainMarkingStackClosure g1_par_drain(_cm, marking_task, _processing_is_mt);
+ G1CMKeepAliveAndDrainClosure g1_par_keep_alive(_cm, task, false /* is_serial */);
+ G1CMDrainMarkingStackClosure g1_par_drain(_cm, task, false /* is_serial */);
_proc_task.work(worker_id, g1_is_alive, g1_par_keep_alive, g1_par_drain);
}
@@ -2356,9 +2373,11 @@ void G1CMRefProcTaskExecutor::execute(ProcessTask& proc_task) {
G1CMRefProcTaskProxy proc_task_proxy(proc_task, _g1h, _cm);
- // We need to reset the phase for each task execution so that
- // the termination protocol of CMTask::do_marking_step works.
- _cm->set_phase(_active_workers, false /* concurrent */);
+ // We need to reset the concurrency level before each
+ // proxy task execution, so that the termination protocol
+ // and overflow handling in CMTask::do_marking_step() knows
+ // how many workers to wait for.
+ _cm->set_concurrency(_active_workers);
_g1h->set_par_threads(_active_workers);
_workers->run_task(&proc_task_proxy);
_g1h->set_par_threads(0);
@@ -2384,12 +2403,29 @@ void G1CMRefProcTaskExecutor::execute(EnqueueTask& enq_task) {
G1CMRefEnqueueTaskProxy enq_task_proxy(enq_task);
+ // Not strictly necessary but...
+ //
+ // We need to reset the concurrency level before each
+ // proxy task execution, so that the termination protocol
+ // and overflow handling in CMTask::do_marking_step() knows
+ // how many workers to wait for.
+ _cm->set_concurrency(_active_workers);
_g1h->set_par_threads(_active_workers);
_workers->run_task(&enq_task_proxy);
_g1h->set_par_threads(0);
}
void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
+ if (has_overflown()) {
+ // Skip processing the discovered references if we have
+ // overflown the global marking stack. Reference objects
+ // only get discovered once so it is OK to not
+ // de-populate the discovered reference lists. We could have,
+ // but the only benefit would be that, when marking restarts,
+ // less reference objects are discovered.
+ return;
+ }
+
ResourceMark rm;
HandleMark hm;
@@ -2415,26 +2451,39 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
rp->setup_policy(clear_all_soft_refs);
assert(_markStack.isEmpty(), "mark stack should be empty");
- // Non-MT instances 'Keep Alive' and 'Complete GC' oop closures.
- G1CMKeepAliveAndDrainClosure g1_keep_alive(this, task(0));
- G1CMDrainMarkingStackClosure g1_drain_mark_stack(this, task(0), false);
-
- // We need at least one active thread. If reference processing is
- // not multi-threaded we use the current (ConcurrentMarkThread) thread,
- // otherwise we use the work gang from the G1CollectedHeap and we
- // utilize all the worker threads we can.
- uint active_workers = (rp->processing_is_mt() && g1h->workers() != NULL
- ? g1h->workers()->active_workers()
- : 1U);
-
+ // Instances of the 'Keep Alive' and 'Complete GC' closures used
+ // in serial reference processing. Note these closures are also
+ // used for serially processing (by the the current thread) the
+ // JNI references during parallel reference processing.
+ //
+ // These closures do not need to synchronize with the worker
+ // threads involved in parallel reference processing as these
+ // instances are executed serially by the current thread (e.g.
+ // reference processing is not multi-threaded and is thus
+ // performed by the current thread instead of a gang worker).
+ //
+ // The gang tasks involved in parallel reference procssing create
+ // their own instances of these closures, which do their own
+ // synchronization among themselves.
+ G1CMKeepAliveAndDrainClosure g1_keep_alive(this, task(0), true /* is_serial */);
+ G1CMDrainMarkingStackClosure g1_drain_mark_stack(this, task(0), true /* is_serial */);
+
+ // We need at least one active thread. If reference processing
+ // is not multi-threaded we use the current (VMThread) thread,
+ // otherwise we use the work gang from the G1CollectedHeap and
+ // we utilize all the worker threads we can.
+ bool processing_is_mt = rp->processing_is_mt() && g1h->workers() != NULL;
+ uint active_workers = (processing_is_mt ? g1h->workers()->active_workers() : 1U);
active_workers = MAX2(MIN2(active_workers, _max_worker_id), 1U);
+ // Parallel processing task executor.
G1CMRefProcTaskExecutor par_task_executor(g1h, this,
g1h->workers(), active_workers);
+ AbstractRefProcTaskExecutor* executor = (processing_is_mt ? &par_task_executor : NULL);
- AbstractRefProcTaskExecutor* executor = (rp->processing_is_mt()
- ? &par_task_executor
- : NULL);
+ // Set the concurrency level. The phase was already set prior to
+ // executing the remark task.
+ set_concurrency(active_workers);
// Set the degree of MT processing here. If the discovery was done MT,
// the number of threads involved during discovery could differ from
@@ -2454,6 +2503,7 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
assert(_markStack.overflow() || _markStack.isEmpty(),
"mark stack should be empty (unless it overflowed)");
+
if (_markStack.overflow()) {
// This should have been done already when we tried to push an
// entry on to the global mark stack. But let's do it again.
@@ -2482,8 +2532,8 @@ void ConcurrentMark::swapMarkBitMaps() {
class CMRemarkTask: public AbstractGangTask {
private:
- ConcurrentMark *_cm;
-
+ ConcurrentMark* _cm;
+ bool _is_serial;
public:
void work(uint worker_id) {
// Since all available tasks are actually started, we should
@@ -2493,8 +2543,8 @@ public:
task->record_start_time();
do {
task->do_marking_step(1000000000.0 /* something very large */,
- true /* do_stealing */,
- true /* do_termination */);
+ true /* do_termination */,
+ _is_serial);
} while (task->has_aborted() && !_cm->has_overflown());
// If we overflow, then we do not want to restart. We instead
// want to abort remark and do concurrent marking again.
@@ -2502,8 +2552,8 @@ public:
}
}
- CMRemarkTask(ConcurrentMark* cm, int active_workers) :
- AbstractGangTask("Par Remark"), _cm(cm) {
+ CMRemarkTask(ConcurrentMark* cm, int active_workers, bool is_serial) :
+ AbstractGangTask("Par Remark"), _cm(cm), _is_serial(is_serial) {
_cm->terminator()->reset_for_reuse(active_workers);
}
};
@@ -2524,30 +2574,40 @@ void ConcurrentMark::checkpointRootsFinalWork() {
active_workers = (uint) ParallelGCThreads;
g1h->workers()->set_active_workers(active_workers);
}
- set_phase(active_workers, false /* concurrent */);
+ set_concurrency_and_phase(active_workers, false /* concurrent */);
// Leave _parallel_marking_threads at it's
// value originally calculated in the ConcurrentMark
// constructor and pass values of the active workers
// through the gang in the task.
- CMRemarkTask remarkTask(this, active_workers);
+ CMRemarkTask remarkTask(this, active_workers, false /* is_serial */);
+ // We will start all available threads, even if we decide that the
+ // active_workers will be fewer. The extra ones will just bail out
+ // immediately.
g1h->set_par_threads(active_workers);
g1h->workers()->run_task(&remarkTask);
g1h->set_par_threads(0);
} else {
G1CollectedHeap::StrongRootsScope srs(g1h);
- // this is remark, so we'll use up all available threads
uint active_workers = 1;
- set_phase(active_workers, false /* concurrent */);
-
- CMRemarkTask remarkTask(this, active_workers);
- // We will start all available threads, even if we decide that the
- // active_workers will be fewer. The extra ones will just bail out
- // immediately.
+ set_concurrency_and_phase(active_workers, false /* concurrent */);
+
+ // Note - if there's no work gang then the VMThread will be
+ // the thread to execute the remark - serially. We have
+ // to pass true for the is_serial parameter so that
+ // CMTask::do_marking_step() doesn't enter the sync
+ // barriers in the event of an overflow. Doing so will
+ // cause an assert that the current thread is not a
+ // concurrent GC thread.
+ CMRemarkTask remarkTask(this, active_workers, true /* is_serial*/);
remarkTask.work(0);
}
SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
- guarantee(satb_mq_set.completed_buffers_num() == 0, "invariant");
+ guarantee(has_overflown() ||
+ satb_mq_set.completed_buffers_num() == 0,
+ err_msg("Invariant: has_overflown = %s, num buffers = %d",
+ BOOL_TO_STR(has_overflown()),
+ satb_mq_set.completed_buffers_num()));
print_stats();
}
@@ -3854,8 +3914,8 @@ void CMTask::print_stats() {
/*****************************************************************************
- The do_marking_step(time_target_ms) method is the building block
- of the parallel marking framework. It can be called in parallel
+ The do_marking_step(time_target_ms, ...) method is the building
+ block of the parallel marking framework. It can be called in parallel
with other invocations of do_marking_step() on different tasks
(but only one per task, obviously) and concurrently with the
mutator threads, or during remark, hence it eliminates the need
@@ -3865,7 +3925,7 @@ void CMTask::print_stats() {
pauses too, since do_marking_step() ensures that it aborts before
it needs to yield.
- The data structures that is uses to do marking work are the
+ The data structures that it uses to do marking work are the
following:
(1) Marking Bitmap. If there are gray objects that appear only
@@ -3914,7 +3974,7 @@ void CMTask::print_stats() {
(2) When a global overflow (on the global stack) has been
triggered. Before the task aborts, it will actually sync up with
the other tasks to ensure that all the marking data structures
- (local queues, stacks, fingers etc.) are re-initialised so that
+ (local queues, stacks, fingers etc.) are re-initialized so that
when do_marking_step() completes, the marking phase can
immediately restart.
@@ -3951,11 +4011,25 @@ void CMTask::print_stats() {
place, it was natural to piggy-back all the other conditions on it
too and not constantly check them throughout the code.
+ If do_termination is true then do_marking_step will enter its
+ termination protocol.
+
+ The value of is_serial must be true when do_marking_step is being
+ called serially (i.e. by the VMThread) and do_marking_step should
+ skip any synchronization in the termination and overflow code.
+ Examples include the serial remark code and the serial reference
+ processing closures.
+
+ The value of is_serial must be false when do_marking_step is
+ being called by any of the worker threads in a work gang.
+ Examples include the concurrent marking code (CMMarkingTask),
+ the MT remark code, and the MT reference processing closures.
+
*****************************************************************************/
void CMTask::do_marking_step(double time_target_ms,
- bool do_stealing,
- bool do_termination) {
+ bool do_termination,
+ bool is_serial) {
assert(time_target_ms >= 1.0, "minimum granularity is 1ms");
assert(concurrent() == _cm->concurrent(), "they should be the same");
@@ -3976,6 +4050,12 @@ void CMTask::do_marking_step(double time_target_ms,
_start_time_ms = os::elapsedVTime() * 1000.0;
statsOnly( _interval_start_time_ms = _start_time_ms );
+ // If do_stealing is true then do_marking_step will attempt to
+ // steal work from the other CMTasks. It only makes sense to
+ // enable stealing when the termination protocol is enabled
+ // and do_marking_step() is not being called serially.
+ bool do_stealing = do_termination && !is_serial;
+
double diff_prediction_ms =
g1_policy->get_new_prediction(&_marking_step_diffs_ms);
_time_target_ms = time_target_ms - diff_prediction_ms;
@@ -4237,10 +4317,12 @@ void CMTask::do_marking_step(double time_target_ms,
}
_termination_start_time_ms = os::elapsedVTime() * 1000.0;
+
// The CMTask class also extends the TerminatorTerminator class,
// hence its should_exit_termination() method will also decide
// whether to exit the termination protocol or not.
- bool finished = _cm->terminator()->offer_termination(this);
+ bool finished = (is_serial ||
+ _cm->terminator()->offer_termination(this));
double termination_end_time_ms = os::elapsedVTime() * 1000.0;
_termination_time_ms +=
termination_end_time_ms - _termination_start_time_ms;
@@ -4320,20 +4402,28 @@ void CMTask::do_marking_step(double time_target_ms,
gclog_or_tty->print_cr("[%u] detected overflow", _worker_id);
}
- _cm->enter_first_sync_barrier(_worker_id);
- // When we exit this sync barrier we know that all tasks have
- // stopped doing marking work. So, it's now safe to
- // re-initialise our data structures. At the end of this method,
- // task 0 will clear the global data structures.
+ if (!is_serial) {
+ // We only need to enter the sync barrier if being called
+ // from a parallel context
+ _cm->enter_first_sync_barrier(_worker_id);
+
+ // When we exit this sync barrier we know that all tasks have
+ // stopped doing marking work. So, it's now safe to
+ // re-initialise our data structures. At the end of this method,
+ // task 0 will clear the global data structures.
+ }
statsOnly( ++_aborted_overflow );
// We clear the local state of this task...
clear_region_fields();
- // ...and enter the second barrier.
- _cm->enter_second_sync_barrier(_worker_id);
- // At this point everything has bee re-initialised and we're
+ if (!is_serial) {
+ // ...and enter the second barrier.
+ _cm->enter_second_sync_barrier(_worker_id);
+ }
+ // At this point, if we're during the concurrent phase of
+ // marking, everything has been re-initialized and we're
// ready to restart.
}
diff --git a/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/src/share/vm/gc_implementation/g1/concurrentMark.hpp
index 61e64df8b..43554a5c9 100644
--- a/src/share/vm/gc_implementation/g1/concurrentMark.hpp
+++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp
@@ -166,7 +166,7 @@ class CMBitMap : public CMBitMapRO {
class CMMarkStack VALUE_OBJ_CLASS_SPEC {
VirtualSpace _virtual_space; // Underlying backing store for actual stack
ConcurrentMark* _cm;
- oop* _base; // bottom of stack
+ oop* _base; // bottom of stack
jint _index; // one more than last occupied index
jint _capacity; // max #elements
jint _saved_index; // value of _index saved at start of GC
@@ -491,9 +491,12 @@ protected:
// structures are initialised to a sensible and predictable state.
void set_non_marking_state();
+ // Called to indicate how many threads are currently active.
+ void set_concurrency(uint active_tasks);
+
// It should be called to indicate which phase we're in (concurrent
// mark or remark) and how many threads are currently active.
- void set_phase(uint active_tasks, bool concurrent);
+ void set_concurrency_and_phase(uint active_tasks, bool concurrent);
// prints all gathered CM-related statistics
void print_stats();
@@ -1146,7 +1149,9 @@ public:
// trying not to exceed the given duration. However, it might exit
// prematurely, according to some conditions (i.e. SATB buffers are
// available for processing).
- void do_marking_step(double target_ms, bool do_stealing, bool do_termination);
+ void do_marking_step(double target_ms,
+ bool do_termination,
+ bool is_serial);
// These two calls start and stop the timer
void record_start_time() {
diff --git a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp
index 21e08b6f8..0c39e69e1 100644
--- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp
+++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp
@@ -656,7 +656,7 @@ void ParallelScavengeHeap::print_tracing_info() const {
tty->print_cr("[Accumulated GC generation 0 time %3.7f secs]", time);
}
if (TraceGen1Time) {
- double time = PSMarkSweep::accumulated_time()->seconds();
+ double time = UseParallelOldGC ? PSParallelCompact::accumulated_time()->seconds() : PSMarkSweep::accumulated_time()->seconds();
tty->print_cr("[Accumulated GC generation 1 time %3.7f secs]", time);
}
}
diff --git a/src/share/vm/interpreter/interpreter.cpp b/src/share/vm/interpreter/interpreter.cpp
index 24de109f3..06554172b 100644
--- a/src/share/vm/interpreter/interpreter.cpp
+++ b/src/share/vm/interpreter/interpreter.cpp
@@ -76,7 +76,7 @@ void InterpreterCodelet::print_on(outputStream* st) const {
if (PrintInterpreter) {
st->cr();
- Disassembler::decode(code_begin(), code_end(), st, DEBUG_ONLY(_comments) NOT_DEBUG(CodeComments()));
+ Disassembler::decode(code_begin(), code_end(), st, DEBUG_ONLY(_strings) NOT_DEBUG(CodeStrings()));
}
}
diff --git a/src/share/vm/interpreter/interpreter.hpp b/src/share/vm/interpreter/interpreter.hpp
index 346af856a..1fb4ac5c8 100644
--- a/src/share/vm/interpreter/interpreter.hpp
+++ b/src/share/vm/interpreter/interpreter.hpp
@@ -48,12 +48,12 @@ class InterpreterCodelet: public Stub {
int _size; // the size in bytes
const char* _description; // a description of the codelet, for debugging & printing
Bytecodes::Code _bytecode; // associated bytecode if any
- DEBUG_ONLY(CodeComments _comments;) // Comments for annotating assembler output.
+ DEBUG_ONLY(CodeStrings _strings;) // Comments for annotating assembler output.
public:
// Initialization/finalization
void initialize(int size,
- CodeComments& comments) { _size = size; DEBUG_ONLY(_comments.assign(comments);) }
+ CodeStrings& strings) { _size = size; DEBUG_ONLY(_strings.assign(strings);) }
void finalize() { ShouldNotCallThis(); }
// General info/converters
@@ -131,7 +131,7 @@ class CodeletMark: ResourceMark {
// commit Codelet
- AbstractInterpreter::code()->commit((*_masm)->code()->pure_insts_size(), (*_masm)->code()->comments());
+ AbstractInterpreter::code()->commit((*_masm)->code()->pure_insts_size(), (*_masm)->code()->strings());
// make sure nobody can use _masm outside a CodeletMark lifespan
*_masm = NULL;
}
diff --git a/src/share/vm/memory/genCollectedHeap.cpp b/src/share/vm/memory/genCollectedHeap.cpp
index 9d65cc157..6b7402c82 100644
--- a/src/share/vm/memory/genCollectedHeap.cpp
+++ b/src/share/vm/memory/genCollectedHeap.cpp
@@ -554,6 +554,8 @@ void GenCollectedHeap::do_collection(bool full,
}
if (complete) {
+ // Delete metaspaces for unloaded class loaders and clean up loader_data graph
+ ClassLoaderDataGraph::purge();
// Resize the metaspace capacity after full collections
MetaspaceGC::compute_new_size();
update_full_collections_completed();
@@ -564,11 +566,6 @@ void GenCollectedHeap::do_collection(bool full,
gc_epilogue(complete);
- // Delete metaspaces for unloaded class loaders and clean up loader_data graph
- if (complete) {
- ClassLoaderDataGraph::purge();
- }
-
if (must_restore_marks_for_biased_locking) {
BiasedLocking::restore_marks();
}
diff --git a/src/share/vm/memory/metaspace.cpp b/src/share/vm/memory/metaspace.cpp
index af8e8a321..f5b37bbe7 100644
--- a/src/share/vm/memory/metaspace.cpp
+++ b/src/share/vm/memory/metaspace.cpp
@@ -334,6 +334,9 @@ class VirtualSpaceNode : public CHeapObj<mtClass> {
// byte_size is the size of the associated virtualspace.
VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(0) {
+ // align up to vm allocation granularity
+ byte_size = align_size_up(byte_size, os::vm_allocation_granularity());
+
// This allocates memory with mmap. For DumpSharedspaces, allocate the
// space at low memory so that other shared images don't conflict.
// This is the same address as memory needed for UseCompressedOops but
@@ -1100,25 +1103,24 @@ size_t MetaspaceGC::delta_capacity_until_GC(size_t word_size) {
}
bool MetaspaceGC::should_expand(VirtualSpaceList* vsl, size_t word_size) {
-
- // Class virtual space should always be expanded. Call GC for the other
- // metadata virtual space.
- if (vsl == Metaspace::class_space_list()) return true;
-
// If the user wants a limit, impose one.
- size_t max_metaspace_size_words = MaxMetaspaceSize / BytesPerWord;
- size_t metaspace_size_words = MetaspaceSize / BytesPerWord;
if (!FLAG_IS_DEFAULT(MaxMetaspaceSize) &&
- vsl->capacity_words_sum() >= max_metaspace_size_words) {
+ MetaspaceAux::reserved_in_bytes() >= MaxMetaspaceSize) {
return false;
}
+ // Class virtual space should always be expanded. Call GC for the other
+ // metadata virtual space.
+ if (vsl == Metaspace::class_space_list()) return true;
+
// If this is part of an allocation after a GC, expand
// unconditionally.
if(MetaspaceGC::expand_after_GC()) {
return true;
}
+ size_t metaspace_size_words = MetaspaceSize / BytesPerWord;
+
// If the capacity is below the minimum capacity, allow the
// expansion. Also set the high-water-mark (capacity_until_GC)
// to that minimum capacity so that a GC will not be induced
@@ -1308,8 +1310,7 @@ void MetaspaceGC::compute_new_size() {
gclog_or_tty->print_cr(" metaspace HWM: %.1fK", new_capacity_until_GC / (double) K);
}
}
- assert(vsl->used_bytes_sum() == used_after_gc &&
- used_after_gc <= vsl->capacity_bytes_sum(),
+ assert(used_after_gc <= vsl->capacity_bytes_sum(),
"sanity check");
}
@@ -1969,6 +1970,9 @@ void SpaceManager::initialize() {
}
SpaceManager::~SpaceManager() {
+ // This call this->_lock which can't be done while holding expand_lock()
+ const size_t in_use_before = sum_capacity_in_chunks_in_use();
+
MutexLockerEx fcl(SpaceManager::expand_lock(),
Mutex::_no_safepoint_check_flag);
@@ -1986,7 +1990,7 @@ SpaceManager::~SpaceManager() {
// Have to update before the chunks_in_use lists are emptied
// below.
- chunk_manager->inc_free_chunks_total(sum_capacity_in_chunks_in_use(),
+ chunk_manager->inc_free_chunks_total(in_use_before,
sum_count_in_chunks_in_use());
// Add all the chunks in use by this space manager
diff --git a/src/share/vm/memory/sharedHeap.cpp b/src/share/vm/memory/sharedHeap.cpp
index be641d304..caef7ac7a 100644
--- a/src/share/vm/memory/sharedHeap.cpp
+++ b/src/share/vm/memory/sharedHeap.cpp
@@ -178,7 +178,7 @@ void SharedHeap::process_strong_roots(bool activate_scope,
SystemDictionary::always_strong_oops_do(roots);
ClassLoaderDataGraph::always_strong_oops_do(roots, klass_closure, !is_scavenging);
} else {
- ShouldNotReachHere2("We should always have selected either SO_AllClasses or SO_SystemClasses");
+ fatal("We should always have selected either SO_AllClasses or SO_SystemClasses");
}
}
diff --git a/src/share/vm/oops/constantPool.cpp b/src/share/vm/oops/constantPool.cpp
index c025730bb..ba7ec439e 100644
--- a/src/share/vm/oops/constantPool.cpp
+++ b/src/share/vm/oops/constantPool.cpp
@@ -1852,6 +1852,7 @@ void ConstantPool::print_entry_on(const int index, outputStream* st) {
switch (tag_at(index).value()) {
case JVM_CONSTANT_Class :
{ Klass* k = klass_at(index, CATCH);
+ guarantee(k != NULL, "need klass");
k->print_value_on(st);
st->print(" {0x%lx}", (address)k);
}
diff --git a/src/share/vm/oops/fieldInfo.hpp b/src/share/vm/oops/fieldInfo.hpp
index 331dc05f3..5da8ed962 100644
--- a/src/share/vm/oops/fieldInfo.hpp
+++ b/src/share/vm/oops/fieldInfo.hpp
@@ -108,11 +108,11 @@ class FieldInfo VALUE_OBJ_CLASS_SPEC {
return build_int_from_shorts(_shorts[low_packed_offset], _shorts[high_packed_offset]) >> FIELDINFO_TAG_SIZE;
#ifndef PRODUCT
case FIELDINFO_TAG_TYPE_PLAIN:
- ShouldNotReachHere2("Asking offset for the plain type field");
+ fatal("Asking offset for the plain type field");
case FIELDINFO_TAG_TYPE_CONTENDED:
- ShouldNotReachHere2("Asking offset for the contended type field");
+ fatal("Asking offset for the contended type field");
case FIELDINFO_TAG_BLANK:
- ShouldNotReachHere2("Asking offset for the blank field");
+ fatal("Asking offset for the blank field");
#endif
}
ShouldNotReachHere();
@@ -128,9 +128,9 @@ class FieldInfo VALUE_OBJ_CLASS_SPEC {
return true;
#ifndef PRODUCT
case FIELDINFO_TAG_OFFSET:
- ShouldNotReachHere2("Asking contended flag for the field with offset");
+ fatal("Asking contended flag for the field with offset");
case FIELDINFO_TAG_BLANK:
- ShouldNotReachHere2("Asking contended flag for the blank field");
+ fatal("Asking contended flag for the blank field");
#endif
}
ShouldNotReachHere();
@@ -146,9 +146,9 @@ class FieldInfo VALUE_OBJ_CLASS_SPEC {
return _shorts[high_packed_offset];
#ifndef PRODUCT
case FIELDINFO_TAG_OFFSET:
- ShouldNotReachHere2("Asking the contended group for the field with offset");
+ fatal("Asking the contended group for the field with offset");
case FIELDINFO_TAG_BLANK:
- ShouldNotReachHere2("Asking the contended group for the blank field");
+ fatal("Asking the contended group for the blank field");
#endif
}
ShouldNotReachHere();
@@ -163,9 +163,9 @@ class FieldInfo VALUE_OBJ_CLASS_SPEC {
return (lo >> FIELDINFO_TAG_SIZE);
#ifndef PRODUCT
case FIELDINFO_TAG_OFFSET:
- ShouldNotReachHere2("Asking the field type for field with offset");
+ fatal("Asking the field type for field with offset");
case FIELDINFO_TAG_BLANK:
- ShouldNotReachHere2("Asking the field type for the blank field");
+ fatal("Asking the field type for the blank field");
#endif
}
ShouldNotReachHere();
@@ -211,7 +211,7 @@ class FieldInfo VALUE_OBJ_CLASS_SPEC {
case FIELDINFO_TAG_TYPE_PLAIN:
case FIELDINFO_TAG_TYPE_CONTENDED:
case FIELDINFO_TAG_OFFSET:
- ShouldNotReachHere2("Setting the field type with overwriting");
+ fatal("Setting the field type with overwriting");
#endif
}
ShouldNotReachHere();
@@ -226,11 +226,11 @@ class FieldInfo VALUE_OBJ_CLASS_SPEC {
return;
#ifndef PRODUCT
case FIELDINFO_TAG_TYPE_CONTENDED:
- ShouldNotReachHere2("Overwriting contended group");
+ fatal("Overwriting contended group");
case FIELDINFO_TAG_BLANK:
- ShouldNotReachHere2("Setting contended group for the blank field");
+ fatal("Setting contended group for the blank field");
case FIELDINFO_TAG_OFFSET:
- ShouldNotReachHere2("Setting contended group for field with offset");
+ fatal("Setting contended group for field with offset");
#endif
}
ShouldNotReachHere();
diff --git a/src/share/vm/oops/generateOopMap.cpp b/src/share/vm/oops/generateOopMap.cpp
index 96572a64e..8c12b7ac7 100644
--- a/src/share/vm/oops/generateOopMap.cpp
+++ b/src/share/vm/oops/generateOopMap.cpp
@@ -762,6 +762,7 @@ void GenerateOopMap::copy_state(CellTypeState *dst, CellTypeState *src) {
// monitor matching is purely informational and doesn't say anything
// about the correctness of the code.
void GenerateOopMap::merge_state_into_bb(BasicBlock *bb) {
+ guarantee(bb != NULL, "null basicblock");
assert(bb->is_alive(), "merging state into a dead basicblock");
if (_stack_top == bb->_stack_top) {
@@ -1189,6 +1190,7 @@ void GenerateOopMap::do_exception_edge(BytecodeStream* itr) {
if (start_pc <= bci && bci < end_pc) {
BasicBlock *excBB = get_basic_block_at(handler_pc);
+ guarantee(excBB != NULL, "no basic block for exception");
CellTypeState *excStk = excBB->stack();
CellTypeState *cOpStck = stack();
CellTypeState cOpStck_0 = cOpStck[0];
@@ -1803,6 +1805,7 @@ void GenerateOopMap::do_monitorexit(int bci) {
// possibility that this bytecode will throw an
// exception.
BasicBlock* bb = get_basic_block_containing(bci);
+ guarantee(bb != NULL, "no basic block for bci");
bb->set_changed(true);
bb->_monitor_top = bad_monitors;
@@ -2190,6 +2193,7 @@ void GenerateOopMap::result_for_basicblock(int bci) {
// Find basicblock and report results
BasicBlock* bb = get_basic_block_containing(bci);
+ guarantee(bb != NULL, "no basic block for bci");
assert(bb->is_reachable(), "getting result from unreachable basicblock");
bb->set_changed(true);
interp_bb(bb);
diff --git a/src/share/vm/oops/klass.cpp b/src/share/vm/oops/klass.cpp
index edfda97a5..06c644c34 100644
--- a/src/share/vm/oops/klass.cpp
+++ b/src/share/vm/oops/klass.cpp
@@ -486,6 +486,12 @@ void Klass::oops_do(OopClosure* cl) {
}
void Klass::remove_unshareable_info() {
+ if (!DumpSharedSpaces) {
+ // Clean up after OOM during class loading
+ if (class_loader_data() != NULL) {
+ class_loader_data()->remove_class(this);
+ }
+ }
set_subklass(NULL);
set_next_sibling(NULL);
// Clear the java mirror
diff --git a/src/share/vm/oops/method.cpp b/src/share/vm/oops/method.cpp
index 0ee78f176..11ddd21f1 100644
--- a/src/share/vm/oops/method.cpp
+++ b/src/share/vm/oops/method.cpp
@@ -798,7 +798,15 @@ void Method::unlink_method() {
backedge_counter()->reset();
_adapter = NULL;
_from_compiled_entry = NULL;
- assert(_method_data == NULL, "unexpected method data?");
+
+ // In case of DumpSharedSpaces, _method_data should always be NULL.
+ //
+ // During runtime (!DumpSharedSpaces), when we are cleaning a
+ // shared class that failed to load, this->link_method() may
+ // have already been called (before an exception happened), so
+ // this->_method_data may not be NULL.
+ assert(!DumpSharedSpaces || _method_data == NULL, "unexpected method data?");
+
set_method_data(NULL);
set_interpreter_throwout_count(0);
set_interpreter_invocation_count(0);
diff --git a/src/share/vm/opto/bytecodeInfo.cpp b/src/share/vm/opto/bytecodeInfo.cpp
index 155bc47e9..6d8f1b3da 100644
--- a/src/share/vm/opto/bytecodeInfo.cpp
+++ b/src/share/vm/opto/bytecodeInfo.cpp
@@ -157,9 +157,10 @@ bool InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_method,
} else {
// Not hot. Check for medium-sized pre-existing nmethod at cold sites.
if (callee_method->has_compiled_code() &&
- callee_method->instructions_size() > inline_small_code_size)
+ callee_method->instructions_size() > inline_small_code_size) {
set_msg("already compiled into a medium method");
return false;
+ }
}
if (size > max_inline_size) {
if (max_inline_size > default_max_inline_size) {
diff --git a/src/share/vm/opto/loopTransform.cpp b/src/share/vm/opto/loopTransform.cpp
index b405bbcf6..c438cf9b8 100644
--- a/src/share/vm/opto/loopTransform.cpp
+++ b/src/share/vm/opto/loopTransform.cpp
@@ -888,6 +888,7 @@ void PhaseIdealLoop::insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_
CountedLoopNode *main_head = loop->_head->as_CountedLoop();
assert( main_head->is_normal_loop(), "" );
CountedLoopEndNode *main_end = main_head->loopexit();
+ guarantee(main_end != NULL, "no loop exit node");
assert( main_end->outcnt() == 2, "1 true, 1 false path only" );
uint dd_main_head = dom_depth(main_head);
uint max = main_head->outcnt();
@@ -2554,13 +2555,16 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st
ok.set(store->_idx);
ok.set(store->in(MemNode::Memory)->_idx);
+ CountedLoopEndNode* loop_exit = head->loopexit();
+ guarantee(loop_exit != NULL, "no loop exit node");
+
// Loop structure is ok
ok.set(head->_idx);
- ok.set(head->loopexit()->_idx);
+ ok.set(loop_exit->_idx);
ok.set(head->phi()->_idx);
ok.set(head->incr()->_idx);
- ok.set(head->loopexit()->cmp_node()->_idx);
- ok.set(head->loopexit()->in(1)->_idx);
+ ok.set(loop_exit->cmp_node()->_idx);
+ ok.set(loop_exit->in(1)->_idx);
// Address elements are ok
if (con) ok.set(con->_idx);
@@ -2572,7 +2576,7 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st
if (n->outcnt() == 0) continue; // Ignore dead
if (ok.test(n->_idx)) continue;
// Backedge projection is ok
- if (n->is_IfTrue() && n->in(0) == head->loopexit()) continue;
+ if (n->is_IfTrue() && n->in(0) == loop_exit) continue;
if (!n->is_AddP()) {
msg = "unhandled node";
msg_node = n;
@@ -2585,7 +2589,7 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st
Node* n = lpt->_body.at(i);
// These values can be replaced with other nodes if they are used
// outside the loop.
- if (n == store || n == head->loopexit() || n == head->incr() || n == store->in(MemNode::Memory)) continue;
+ if (n == store || n == loop_exit || n == head->incr() || n == store->in(MemNode::Memory)) continue;
for (SimpleDUIterator iter(n); iter.has_next(); iter.next()) {
Node* use = iter.get();
if (!lpt->_body.contains(use)) {
diff --git a/src/share/vm/opto/loopnode.hpp b/src/share/vm/opto/loopnode.hpp
index 104d7b787..c45ea8421 100644
--- a/src/share/vm/opto/loopnode.hpp
+++ b/src/share/vm/opto/loopnode.hpp
@@ -603,7 +603,10 @@ class PhaseIdealLoop : public PhaseTransform {
}
public:
- bool has_node( Node* n ) const { return _nodes[n->_idx] != NULL; }
+ bool has_node( Node* n ) const {
+ guarantee(n != NULL, "No Node.");
+ return _nodes[n->_idx] != NULL;
+ }
// check if transform created new nodes that need _ctrl recorded
Node *get_late_ctrl( Node *n, Node *early );
Node *get_early_ctrl( Node *n );
@@ -737,7 +740,8 @@ private:
return n;
}
uint dom_depth(Node* d) const {
- assert(d->_idx < _idom_size, "");
+ guarantee(d != NULL, "Null dominator info.");
+ guarantee(d->_idx < _idom_size, "");
return _dom_depth[d->_idx];
}
void set_idom(Node* d, Node* n, uint dom_depth);
diff --git a/src/share/vm/opto/loopopts.cpp b/src/share/vm/opto/loopopts.cpp
index 31f080dbf..1db82d4ce 100644
--- a/src/share/vm/opto/loopopts.cpp
+++ b/src/share/vm/opto/loopopts.cpp
@@ -232,7 +232,11 @@ void PhaseIdealLoop::dominated_by( Node *prevdom, Node *iff, bool flip, bool exc
// Loop predicates may have depending checks which should not
// be skipped. For example, range check predicate has two checks
// for lower and upper bounds.
- ProjNode* unc_proj = iff->as_If()->proj_out(1 - dp->as_Proj()->_con)->as_Proj();
+ if (dp == NULL)
+ return;
+
+ ProjNode* dp_proj = dp->as_Proj();
+ ProjNode* unc_proj = iff->as_If()->proj_out(1 - dp_proj->_con)->as_Proj();
if (exclude_loop_predicate &&
is_uncommon_trap_proj(unc_proj, Deoptimization::Reason_predicate))
return; // Let IGVN transformation change control dependence.
@@ -866,8 +870,11 @@ void PhaseIdealLoop::split_if_with_blocks_post( Node *n ) {
// Now split the bool up thru the phi
Node *bolphi = split_thru_phi( bol, n_ctrl, -1 );
+ guarantee(bolphi != NULL, "null boolean phi node");
+
_igvn.replace_node( bol, bolphi );
assert( iff->in(1) == bolphi, "" );
+
if( bolphi->Value(&_igvn)->singleton() )
return;
@@ -1628,6 +1635,7 @@ ProjNode* PhaseIdealLoop::proj_clone(ProjNode* p, IfNode* iff) {
//------------------------------ short_circuit_if -------------------------------------
// Force the iff control output to be the live_proj
Node* PhaseIdealLoop::short_circuit_if(IfNode* iff, ProjNode* live_proj) {
+ guarantee(live_proj != NULL, "null projection");
int proj_con = live_proj->_con;
assert(proj_con == 0 || proj_con == 1, "false or true projection");
Node *con = _igvn.intcon(proj_con);
@@ -1686,6 +1694,7 @@ ProjNode* PhaseIdealLoop::insert_if_before_proj(Node* left, bool Signed, BoolTes
set_idom(proj, new_if, ddepth);
ProjNode* new_exit = proj_clone(other_proj, new_if)->as_Proj();
+ guarantee(new_exit != NULL, "null exit node");
register_node(new_exit, get_loop(other_proj), new_if, ddepth);
return new_exit;
@@ -1793,7 +1802,10 @@ IfNode* PhaseIdealLoop::insert_cmpi_loop_exit(IfNode* if_cmpu, IdealLoopTree *lo
int stride = stride_of_possible_iv(if_cmpu);
if (stride == 0) return NULL;
- ProjNode* lp_continue = stay_in_loop(if_cmpu, loop)->as_Proj();
+ Node* lp_proj = stay_in_loop(if_cmpu, loop);
+ guarantee(lp_proj != NULL, "null loop node");
+
+ ProjNode* lp_continue = lp_proj->as_Proj();
ProjNode* lp_exit = if_cmpu->proj_out(!lp_continue->is_IfTrue())->as_Proj();
Node* limit = NULL;
@@ -1805,6 +1817,7 @@ IfNode* PhaseIdealLoop::insert_cmpi_loop_exit(IfNode* if_cmpu, IdealLoopTree *lo
}
// Create a new region on the exit path
RegionNode* reg = insert_region_before_proj(lp_exit);
+ guarantee(reg != NULL, "null region node");
// Clone the if-cmpu-true-false using a signed compare
BoolTest::mask rel_i = stride > 0 ? bol->_test._test : BoolTest::ge;
diff --git a/src/share/vm/opto/output.cpp b/src/share/vm/opto/output.cpp
index b0d7a9948..c77b9f60c 100644
--- a/src/share/vm/opto/output.cpp
+++ b/src/share/vm/opto/output.cpp
@@ -2518,6 +2518,7 @@ void Scheduling::DoScheduling() {
// Schedule the remaining instructions in the block
while ( _available.size() > 0 ) {
Node *n = ChooseNodeToBundle();
+ guarantee(n != NULL, "no nodes available");
AddNodeToBundle(n,bb);
}
diff --git a/src/share/vm/opto/type.cpp b/src/share/vm/opto/type.cpp
index 3928c23af..68f681342 100644
--- a/src/share/vm/opto/type.cpp
+++ b/src/share/vm/opto/type.cpp
@@ -4193,6 +4193,7 @@ const TypeOopPtr* TypeKlassPtr::as_instance_type() const {
bool xk = klass_is_exact();
//return TypeInstPtr::make(TypePtr::NotNull, k, xk, NULL, 0);
const TypeOopPtr* toop = TypeOopPtr::make_from_klass_raw(k);
+ guarantee(toop != NULL, "need type for given klass");
toop = toop->cast_to_ptr_type(TypePtr::NotNull)->is_oopptr();
return toop->cast_to_exactness(xk)->is_oopptr();
}
diff --git a/src/share/vm/prims/jni.cpp b/src/share/vm/prims/jni.cpp
index f45568a7c..22716c400 100644
--- a/src/share/vm/prims/jni.cpp
+++ b/src/share/vm/prims/jni.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -92,7 +92,7 @@
# include "os_bsd.inline.hpp"
#endif
-static jint CurrentVersion = JNI_VERSION_1_6;
+static jint CurrentVersion = JNI_VERSION_1_8;
// The DT_RETURN_MARK macros create a scoped object to fire the dtrace
diff --git a/src/share/vm/prims/jni.h b/src/share/vm/prims/jni.h
index a67c2e540..582f2c970 100644
--- a/src/share/vm/prims/jni.h
+++ b/src/share/vm/prims/jni.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1951,6 +1951,7 @@ JNI_OnUnload(JavaVM *vm, void *reserved);
#define JNI_VERSION_1_2 0x00010002
#define JNI_VERSION_1_4 0x00010004
#define JNI_VERSION_1_6 0x00010006
+#define JNI_VERSION_1_8 0x00010008
#ifdef __cplusplus
} /* extern "C" */
diff --git a/src/share/vm/runtime/stubCodeGenerator.cpp b/src/share/vm/runtime/stubCodeGenerator.cpp
index 2ba8e159f..127b5e316 100644
--- a/src/share/vm/runtime/stubCodeGenerator.cpp
+++ b/src/share/vm/runtime/stubCodeGenerator.cpp
@@ -87,7 +87,7 @@ StubCodeGenerator::~StubCodeGenerator() {
CodeBuffer* cbuf = _masm->code();
CodeBlob* blob = CodeCache::find_blob_unsafe(cbuf->insts()->start());
if (blob != NULL) {
- blob->set_comments(cbuf->comments());
+ blob->set_strings(cbuf->strings());
}
bool saw_first = false;
StubCodeDesc* toprint[1000];
diff --git a/src/share/vm/runtime/thread.cpp b/src/share/vm/runtime/thread.cpp
index cb883c5d8..322597fe4 100644
--- a/src/share/vm/runtime/thread.cpp
+++ b/src/share/vm/runtime/thread.cpp
@@ -4061,6 +4061,7 @@ jboolean Threads::is_supported_jni_version(jint version) {
if (version == JNI_VERSION_1_2) return JNI_TRUE;
if (version == JNI_VERSION_1_4) return JNI_TRUE;
if (version == JNI_VERSION_1_6) return JNI_TRUE;
+ if (version == JNI_VERSION_1_8) return JNI_TRUE;
return JNI_FALSE;
}
diff --git a/src/share/vm/runtime/vm_version.cpp b/src/share/vm/runtime/vm_version.cpp
index ef03c76f6..322a5b6c0 100644
--- a/src/share/vm/runtime/vm_version.cpp
+++ b/src/share/vm/runtime/vm_version.cpp
@@ -211,6 +211,10 @@ const char* Abstract_VM_Version::internal_vm_info_string() {
#define HOTSPOT_BUILD_COMPILER "MS VC++ 8.0 (VS2005)"
#elif _MSC_VER == 1500
#define HOTSPOT_BUILD_COMPILER "MS VC++ 9.0 (VS2008)"
+ #elif _MSC_VER == 1600
+ #define HOTSPOT_BUILD_COMPILER "MS VC++ 10.0 (VS2010)"
+ #elif _MSC_VER == 1700
+ #define HOTSPOT_BUILD_COMPILER "MS VC++ 11.0 (VS2012)"
#else
#define HOTSPOT_BUILD_COMPILER "unknown MS VC++:" XSTR(_MSC_VER)
#endif
diff --git a/src/share/vm/services/memoryService.cpp b/src/share/vm/services/memoryService.cpp
index 0040f9d96..75693dbcf 100644
--- a/src/share/vm/services/memoryService.cpp
+++ b/src/share/vm/services/memoryService.cpp
@@ -240,6 +240,7 @@ MemoryPool* MemoryService::add_cms_space(CompactibleFreeListSpace* space,
void MemoryService::add_generation_memory_pool(Generation* gen,
MemoryManager* major_mgr,
MemoryManager* minor_mgr) {
+ guarantee(gen != NULL, "No generation for memory pool");
Generation::Name kind = gen->kind();
int index = _pools_list->length();
diff --git a/src/share/vm/utilities/debug.cpp b/src/share/vm/utilities/debug.cpp
index 131f08d44..e74475fc3 100644
--- a/src/share/vm/utilities/debug.cpp
+++ b/src/share/vm/utilities/debug.cpp
@@ -248,10 +248,6 @@ void report_should_not_reach_here(const char* file, int line) {
report_vm_error(file, line, "ShouldNotReachHere()");
}
-void report_should_not_reach_here2(const char* file, int line, const char* message) {
- report_vm_error(file, line, "ShouldNotReachHere()", message);
-}
-
void report_unimplemented(const char* file, int line) {
report_vm_error(file, line, "Unimplemented()");
}
diff --git a/src/share/vm/utilities/debug.hpp b/src/share/vm/utilities/debug.hpp
index 515b1286b..0c718a2fe 100644
--- a/src/share/vm/utilities/debug.hpp
+++ b/src/share/vm/utilities/debug.hpp
@@ -192,12 +192,6 @@ do { \
BREAKPOINT; \
} while (0)
-#define ShouldNotReachHere2(message) \
-do { \
- report_should_not_reach_here2(__FILE__, __LINE__, message); \
- BREAKPOINT; \
-} while (0)
-
#define Unimplemented() \
do { \
report_unimplemented(__FILE__, __LINE__); \
@@ -218,7 +212,6 @@ void report_vm_out_of_memory(const char* file, int line, size_t size,
const char* message);
void report_should_not_call(const char* file, int line);
void report_should_not_reach_here(const char* file, int line);
-void report_should_not_reach_here2(const char* file, int line, const char* message);
void report_unimplemented(const char* file, int line);
void report_untested(const char* file, int line, const char* message);
diff --git a/test/compiler/whitebox/CompilerWhiteBoxTest.java b/test/compiler/whitebox/CompilerWhiteBoxTest.java
index ebd5a9af4..02b928158 100644
--- a/test/compiler/whitebox/CompilerWhiteBoxTest.java
+++ b/test/compiler/whitebox/CompilerWhiteBoxTest.java
@@ -35,6 +35,8 @@ public abstract class CompilerWhiteBoxTest {
protected static final Method METHOD = getMethod("method");
protected static final int COMPILE_THRESHOLD
= Integer.parseInt(getVMOption("CompileThreshold", "10000"));
+ protected static final boolean BACKGROUND_COMPILATION
+ = Boolean.valueOf(getVMOption("BackgroundCompilation", "true"));
protected static Method getMethod(String name) {
try {
@@ -45,11 +47,16 @@ public abstract class CompilerWhiteBoxTest {
}
}
- protected static String getVMOption(String name, String defaultValue) {
+ protected static String getVMOption(String name) {
String result;
HotSpotDiagnosticMXBean diagnostic
= ManagementFactoryHelper.getDiagnosticMXBean();
result = diagnostic.getVMOption(name).getValue();
+ return result;
+ }
+
+ protected static String getVMOption(String name, String defaultValue) {
+ String result = getVMOption(name);
return result == null ? defaultValue : result;
}
@@ -66,6 +73,7 @@ public abstract class CompilerWhiteBoxTest {
} catch (Exception e) {
System.out.printf("on exception '%s':", e.getMessage());
printInfo(METHOD);
+ e.printStackTrace();
throw new RuntimeException(e);
}
System.out.println("at test's end:");
@@ -100,6 +108,9 @@ public abstract class CompilerWhiteBoxTest {
protected static void waitBackgroundCompilation(Method method)
throws InterruptedException {
+ if (!BACKGROUND_COMPILATION) {
+ return;
+ }
final Object obj = new Object();
synchronized (obj) {
for (int i = 0; i < 10; ++i) {
@@ -129,13 +140,14 @@ public abstract class CompilerWhiteBoxTest {
protected final int compile() {
int result = 0;
- for (int i = 0; i < COMPILE_THRESHOLD; ++i) {
+ int count = Math.max(COMPILE_THRESHOLD, 150000);
+ for (int i = 0; i < count; ++i) {
result += method();
}
+ System.out.println("method was invoked " + count + " times");
return result;
}
-
protected int method() {
return 42;
}
diff --git a/test/compiler/whitebox/DeoptimizeAllTest.java b/test/compiler/whitebox/DeoptimizeAllTest.java
index 7690e6a90..fdf498c31 100644
--- a/test/compiler/whitebox/DeoptimizeAllTest.java
+++ b/test/compiler/whitebox/DeoptimizeAllTest.java
@@ -32,12 +32,12 @@
public class DeoptimizeAllTest extends CompilerWhiteBoxTest {
public static void main(String[] args) throws Exception {
+ // to prevent inlining #method into #compile()
+ WHITE_BOX.setDontInlineMethod(METHOD, true);
new DeoptimizeAllTest().runTest();
}
protected void test() throws Exception {
- // to prevent inlining #method into #compile()
- WHITE_BOX.setDontInlineMethod(METHOD, true);
compile();
checkCompiled(METHOD);
WHITE_BOX.deoptimizeAll();
diff --git a/test/compiler/whitebox/DeoptimizeMethodTest.java b/test/compiler/whitebox/DeoptimizeMethodTest.java
index bc1c9d679..7894c524f 100644
--- a/test/compiler/whitebox/DeoptimizeMethodTest.java
+++ b/test/compiler/whitebox/DeoptimizeMethodTest.java
@@ -32,12 +32,12 @@
public class DeoptimizeMethodTest extends CompilerWhiteBoxTest {
public static void main(String[] args) throws Exception {
+ // to prevent inlining #method into #compile()
+ WHITE_BOX.setDontInlineMethod(METHOD, true);
new DeoptimizeMethodTest().runTest();
}
protected void test() throws Exception {
- // to prevent inlining #method into #compile()
- WHITE_BOX.setDontInlineMethod(METHOD, true);
compile();
checkCompiled(METHOD);
WHITE_BOX.deoptimizeMethod(METHOD);
diff --git a/test/compiler/whitebox/IsMethodCompilableTest.java b/test/compiler/whitebox/IsMethodCompilableTest.java
index d0c102f54..374d48402 100644
--- a/test/compiler/whitebox/IsMethodCompilableTest.java
+++ b/test/compiler/whitebox/IsMethodCompilableTest.java
@@ -44,6 +44,8 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest {
}
public static void main(String[] args) throws Exception {
+ // to prevent inlining #method into #compile()
+ WHITE_BOX.setDontInlineMethod(METHOD, true);
new IsMethodCompilableTest().runTest();
}
@@ -58,8 +60,6 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest {
"Warning: test is not applicable if PerMethodRecompilationCutoff == Inf");
return;
}
- // to prevent inlining #method into #compile()
- WHITE_BOX.setDontInlineMethod(METHOD, true);
boolean madeNotCompilable = false;
for (long i = 0; i < PER_METHOD_RECOMPILATION_CUTOFF; ++i) {
diff --git a/test/compiler/whitebox/MakeMethodNotCompilableTest.java b/test/compiler/whitebox/MakeMethodNotCompilableTest.java
index ad4930b64..0b9144c40 100644
--- a/test/compiler/whitebox/MakeMethodNotCompilableTest.java
+++ b/test/compiler/whitebox/MakeMethodNotCompilableTest.java
@@ -32,6 +32,8 @@
public class MakeMethodNotCompilableTest extends CompilerWhiteBoxTest {
public static void main(String[] args) throws Exception {
+ // to prevent inlining #method into #compile()
+ WHITE_BOX.setDontInlineMethod(METHOD, true);
new MakeMethodNotCompilableTest().runTest();
}