This commit is contained in:
Alejandro Murillo 2013-03-23 01:47:24 -07:00
commit dc09472ed0
89 changed files with 2850 additions and 1942 deletions

View File

@ -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,14 +221,48 @@ 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;
}
/*
* 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
@ -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);
#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
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;
// 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);
if (debug) printf("set registers\n");
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);
(*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);
}

View File

@ -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
INCLUDES = -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$(shell uname -s | tr "[:upper:]" "[:lower:]")
OBJS = $(SOURCES:.c=.o)
OBJS = $(SOURCES:.c=.o)
OBJSPLUS = $(OBJS) sadis.o
LIBSA = $(ARCH)/libsaproc.so
LIBS = -lutil -lthread_db
CFLAGS = -c -fPIC -g -Wall -D_ALLBSD_SOURCE -D_GNU_SOURCE -D$(ARCH) $(INCLUDES)
else
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)
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)

View File

@ -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

View File

@ -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();
fd = open(name, O_RDONLY);
if (fd >= 0) {
init_alt_root();
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;
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;
}
}
}
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.
// 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;
}
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__

View File

@ -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
bool is_elf_file(int fd);
#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_

File diff suppressed because it is too large Load Diff

View File

@ -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
// ----------------------------------------------------
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; // all symbols "__symbol1__'\0'__symbol2__...."
size_t num_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;
};
struct elf_symbol {
char *name;
uintptr_t offset;
uintptr_t size;
};
typedef struct symtab {
char *strs;
size_t num_symbols;
struct elf_symbol *symbols;
DB* hash_table;
} symtab_t;
// 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);

View File

@ -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

View File

@ -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";

View File

@ -24,36 +24,81 @@
package sun.jvm.hotspot;
import java.io.*;
import java.math.*;
import java.util.*;
import java.util.regex.*;
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.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 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;
}
}

View File

@ -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. */

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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. */

View File

@ -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;

View File

@ -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);

View File

@ -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 {

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) \

View File

@ -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

View File

@ -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

View File

@ -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}, \

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
}
};

View File

@ -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); }
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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.

View File

@ -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

View File

@ -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> {
private:
friend class CodeComments;
intptr_t _offset;
const char * _comment;
CodeComment* _next;
const char* CodeBuffer::code_string(const char* str) {
return _strings.add_string(str);
}
~CodeComment() {
class CodeString: public CHeapObj<mtCode> {
private:
friend class CodeStrings;
const char * _string;
CodeString* _next;
intptr_t _offset;
~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;
}
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);
// 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 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;

View File

@ -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);

View File

@ -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()) {

View File

@ -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!");
}
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -186,7 +186,7 @@ void CodeBlob::flush() {
FREE_C_HEAP_ARRAY(unsigned char, _oop_maps, mtCode);
_oop_maps = NULL;
}
_comments.free();
_strings.free();
}

View File

@ -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);
}
};

View File

@ -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;

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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());

View File

@ -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 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]");
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 */);
set_concurrency_and_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.
// 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.
}

View File

@ -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() {

View File

@ -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);
}
}

View File

@ -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()));
}
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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) {
// If the user wants a limit, impose one.
if (!FLAG_IS_DEFAULT(MaxMetaspaceSize) &&
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 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) {
return false;
}
// 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

View File

@ -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");
}
}

View File

@ -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);
}

View File

@ -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();

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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) {

View File

@ -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)) {

View File

@ -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);

View File

@ -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;

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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

View File

@ -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" */

View File

@ -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];

View File

@ -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;
}

View File

@ -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

View File

@ -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();

View File

@ -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()");
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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();

View File

@ -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);

View File

@ -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) {

View File

@ -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();
}