# HG changeset patch # User chegar # Date 1365758082 -3600 # Node ID 124ca22437b147526b7d42a264184cebb6284d01 # Parent 511e334ee345ae770f6fe94730f03067907da454# Parent 3d641132f83b348c6a53067ef5a8977a737e0598 Merge diff -r 3d641132f83b -r 124ca22437b1 .hgtags --- a/.hgtags Tue Feb 26 16:16:54 2013 -0800 +++ b/.hgtags Fri Apr 12 10:14:42 2013 +0100 @@ -325,3 +325,10 @@ 65b797426a3bec6e91b64085a0cfb94adadb634a jdk8-b81 0631ebcc45f05c73b09a56c2586685af1f781c1d hs25-b23 3db4ab0e12f437fe374817de346b2b0c6b4a5b31 jdk8-b82 +e3a41fc0234895eba4f272b984f7dacff495f8eb hs25-b24 +1c8db54ee9f315e20d6d5d9bf0b5c10349e9d301 jdk8-b83 +8d0f263a370c5f3e61791bb06054560804117288 hs25-b25 +af788b85010ebabbc1e8f52c6766e08c7a95cf99 jdk8-b84 +a947f40fb536e5b9e0aa210cf26abb430f80887a hs25-b26 +42fe530cd478744a4d12a0cbf803f0fc804bab1a jdk8-b85 +09b0d3e9ba6cdf7da07d4010d2d1df14596f6864 hs25-b27 diff -r 3d641132f83b -r 124ca22437b1 agent/src/os/bsd/MacosxDebuggerLocal.m --- a/agent/src/os/bsd/MacosxDebuggerLocal.m Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/os/bsd/MacosxDebuggerLocal.m Fri Apr 12 10:14:42 2013 +0100 @@ -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 #import #import +#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 @@ (*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 @@ #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 @@ 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 @@ JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) { + struct ps_prochandle* ph = get_proc_handle(env, this_obj); + if (ph->core != NULL) { + return lookupByNameIncore(env, ph, this_obj, objectName, symbolName); + } + jlong address = 0; JNF_COCOA_ENTER(env); NSString *symbolNameString = JNFJavaToNSString(env, symbolName); - if (debug) { - printf("lookupInProcess called for %s\n", [symbolNameString UTF8String]); - } + print_debug("lookupInProcess called for %s\n", [symbolNameString UTF8String]); id symbolicator = getSymbolicator(env, this_obj); if (symbolicator != nil) { @@ -131,9 +221,7 @@ address = (jlong) dynamicCall(symbolicator, @selector(addressForSymbol:), symbolNameString); } - if (debug) { - printf("address of symbol %s = %llx\n", [symbolNameString UTF8String], address); - } + print_debug("address of symbol %s = %llx\n", [symbolNameString UTF8String], address); JNF_COCOA_EXIT(env); return address; @@ -141,6 +229,42 @@ /* * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal + * Method: lookupByAddress0 + * Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol; + */ +JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0 + (JNIEnv *env, jobject this_obj, jlong addr) { + uintptr_t offset; + const char* sym = NULL; + + struct ps_prochandle* ph = get_proc_handle(env, this_obj); + sym = symbol_for_pc(ph, (uintptr_t) addr, &offset); + if (sym == NULL) return 0; + return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID, + (*env)->NewStringUTF(env, sym), (jlong)offset); +} + +/** called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0 */ +jbyteArray readBytesFromCore( + JNIEnv *env, struct ps_prochandle *ph, jobject this_obj, jlong addr, jlong numBytes) +{ + jboolean isCopy; + jbyteArray array; + jbyte *bufPtr; + ps_err_e err; + + array = (*env)->NewByteArray(env, numBytes); + CHECK_EXCEPTION_(0); + bufPtr = (*env)->GetByteArrayElements(env, array, &isCopy); + CHECK_EXCEPTION_(0); + + err = ps_pread(ph, (psaddr_t) (uintptr_t)addr, bufPtr, numBytes); + (*env)->ReleaseByteArrayElements(env, array, bufPtr, 0); + return (err == PS_OK)? array : 0; +} + +/* + * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal * Method: readBytesFromProcess0 * Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult; */ @@ -149,12 +273,15 @@ 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 @@ // 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 @@ } 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 @@ 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, ®s)) { + 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 @@ */ 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 @@ // 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 @@ // 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 @@ 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 @@ 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 + + // 64 bit + print_debug("Getting threads for a 64-bit process\n"); + registerArray = (*env)->NewLongArray(env, NPRGREG); + CHECK_EXCEPTION_(0); + primitiveArray = (*env)->GetLongArrayElements(env, registerArray, NULL); - primitiveArray[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; + 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"); - if (debug) printf("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 @@ 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 @@ 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 @@ // 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 @@ 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 @@ 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_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 @@ * 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_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 @@ 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_EXIT(env); } - -/* - * Class: sun_jvm_hotspot_asm_Disassembler - * Method: load_library - * Signature: (Ljava/lang/String;)L - */ -JNIEXPORT jlong JNICALL -Java_sun_jvm_hotspot_asm_Disassembler_load_1library( - JNIEnv * env, - jclass disclass, - jstring jrepath_s, - jstring libname_s) -{ - uintptr_t func = 0; - const char* error_message = NULL; - const char* java_home; - jboolean isCopy; - uintptr_t *handle = NULL; - - const char * jrepath = (*env)->GetStringUTFChars(env, jrepath_s, &isCopy); // like $JAVA_HOME/jre/lib/sparc/ - const char * libname = (*env)->GetStringUTFChars(env, libname_s, &isCopy); - char buffer[128]; - - /* Load the hsdis library */ - void* hsdis_handle; - hsdis_handle = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL); - if (hsdis_handle == NULL) { - snprintf(buffer, sizeof(buffer), "%s%s", jrepath, libname); - hsdis_handle = dlopen(buffer, RTLD_LAZY | RTLD_GLOBAL); - } - if (hsdis_handle != NULL) { - func = (uintptr_t)dlsym(hsdis_handle, "decode_instructions_virtual"); - } - if (func == 0) { - error_message = dlerror(); - fprintf(stderr, "%s\n", error_message); - } - - (*env)->ReleaseStringUTFChars(env, libname_s, libname); - (*env)->ReleaseStringUTFChars(env, jrepath_s, jrepath); - - if (func == 0) { - /* Couldn't find entry point. error_message should contain some - * platform dependent error message. - */ - THROW_NEW_DEBUGGER_EXCEPTION_(error_message, (jlong)func); - } - return (jlong)func; -} - -/* signature of decode_instructions_virtual from hsdis.h */ -typedef void* (*decode_func)(uintptr_t start_va, uintptr_t end_va, - unsigned char* start, uintptr_t length, - void* (*event_callback)(void*, const char*, void*), - void* event_stream, - int (*printf_callback)(void*, const char*, ...), - void* printf_stream, - const char* options); - -/* container for call back state when decoding instructions */ -typedef struct { - JNIEnv* env; - jobject dis; - jobject visitor; - jmethodID handle_event; - jmethodID raw_print; - char buffer[4096]; -} decode_env; - - -/* event callback binding to Disassembler.handleEvent */ -static void* event_to_env(void* env_pv, const char* event, void* arg) { - decode_env* denv = (decode_env*)env_pv; - JNIEnv* env = denv->env; - jstring event_string = (*env)->NewStringUTF(env, event); - jlong result = (*env)->CallLongMethod(env, denv->dis, denv->handle_event, denv->visitor, - event_string, (jlong) (uintptr_t)arg); - /* ignore exceptions for now */ - CHECK_EXCEPTION_CLEAR_((void *)0); - return (void*)(uintptr_t)result; -} - -/* printing callback binding to Disassembler.rawPrint */ -static int printf_to_env(void* env_pv, const char* format, ...) { - jstring output; - va_list ap; - int cnt; - decode_env* denv = (decode_env*)env_pv; - JNIEnv* env = denv->env; - size_t flen = strlen(format); - const char* raw = NULL; - - if (flen == 0) return 0; - if (flen < 2 || - strchr(format, '%') == NULL) { - raw = format; - } else if (format[0] == '%' && format[1] == '%' && - strchr(format+2, '%') == NULL) { - // happens a lot on machines with names like %foo - flen--; - raw = format+1; - } - if (raw != NULL) { - jstring output = (*env)->NewStringUTF(env, raw); - (*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output); - CHECK_EXCEPTION_CLEAR; - return (int) flen; - } - va_start(ap, format); - cnt = vsnprintf(denv->buffer, sizeof(denv->buffer), format, ap); - va_end(ap); - - output = (*env)->NewStringUTF(env, denv->buffer); - (*env)->CallVoidMethod(env, denv->dis, denv->raw_print, denv->visitor, output); - CHECK_EXCEPTION_CLEAR; - return cnt; -} - -/* - * Class: sun_jvm_hotspot_asm_Disassembler - * Method: decode - * Signature: (Lsun/jvm/hotspot/asm/InstructionVisitor;J[BLjava/lang/String;J)V - */ -JNIEXPORT void JNICALL -Java_sun_jvm_hotspot_asm_Disassembler_decode( - JNIEnv * env, - jobject dis, - jobject visitor, - jlong startPc, - jbyteArray code, - jstring options_s, - jlong decode_instructions_virtual) -{ - jboolean isCopy; - jbyte* start = (*env)->GetByteArrayElements(env, code, &isCopy); - jbyte* end = start + (*env)->GetArrayLength(env, code); - const char * options = (*env)->GetStringUTFChars(env, options_s, &isCopy); - jclass disclass = (*env)->GetObjectClass(env, dis); - - decode_env denv; - denv.env = env; - denv.dis = dis; - denv.visitor = visitor; - - /* find Disassembler.handleEvent callback */ - denv.handle_event = (*env)->GetMethodID(env, disclass, "handleEvent", - "(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;J)J"); - CHECK_EXCEPTION_CLEAR_VOID - - /* find Disassembler.rawPrint callback */ - denv.raw_print = (*env)->GetMethodID(env, disclass, "rawPrint", - "(Lsun/jvm/hotspot/asm/InstructionVisitor;Ljava/lang/String;)V"); - CHECK_EXCEPTION_CLEAR_VOID - - /* decode the buffer */ - (*(decode_func)(uintptr_t)decode_instructions_virtual)(startPc, - startPc + end - start, - (unsigned char*)start, - end - start, - &event_to_env, (void*) &denv, - &printf_to_env, (void*) &denv, - options); - - /* cleanup */ - (*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT); - (*env)->ReleaseStringUTFChars(env, options_s, options); -} diff -r 3d641132f83b -r 124ca22437b1 agent/src/os/bsd/Makefile --- a/agent/src/os/bsd/Makefile Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/os/bsd/Makefile Fri Apr 12 10:14:42 2013 +0100 @@ -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 -LIBSA = $(ARCH)/libsaproc.so +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) + + 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 @@ 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 @@ clean: rm -f $(LIBSA) - rm -f $(OBJS) + rm -f *.o rm -f test.o -rmdir $(ARCH) - diff -r 3d641132f83b -r 124ca22437b1 agent/src/os/bsd/libproc.h --- a/agent/src/os/bsd/libproc.h Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/os/bsd/libproc.h Fri Apr 12 10:14:42 2013 +0100 @@ -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 #include +#include +#include +#include +#include +#include + +#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 +#else // __APPLE__ +#include +#include #include #include - #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 @@ *************************************************************************************/ -// This C bool type must be int for compatibility with BSD calls and -// it would be a mistake to equivalence it to C++ bool on many platforms - -typedef int bool; -#define true 1 -#define false 0 - +struct reg; struct ps_prochandle; // attach to a process diff -r 3d641132f83b -r 124ca22437b1 agent/src/os/bsd/libproc_impl.c --- a/agent/src/os/bsd/libproc_impl.c Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/os/bsd/libproc_impl.c Fri Apr 12 10:14:42 2013 +0100 @@ -21,12 +21,6 @@ * questions. * */ -#include -#include -#include -#include -#include -#include #include "libproc_impl.h" static const char* alt_root = NULL; @@ -34,61 +28,65 @@ #define SA_ALTROOT "SA_ALTROOT" +off_t ltell(int fd) { + return lseek(fd, 0, SEEK_CUR); +} + static void init_alt_root() { - if (alt_root_len == -1) { - alt_root = getenv(SA_ALTROOT); - if (alt_root) { - alt_root_len = strlen(alt_root); - } else { - alt_root_len = 0; - } - } + if (alt_root_len == -1) { + alt_root = getenv(SA_ALTROOT); + if (alt_root) { + alt_root_len = strlen(alt_root); + } else { + alt_root_len = 0; + } + } } int pathmap_open(const char* name) { - int fd; - char alt_path[PATH_MAX + 1]; + int fd; + char alt_path[PATH_MAX + 1]; + + init_alt_root(); - init_alt_root(); - fd = open(name, O_RDONLY); - if (fd >= 0) { + if (alt_root_len > 0) { + strcpy(alt_path, alt_root); + strcat(alt_path, name); + fd = open(alt_path, O_RDONLY); + if (fd >= 0) { + print_debug("path %s substituted for %s\n", alt_path, name); return fd; - } + } - if (alt_root_len > 0) { + if (strrchr(name, '/')) { strcpy(alt_path, alt_root); - strcat(alt_path, name); + strcat(alt_path, strrchr(name, '/')); fd = open(alt_path, O_RDONLY); if (fd >= 0) { - print_debug("path %s substituted for %s\n", alt_path, name); - return fd; + 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 @@ } 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; - } - - strncpy(newlib->name, libname, sizeof(newlib->name)); - newlib->base = base; + if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) { + print_debug("can't allocate memory for lib_info\n"); + return NULL; + } - 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; - } + strncpy(newlib->name, libname, sizeof(newlib->name)); + newlib->base = base; - // check whether we have got an ELF file. /proc//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; - } - - 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); - } + } + } else { + newlib->fd = fd; + } - // 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++; +#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//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__ - return newlib; + 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); + } + + // 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//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//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 @@ return true; } +#endif // __APPLE__ // get number of threads int get_num_threads(struct ps_prochandle* ph) { @@ -322,18 +384,54 @@ // 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 @@ // 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 @@ 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 @@ print_debug("ps_pcontinue not implemented\n"); return PS_OK; } +#endif // __APPLE__ diff -r 3d641132f83b -r 124ca22437b1 agent/src/os/bsd/libproc_impl.h --- a/agent/src/os/bsd/libproc_impl.h Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/os/bsd/libproc_impl.h Fri Apr 12 10:14:42 2013 +0100 @@ -30,6 +30,60 @@ #include "libproc.h" #include "symtab.h" +#ifdef __APPLE__ +#include // for PRIx64, 32, ... +#include +#include +#include +#include + +#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 +#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 @@ } 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 @@ // 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 @@ 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_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base); -// adds a new thread to threads list, returns NULL on failure -thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id); - +sa_thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id); // a test for ELF signature without using libelf + +#ifdef __APPLE__ +// a test for Mach-O signature +bool is_macho_file(int fd); +// skip fat head to get image start offset of cpu_type_t +// return false if any error happens, else value in offset. +bool get_arch_off(int fd, cpu_type_t cputype, off_t *offset); +#else bool is_elf_file(int fd); +#endif // __APPLE__ + +lwpid_t get_lwp_id(struct ps_prochandle* ph, int index); +bool set_lwp_id(struct ps_prochandle* ph, int index, lwpid_t lwpid); +bool get_nth_lwp_regs(struct ps_prochandle* ph, int index, struct reg* regs); + +// ps_pglobal_lookup() looks up the symbol sym_name in the symbol table +// of the load object object_name in the target process identified by ph. +// It returns the symbol's value as an address in the target process in +// *sym_addr. +ps_err_e ps_pglobal_lookup(struct ps_prochandle *ph, const char *object_name, + const char *sym_name, psaddr_t *sym_addr); + +// read "size" bytes info "buf" from address "addr" +ps_err_e ps_pread(struct ps_prochandle *ph, psaddr_t addr, + void *buf, size_t size); + +// write "size" bytes of data to debuggee at address "addr" +ps_err_e ps_pwrite(struct ps_prochandle *ph, psaddr_t addr, + const void *buf, size_t size); + +// fill in ptrace_lwpinfo for lid +ps_err_e ps_linfo(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo); + +// needed for when libthread_db is compiled with TD_DEBUG defined +void ps_plog (const char *format, ...); + +// untility, tells the position in file +off_t ltell(int fd); #endif //_LIBPROC_IMPL_H_ diff -r 3d641132f83b -r 124ca22437b1 agent/src/os/bsd/ps_core.c --- a/agent/src/os/bsd/ps_core.c Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/os/bsd/ps_core.c Fri Apr 12 10:14:42 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,10 +28,11 @@ #include #include #include -#include -#include #include "libproc_impl.h" -#include "salibelf.h" + +#ifdef __APPLE__ +#include "sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext.h" +#endif // This file has the libproc implementation to read core files. // For live processes, refer to ps_proc.c. Portions of this is adapted @@ -41,156 +42,158 @@ // ps_prochandle cleanup helper functions // close all file descriptors -static void close_elf_files(struct ps_prochandle* ph) { - lib_info* lib = NULL; +static void close_files(struct ps_prochandle* ph) { + lib_info* lib = NULL; + // close core file descriptor + if (ph->core->core_fd >= 0) + close(ph->core->core_fd); - // close core file descriptor - if (ph->core->core_fd >= 0) - close(ph->core->core_fd); + // close exec file descriptor + if (ph->core->exec_fd >= 0) + close(ph->core->exec_fd); - // close exec file descriptor - if (ph->core->exec_fd >= 0) - close(ph->core->exec_fd); + // close interp file descriptor + if (ph->core->interp_fd >= 0) + close(ph->core->interp_fd); - // close interp file descriptor - if (ph->core->interp_fd >= 0) - close(ph->core->interp_fd); - - // close class share archive file - if (ph->core->classes_jsa_fd >= 0) - close(ph->core->classes_jsa_fd); + // close class share archive file + if (ph->core->classes_jsa_fd >= 0) + close(ph->core->classes_jsa_fd); - // close all library file descriptors - lib = ph->libs; - while (lib) { - int fd = lib->fd; - if (fd >= 0 && fd != ph->core->exec_fd) close(fd); - lib = lib->next; - } + // close all library file descriptors + lib = ph->libs; + while (lib) { + int fd = lib->fd; + if (fd >= 0 && fd != ph->core->exec_fd) { + close(fd); + } + lib = lib->next; + } } // clean all map_info stuff static void destroy_map_info(struct ps_prochandle* ph) { map_info* map = ph->core->maps; while (map) { - map_info* next = map->next; - free(map); - map = next; + map_info* next = map->next; + free(map); + map = next; } if (ph->core->map_array) { - free(ph->core->map_array); + free(ph->core->map_array); } // Part of the class sharing workaround map = ph->core->class_share_maps; while (map) { - map_info* next = map->next; - free(map); - map = next; + map_info* next = map->next; + free(map); + map = next; } } // ps_prochandle operations static void core_release(struct ps_prochandle* ph) { - if (ph->core) { - close_elf_files(ph); - destroy_map_info(ph); - free(ph->core); - } + if (ph->core) { + close_files(ph); + destroy_map_info(ph); + free(ph->core); + } } static map_info* allocate_init_map(int fd, off_t offset, uintptr_t vaddr, size_t memsz) { - map_info* map; - if ( (map = (map_info*) calloc(1, sizeof(map_info))) == NULL) { - print_debug("can't allocate memory for map_info\n"); - return NULL; - } + map_info* map; + if ( (map = (map_info*) calloc(1, sizeof(map_info))) == NULL) { + print_debug("can't allocate memory for map_info\n"); + return NULL; + } - // initialize map - map->fd = fd; - map->offset = offset; - map->vaddr = vaddr; - map->memsz = memsz; - return map; + // initialize map + map->fd = fd; + map->offset = offset; + map->vaddr = vaddr; + map->memsz = memsz; + return map; } // add map info with given fd, offset, vaddr and memsz static map_info* add_map_info(struct ps_prochandle* ph, int fd, off_t offset, uintptr_t vaddr, size_t memsz) { - map_info* map; - if ((map = allocate_init_map(fd, offset, vaddr, memsz)) == NULL) { - return NULL; - } + map_info* map; + if ((map = allocate_init_map(fd, offset, vaddr, memsz)) == NULL) { + return NULL; + } - // add this to map list - map->next = ph->core->maps; - ph->core->maps = map; - ph->core->num_maps++; + // add this to map list + map->next = ph->core->maps; + ph->core->maps = map; + ph->core->num_maps++; - return map; + return map; } // Part of the class sharing workaround static map_info* add_class_share_map_info(struct ps_prochandle* ph, off_t offset, uintptr_t vaddr, size_t memsz) { - map_info* map; - if ((map = allocate_init_map(ph->core->classes_jsa_fd, - offset, vaddr, memsz)) == NULL) { - return NULL; - } + map_info* map; + if ((map = allocate_init_map(ph->core->classes_jsa_fd, + offset, vaddr, memsz)) == NULL) { + return NULL; + } - map->next = ph->core->class_share_maps; - ph->core->class_share_maps = map; - return map; + map->next = ph->core->class_share_maps; + ph->core->class_share_maps = map; + return map; } // Return the map_info for the given virtual address. We keep a sorted // array of pointers in ph->map_array, so we can binary search. static map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr) { - int mid, lo = 0, hi = ph->core->num_maps - 1; - map_info *mp; + int mid, lo = 0, hi = ph->core->num_maps - 1; + map_info *mp; - while (hi - lo > 1) { - mid = (lo + hi) / 2; - if (addr >= ph->core->map_array[mid]->vaddr) - lo = mid; - else - hi = mid; - } + while (hi - lo > 1) { + mid = (lo + hi) / 2; + if (addr >= ph->core->map_array[mid]->vaddr) { + lo = mid; + } else { + hi = mid; + } + } - if (addr < ph->core->map_array[hi]->vaddr) - mp = ph->core->map_array[lo]; - else - mp = ph->core->map_array[hi]; + if (addr < ph->core->map_array[hi]->vaddr) { + mp = ph->core->map_array[lo]; + } else { + mp = ph->core->map_array[hi]; + } - if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) - return (mp); + if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) { + return (mp); + } - // Part of the class sharing workaround - // Unfortunately, we have no way of detecting -Xshare state. - // Check out the share maps atlast, if we don't find anywhere. - // This is done this way so to avoid reading share pages - // ahead of other normal maps. For eg. with -Xshare:off we don't - // want to prefer class sharing data to data from core. - mp = ph->core->class_share_maps; - if (mp) { - print_debug("can't locate map_info at 0x%lx, trying class share maps\n", - addr); - } - while (mp) { - if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) { - print_debug("located map_info at 0x%lx from class share maps\n", - addr); - return (mp); - } - mp = mp->next; - } + // Part of the class sharing workaround + // Unfortunately, we have no way of detecting -Xshare state. + // Check out the share maps atlast, if we don't find anywhere. + // This is done this way so to avoid reading share pages + // ahead of other normal maps. For eg. with -Xshare:off we don't + // want to prefer class sharing data to data from core. + mp = ph->core->class_share_maps; + if (mp) { + print_debug("can't locate map_info at 0x%lx, trying class share maps\n", addr); + } + while (mp) { + if (addr >= mp->vaddr && addr < mp->vaddr + mp->memsz) { + print_debug("located map_info at 0x%lx from class share maps\n", addr); + return (mp); + } + mp = mp->next; + } - print_debug("can't locate map_info at 0x%lx\n", addr); - return (NULL); + print_debug("can't locate map_info at 0x%lx\n", addr); + return (NULL); } //--------------------------------------------------------------- @@ -239,157 +242,171 @@ }; static bool read_jboolean(struct ps_prochandle* ph, uintptr_t addr, jboolean* pvalue) { - jboolean i; - if (ps_pread(ph, (psaddr_t) addr, &i, sizeof(i)) == PS_OK) { - *pvalue = i; - return true; - } else { - return false; - } + jboolean i; + if (ps_pread(ph, (psaddr_t) addr, &i, sizeof(i)) == PS_OK) { + *pvalue = i; + return true; + } else { + return false; + } } static bool read_pointer(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* pvalue) { - uintptr_t uip; - if (ps_pread(ph, (psaddr_t) addr, &uip, sizeof(uip)) == PS_OK) { - *pvalue = uip; - return true; - } else { - return false; - } + uintptr_t uip; + if (ps_pread(ph, (psaddr_t) addr, (char *)&uip, sizeof(uip)) == PS_OK) { + *pvalue = uip; + return true; + } else { + return false; + } } // used to read strings from debuggee static bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, size_t size) { - size_t i = 0; - char c = ' '; + size_t i = 0; + char c = ' '; - while (c != '\0') { - if (ps_pread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK) - return false; - if (i < size - 1) - buf[i] = c; - else // smaller buffer - return false; - i++; addr++; - } - - buf[i] = '\0'; - return true; + while (c != '\0') { + if (ps_pread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK) { + return false; + } + if (i < size - 1) { + buf[i] = c; + } else { + // smaller buffer + return false; + } + i++; addr++; + } + buf[i] = '\0'; + return true; } +#ifdef __APPLE__ +#define USE_SHARED_SPACES_SYM "_UseSharedSpaces" +// mangled name of Arguments::SharedArchivePath +#define SHARED_ARCHIVE_PATH_SYM "_ZN9Arguments17SharedArchivePathE" +#else #define USE_SHARED_SPACES_SYM "UseSharedSpaces" // mangled name of Arguments::SharedArchivePath -#define SHARED_ARCHIVE_PATH_SYM "_ZN9Arguments17SharedArchivePathE" +#define SHARED_ARCHIVE_PATH_SYM "__ZN9Arguments17SharedArchivePathE" +#endif // __APPLE_ static bool init_classsharing_workaround(struct ps_prochandle* ph) { - lib_info* lib = ph->libs; - while (lib != NULL) { - // we are iterating over shared objects from the core dump. look for - // libjvm[_g].so. - const char *jvm_name = 0; - if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0 || - (jvm_name = strstr(lib->name, "/libjvm_g.so")) != 0) { - char classes_jsa[PATH_MAX]; - struct FileMapHeader header; - size_t n = 0; - int fd = -1, m = 0; - uintptr_t base = 0, useSharedSpacesAddr = 0; - uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0; - jboolean useSharedSpaces = 0; - - memset(classes_jsa, 0, sizeof(classes_jsa)); - jvm_name = lib->name; - useSharedSpacesAddr = lookup_symbol(ph, jvm_name, USE_SHARED_SPACES_SYM); - if (useSharedSpacesAddr == 0) { - print_debug("can't lookup 'UseSharedSpaces' flag\n"); - return false; - } + int m; + size_t n; + lib_info* lib = ph->libs; + while (lib != NULL) { + // we are iterating over shared objects from the core dump. look for + // libjvm[_g].so. + const char *jvm_name = 0; +#ifdef __APPLE__ + if ((jvm_name = strstr(lib->name, "/libjvm.dylib")) != 0 || + (jvm_name = strstr(lib->name, "/libjvm_g.dylib")) != 0) +#else + if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0 || + (jvm_name = strstr(lib->name, "/libjvm_g.so")) != 0) +#endif // __APPLE__ + { + char classes_jsa[PATH_MAX]; + struct FileMapHeader header; + int fd = -1; + uintptr_t base = 0, useSharedSpacesAddr = 0; + uintptr_t sharedArchivePathAddrAddr = 0, sharedArchivePathAddr = 0; + jboolean useSharedSpaces = 0; - // Hotspot vm types are not exported to build this library. So - // using equivalent type jboolean to read the value of - // UseSharedSpaces which is same as hotspot type "bool". - if (read_jboolean(ph, useSharedSpacesAddr, &useSharedSpaces) != true) { - print_debug("can't read the value of 'UseSharedSpaces' flag\n"); - return false; - } + memset(classes_jsa, 0, sizeof(classes_jsa)); + jvm_name = lib->name; + useSharedSpacesAddr = lookup_symbol(ph, jvm_name, USE_SHARED_SPACES_SYM); + if (useSharedSpacesAddr == 0) { + print_debug("can't lookup 'UseSharedSpaces' flag\n"); + return false; + } - if ((int)useSharedSpaces == 0) { - print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n"); - return true; - } + // Hotspot vm types are not exported to build this library. So + // using equivalent type jboolean to read the value of + // UseSharedSpaces which is same as hotspot type "bool". + if (read_jboolean(ph, useSharedSpacesAddr, &useSharedSpaces) != true) { + print_debug("can't read the value of 'UseSharedSpaces' flag\n"); + return false; + } - sharedArchivePathAddrAddr = lookup_symbol(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM); - if (sharedArchivePathAddrAddr == 0) { - print_debug("can't lookup shared archive path symbol\n"); - return false; - } + if ((int)useSharedSpaces == 0) { + print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n"); + return true; + } - if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) { - print_debug("can't read shared archive path pointer\n"); - return false; - } + sharedArchivePathAddrAddr = lookup_symbol(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM); + if (sharedArchivePathAddrAddr == 0) { + print_debug("can't lookup shared archive path symbol\n"); + return false; + } - if (read_string(ph, sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) { - print_debug("can't read shared archive path value\n"); - return false; - } + if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) { + print_debug("can't read shared archive path pointer\n"); + return false; + } - print_debug("looking for %s\n", classes_jsa); - // open the class sharing archive file - fd = pathmap_open(classes_jsa); - if (fd < 0) { - print_debug("can't open %s!\n", classes_jsa); - ph->core->classes_jsa_fd = -1; - return false; - } else { - print_debug("opened %s\n", classes_jsa); - } + if (read_string(ph, sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) { + print_debug("can't read shared archive path value\n"); + return false; + } - // read FileMapHeader from the file - memset(&header, 0, sizeof(struct FileMapHeader)); - if ((n = read(fd, &header, sizeof(struct FileMapHeader))) - != sizeof(struct FileMapHeader)) { - print_debug("can't read shared archive file map header from %s\n", classes_jsa); - close(fd); - return false; - } + print_debug("looking for %s\n", classes_jsa); + // open the class sharing archive file + fd = pathmap_open(classes_jsa); + if (fd < 0) { + print_debug("can't open %s!\n", classes_jsa); + ph->core->classes_jsa_fd = -1; + return false; + } else { + print_debug("opened %s\n", classes_jsa); + } - // check file magic - if (header._magic != 0xf00baba2) { - print_debug("%s has bad shared archive file magic number 0x%x, expecing 0xf00baba2\n", - classes_jsa, header._magic); - close(fd); - return false; - } + // read FileMapHeader from the file + memset(&header, 0, sizeof(struct FileMapHeader)); + if ((n = read(fd, &header, sizeof(struct FileMapHeader))) + != sizeof(struct FileMapHeader)) { + print_debug("can't read shared archive file map header from %s\n", classes_jsa); + close(fd); + return false; + } - // check version - if (header._version != CURRENT_ARCHIVE_VERSION) { - print_debug("%s has wrong shared archive file version %d, expecting %d\n", - classes_jsa, header._version, CURRENT_ARCHIVE_VERSION); - close(fd); - return false; - } + // check file magic + if (header._magic != 0xf00baba2) { + print_debug("%s has bad shared archive file magic number 0x%x, expecing 0xf00baba2\n", + classes_jsa, header._magic); + close(fd); + return false; + } + + // check version + if (header._version != CURRENT_ARCHIVE_VERSION) { + print_debug("%s has wrong shared archive file version %d, expecting %d\n", + classes_jsa, header._version, CURRENT_ARCHIVE_VERSION); + close(fd); + return false; + } - ph->core->classes_jsa_fd = fd; - // add read-only maps from classes[_g].jsa to the list of maps - for (m = 0; m < NUM_SHARED_MAPS; m++) { - if (header._space[m]._read_only) { - base = (uintptr_t) header._space[m]._base; - // no need to worry about the fractional pages at-the-end. - // possible fractional pages are handled by core_read_data. - add_class_share_map_info(ph, (off_t) header._space[m]._file_offset, - base, (size_t) header._space[m]._used); - print_debug("added a share archive map at 0x%lx\n", base); - } - } - return true; + ph->core->classes_jsa_fd = fd; + // add read-only maps from classes[_g].jsa to the list of maps + for (m = 0; m < NUM_SHARED_MAPS; m++) { + if (header._space[m]._read_only) { + base = (uintptr_t) header._space[m]._base; + // no need to worry about the fractional pages at-the-end. + // possible fractional pages are handled by core_read_data. + add_class_share_map_info(ph, (off_t) header._space[m]._file_offset, + base, (size_t) header._space[m]._used); + print_debug("added a share archive map at 0x%lx\n", base); + } } - lib = lib->next; - } - return true; + return true; + } + lib = lib->next; + } + return true; } - //--------------------------------------------------------------------------- // functions to handle map_info @@ -397,54 +414,57 @@ // callback for sorting the array of map_info pointers. static int core_cmp_mapping(const void *lhsp, const void *rhsp) { - const map_info *lhs = *((const map_info **)lhsp); - const map_info *rhs = *((const map_info **)rhsp); + const map_info *lhs = *((const map_info **)lhsp); + const map_info *rhs = *((const map_info **)rhsp); - if (lhs->vaddr == rhs->vaddr) - return (0); + if (lhs->vaddr == rhs->vaddr) { + return (0); + } - return (lhs->vaddr < rhs->vaddr ? -1 : 1); + return (lhs->vaddr < rhs->vaddr ? -1 : 1); } // we sort map_info by starting virtual address so that we can do // binary search to read from an address. static bool sort_map_array(struct ps_prochandle* ph) { - size_t num_maps = ph->core->num_maps; - map_info* map = ph->core->maps; - int i = 0; + size_t num_maps = ph->core->num_maps; + map_info* map = ph->core->maps; + int i = 0; - // allocate map_array - map_info** array; - if ( (array = (map_info**) malloc(sizeof(map_info*) * num_maps)) == NULL) { - print_debug("can't allocate memory for map array\n"); - return false; - } + // allocate map_array + map_info** array; + if ( (array = (map_info**) malloc(sizeof(map_info*) * num_maps)) == NULL) { + print_debug("can't allocate memory for map array\n"); + return false; + } - // add maps to array - while (map) { - array[i] = map; - i++; - map = map->next; - } + // add maps to array + while (map) { + array[i] = map; + i++; + map = map->next; + } - // sort is called twice. If this is second time, clear map array - if (ph->core->map_array) free(ph->core->map_array); - ph->core->map_array = array; - // sort the map_info array by base virtual address. - qsort(ph->core->map_array, ph->core->num_maps, sizeof (map_info*), - core_cmp_mapping); + // sort is called twice. If this is second time, clear map array + if (ph->core->map_array) { + free(ph->core->map_array); + } + ph->core->map_array = array; + // sort the map_info array by base virtual address. + qsort(ph->core->map_array, ph->core->num_maps, sizeof (map_info*), + core_cmp_mapping); - // print map - if (is_debug()) { - int j = 0; - print_debug("---- sorted virtual address map ----\n"); - for (j = 0; j < ph->core->num_maps; j++) { - print_debug("base = 0x%lx\tsize = %d\n", ph->core->map_array[j]->vaddr, - ph->core->map_array[j]->memsz); - } - } + // print map + if (is_debug()) { + int j = 0; + print_debug("---- sorted virtual address map ----\n"); + for (j = 0; j < ph->core->num_maps; j++) { + print_debug("base = 0x%lx\tsize = %d\n", ph->core->map_array[j]->vaddr, + ph->core->map_array[j]->memsz); + } + } - return true; + return true; } #ifndef MIN @@ -461,16 +481,18 @@ off_t off; int fd; - if (mp == NULL) + if (mp == NULL) { break; /* No mapping for this address */ + } fd = mp->fd; mapoff = addr - mp->vaddr; len = MIN(resid, mp->memsz - mapoff); off = mp->offset + mapoff; - if ((len = pread(fd, buf, len, off)) <= 0) + if ((len = pread(fd, buf, len, off)) <= 0) { break; + } resid -= len; addr += len; @@ -507,8 +529,8 @@ static bool core_get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) { - // for core we have cached the lwp regs from NOTE section - thread_info* thr = ph->threads; + // for core we have cached the lwp regs after segment parsed + sa_thread_info* thr = ph->threads; while (thr) { if (thr->lwp_id == lwp_id) { memcpy(regs, &thr->regs, sizeof(struct reg)); @@ -519,7 +541,7 @@ return false; } -static bool core_get_lwp_info(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo) { +static bool core_get_lwp_info(struct ps_prochandle *ph, lwpid_t id, void *info) { print_debug("core_get_lwp_info not implemented\n"); return false; } @@ -532,12 +554,451 @@ .get_lwp_info= core_get_lwp_info }; -// read regs and create thread from NT_PRSTATUS entries from core file +// from this point, mainly two blocks divided by def __APPLE__ +// one for Macosx, the other for regular Bsd + +#ifdef __APPLE__ + +void print_thread(sa_thread_info *threadinfo) { + print_debug("thread added: %d\n", threadinfo->lwp_id); + print_debug("registers:\n"); + print_debug(" r_r15: 0x%" PRIx64 "\n", threadinfo->regs.r_r15); + print_debug(" r_r14: 0x%" PRIx64 "\n", threadinfo->regs.r_r14); + print_debug(" r_r13: 0x%" PRIx64 "\n", threadinfo->regs.r_r13); + print_debug(" r_r12: 0x%" PRIx64 "\n", threadinfo->regs.r_r12); + print_debug(" r_r11: 0x%" PRIx64 "\n", threadinfo->regs.r_r11); + print_debug(" r_r10: 0x%" PRIx64 "\n", threadinfo->regs.r_r10); + print_debug(" r_r9: 0x%" PRIx64 "\n", threadinfo->regs.r_r9); + print_debug(" r_r8: 0x%" PRIx64 "\n", threadinfo->regs.r_r8); + print_debug(" r_rdi: 0x%" PRIx64 "\n", threadinfo->regs.r_rdi); + print_debug(" r_rsi: 0x%" PRIx64 "\n", threadinfo->regs.r_rsi); + print_debug(" r_rbp: 0x%" PRIx64 "\n", threadinfo->regs.r_rbp); + print_debug(" r_rbx: 0x%" PRIx64 "\n", threadinfo->regs.r_rbx); + print_debug(" r_rdx: 0x%" PRIx64 "\n", threadinfo->regs.r_rdx); + print_debug(" r_rcx: 0x%" PRIx64 "\n", threadinfo->regs.r_rcx); + print_debug(" r_rax: 0x%" PRIx64 "\n", threadinfo->regs.r_rax); + print_debug(" r_fs: 0x%" PRIx32 "\n", threadinfo->regs.r_fs); + print_debug(" r_gs: 0x%" PRIx32 "\n", threadinfo->regs.r_gs); + print_debug(" r_rip 0x%" PRIx64 "\n", threadinfo->regs.r_rip); + print_debug(" r_cs: 0x%" PRIx64 "\n", threadinfo->regs.r_cs); + print_debug(" r_rsp: 0x%" PRIx64 "\n", threadinfo->regs.r_rsp); + print_debug(" r_rflags: 0x%" PRIx64 "\n", threadinfo->regs.r_rflags); +} + +// read all segments64 commands from core file +// read all thread commands from core file +static bool read_core_segments(struct ps_prochandle* ph) { + int i = 0; + int num_threads = 0; + int fd = ph->core->core_fd; + off_t offset = 0; + mach_header_64 fhead; + load_command lcmd; + segment_command_64 segcmd; + // thread_command thrcmd; + + lseek(fd, offset, SEEK_SET); + if(read(fd, (void *)&fhead, sizeof(mach_header_64)) != sizeof(mach_header_64)) { + goto err; + } + print_debug("total commands: %d\n", fhead.ncmds); + offset += sizeof(mach_header_64); + for (i = 0; i < fhead.ncmds; i++) { + lseek(fd, offset, SEEK_SET); + if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) { + goto err; + } + offset += lcmd.cmdsize; // next command position + if (lcmd.cmd == LC_SEGMENT_64) { + lseek(fd, -sizeof(load_command), SEEK_CUR); + if (read(fd, (void *)&segcmd, sizeof(segment_command_64)) != sizeof(segment_command_64)) { + print_debug("failed to read LC_SEGMENT_64 i = %d!\n", i); + goto err; + } + if (add_map_info(ph, fd, segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize) == NULL) { + print_debug("Failed to add map_info at i = %d\n", i); + goto err; + } + print_debug("segment added: %" PRIu64 " 0x%" PRIx64 " %d\n", + segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize); + } else if (lcmd.cmd == LC_THREAD || lcmd.cmd == LC_UNIXTHREAD) { + typedef struct thread_fc { + uint32_t flavor; + uint32_t count; + } thread_fc; + thread_fc fc; + uint32_t size = sizeof(load_command); + while (size < lcmd.cmdsize) { + if (read(fd, (void *)&fc, sizeof(thread_fc)) != sizeof(thread_fc)) { + printf("Reading flavor, count failed.\n"); + goto err; + } + size += sizeof(thread_fc); + if (fc.flavor == x86_THREAD_STATE) { + x86_thread_state_t thrstate; + if (read(fd, (void *)&thrstate, sizeof(x86_thread_state_t)) != sizeof(x86_thread_state_t)) { + printf("Reading flavor, count failed.\n"); + goto err; + } + size += sizeof(x86_thread_state_t); + // create thread info list, update lwp_id later + sa_thread_info* newthr = add_thread_info(ph, (pthread_t) -1, (lwpid_t) num_threads++); + if (newthr == NULL) { + printf("create thread_info failed\n"); + goto err; + } + + // note __DARWIN_UNIX03 depengs on other definitions +#if __DARWIN_UNIX03 +#define get_register_v(regst, regname) \ + regst.uts.ts64.__##regname +#else +#define get_register_v(regst, regname) \ + regst.uts.ts64.##regname +#endif // __DARWIN_UNIX03 + newthr->regs.r_rax = get_register_v(thrstate, rax); + newthr->regs.r_rbx = get_register_v(thrstate, rbx); + newthr->regs.r_rcx = get_register_v(thrstate, rcx); + newthr->regs.r_rdx = get_register_v(thrstate, rdx); + newthr->regs.r_rdi = get_register_v(thrstate, rdi); + newthr->regs.r_rsi = get_register_v(thrstate, rsi); + newthr->regs.r_rbp = get_register_v(thrstate, rbp); + newthr->regs.r_rsp = get_register_v(thrstate, rsp); + newthr->regs.r_r8 = get_register_v(thrstate, r8); + newthr->regs.r_r9 = get_register_v(thrstate, r9); + newthr->regs.r_r10 = get_register_v(thrstate, r10); + newthr->regs.r_r11 = get_register_v(thrstate, r11); + newthr->regs.r_r12 = get_register_v(thrstate, r12); + newthr->regs.r_r13 = get_register_v(thrstate, r13); + newthr->regs.r_r14 = get_register_v(thrstate, r14); + newthr->regs.r_r15 = get_register_v(thrstate, r15); + newthr->regs.r_rip = get_register_v(thrstate, rip); + newthr->regs.r_rflags = get_register_v(thrstate, rflags); + newthr->regs.r_cs = get_register_v(thrstate, cs); + newthr->regs.r_fs = get_register_v(thrstate, fs); + newthr->regs.r_gs = get_register_v(thrstate, gs); + print_thread(newthr); + } else if (fc.flavor == x86_FLOAT_STATE) { + x86_float_state_t flstate; + if (read(fd, (void *)&flstate, sizeof(x86_float_state_t)) != sizeof(x86_float_state_t)) { + print_debug("Reading flavor, count failed.\n"); + goto err; + } + size += sizeof(x86_float_state_t); + } else if (fc.flavor == x86_EXCEPTION_STATE) { + x86_exception_state_t excpstate; + if (read(fd, (void *)&excpstate, sizeof(x86_exception_state_t)) != sizeof(x86_exception_state_t)) { + printf("Reading flavor, count failed.\n"); + goto err; + } + size += sizeof(x86_exception_state_t); + } + } + } + } + return true; +err: + return false; +} + +/**local function **/ +bool exists(const char *fname) +{ + int fd; + if ((fd = open(fname, O_RDONLY)) > 0) { + close(fd); + return true; + } + return false; +} + +// we check: 1. lib +// 2. lib/server +// 3. jre/lib +// 4. jre/lib/server +// from: 1. exe path +// 2. JAVA_HOME +// 3. DYLD_LIBRARY_PATH +static bool get_real_path(struct ps_prochandle* ph, char *rpath) { + /** check if they exist in JAVA ***/ + char* execname = ph->core->exec_path; + char filepath[4096]; + char* filename = strrchr(rpath, '/'); // like /libjvm.dylib + if (filename == NULL) { + return false; + } + + char* posbin = strstr(execname, "/bin/java"); + if (posbin != NULL) { + memcpy(filepath, execname, posbin - execname); // not include trailing '/' + filepath[posbin - execname] = '\0'; + } else { + char* java_home = getenv("JAVA_HOME"); + if (java_home != NULL) { + strcpy(filepath, java_home); + } else { + char* dyldpath = getenv("DYLD_LIBRARY_PATH"); + char* dypath = strtok(dyldpath, ":"); + while (dypath != NULL) { + strcpy(filepath, dypath); + strcat(filepath, filename); + if (exists(filepath)) { + strcpy(rpath, filepath); + return true; + } + dypath = strtok(dyldpath, ":"); + } + // not found + return false; + } + } + // for exec and java_home, jdkpath now is filepath + size_t filepath_base_size = strlen(filepath); + + // first try /lib/ and /lib/server + strcat(filepath, "/lib"); + strcat(filepath, filename); + if (exists(filepath)) { + strcpy(rpath, filepath); + return true; + } + char* pos = strstr(filepath, filename); // like /libjvm.dylib + *pos = '\0'; + strcat(filepath, "/server"); + strcat(filepath, filename); + if (exists(filepath)) { + strcpy(rpath, filepath); + return true; + } + + // then try /jre/lib/ and /jre/lib/server + filepath[filepath_base_size] = '\0'; + strcat(filepath, "/jre/lib"); + strcat(filepath, filename); + if (exists(filepath)) { + strcpy(rpath, filepath); + return true; + } + pos = strstr(filepath, filename); + *pos = '\0'; + strcat(filepath, "/server"); + strcat(filepath, filename); + if (exists(filepath)) { + strcpy(rpath, filepath); + return true; + } + + return false; +} + +static bool read_shared_lib_info(struct ps_prochandle* ph) { + static int pagesize = 0; + int fd = ph->core->core_fd; + int i = 0, j; + uint32_t v; + mach_header_64 header; // used to check if a file header in segment + load_command lcmd; + dylib_command dylibcmd; + + char name[BUF_SIZE]; // use to store name + + if (pagesize == 0) { + pagesize = getpagesize(); + print_debug("page size is %d\n", pagesize); + } + for (j = 0; j < ph->core->num_maps; j++) { + map_info *iter = ph->core->map_array[j]; // head + off_t fpos = iter->offset; + if (iter->fd != fd) { + // only search core file! + continue; + } + print_debug("map_info %d: vmaddr = 0x%016" PRIx64 " fileoff = %" PRIu64 " vmsize = %" PRIu64 "\n", + j, iter->vaddr, iter->offset, iter->memsz); + lseek(fd, fpos, SEEK_SET); + // we assume .dylib loaded at segment address --- which is true for JVM libraries + // multiple files may be loaded in one segment. + // if first word is not a magic word, means this segment does not contain lib file. + if (read(fd, (void *)&v, sizeof(uint32_t)) == sizeof(uint32_t)) { + if (v != MH_MAGIC_64) { + continue; + } + } else { + // may be encountered last map, which is not readable + continue; + } + while (ltell(fd) - iter->offset < iter->memsz) { + lseek(fd, fpos, SEEK_SET); + if (read(fd, (void *)&v, sizeof(uint32_t)) != sizeof(uint32_t)) { + break; + } + if (v != MH_MAGIC_64) { + fpos = (ltell(fd) + pagesize -1)/pagesize * pagesize; + continue; + } + lseek(fd, -sizeof(uint32_t), SEEK_CUR); + // this is the file begining to core file. + if (read(fd, (void *)&header, sizeof(mach_header_64)) != sizeof(mach_header_64)) { + goto err; + } + fpos = ltell(fd); + + // found a mach-o file in this segment + for (i = 0; i < header.ncmds; i++) { + // read commands in this "file" + // LC_ID_DYLIB is the file itself for a .dylib + lseek(fd, fpos, SEEK_SET); + if (read(fd, (void *)&lcmd, sizeof(load_command)) != sizeof(load_command)) { + return false; // error + } + fpos += lcmd.cmdsize; // next command position + // make sure still within seg size. + if (fpos - lcmd.cmdsize - iter->offset > iter->memsz) { + print_debug("Warning: out of segement limit: %ld \n", fpos - lcmd.cmdsize - iter->offset); + break; // no need to iterate all commands + } + if (lcmd.cmd == LC_ID_DYLIB) { + lseek(fd, -sizeof(load_command), SEEK_CUR); + if (read(fd, (void *)&dylibcmd, sizeof(dylib_command)) != sizeof(dylib_command)) { + return false; + } + /**** name stored at dylib_command.dylib.name.offset, is a C string */ + lseek(fd, dylibcmd.dylib.name.offset - sizeof(dylib_command), SEEK_CUR); + int j = 0; + while (j < BUF_SIZE) { + read(fd, (void *)(name + j), sizeof(char)); + if (name[j] == '\0') break; + j++; + } + print_debug("%s\n", name); + // changed name from @rpath/xxxx.dylib to real path + if (strrchr(name, '@')) { + get_real_path(ph, name); + print_debug("get_real_path returned: %s\n", name); + } + add_lib_info(ph, name, iter->vaddr); + break; + } + } + // done with the file, advanced to next page to search more files + fpos = (ltell(fd) + pagesize - 1) / pagesize * pagesize; + } + } + return true; +err: + return false; +} + +bool read_macho64_header(int fd, mach_header_64* core_header) { + bool is_macho = false; + if (fd < 0) return false; + off_t pos = ltell(fd); + lseek(fd, 0, SEEK_SET); + if (read(fd, (void *)core_header, sizeof(mach_header_64)) != sizeof(mach_header_64)) { + is_macho = false; + } else { + is_macho = (core_header->magic == MH_MAGIC_64 || core_header->magic == MH_CIGAM_64); + } + lseek(fd, pos, SEEK_SET); + return is_macho; +} + +// the one and only one exposed stuff from this file +struct ps_prochandle* Pgrab_core(const char* exec_file, const char* core_file) { + mach_header_64 core_header; + mach_header_64 exec_header; + + struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle)); + if (ph == NULL) { + print_debug("cant allocate ps_prochandle\n"); + return NULL; + } + + if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) { + free(ph); + print_debug("can't allocate ps_prochandle\n"); + return NULL; + } + + // initialize ph + ph->ops = &core_ops; + ph->core->core_fd = -1; + ph->core->exec_fd = -1; + ph->core->interp_fd = -1; + + print_debug("exec: %s core: %s", exec_file, core_file); + + strncpy(ph->core->exec_path, exec_file, sizeof(ph->core->exec_path)); + + // open the core file + if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) { + print_error("can't open core file\n"); + goto err; + } + + // read core file header + if (read_macho64_header(ph->core->core_fd, &core_header) != true || core_header.filetype != MH_CORE) { + print_debug("core file is not a valid Mach-O file\n"); + goto err; + } + + if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) { + print_error("can't open executable file\n"); + goto err; + } + + if (read_macho64_header(ph->core->exec_fd, &exec_header) != true || + exec_header.filetype != MH_EXECUTE) { + print_error("executable file is not a valid Mach-O file\n"); + goto err; + } + + // process core file segments + if (read_core_segments(ph) != true) { + print_error("failed to read core segments\n"); + goto err; + } + + // allocate and sort maps into map_array, we need to do this + // here because read_shared_lib_info needs to read from debuggee + // address space + if (sort_map_array(ph) != true) { + print_error("failed to sort segment map array\n"); + goto err; + } + + if (read_shared_lib_info(ph) != true) { + print_error("failed to read libraries\n"); + goto err; + } + + // sort again because we have added more mappings from shared objects + if (sort_map_array(ph) != true) { + print_error("failed to sort segment map array\n"); + goto err; + } + + if (init_classsharing_workaround(ph) != true) { + print_error("failed to workaround classshareing\n"); + goto err; + } + + print_debug("Leave Pgrab_core\n"); + return ph; + +err: + Prelease(ph); + return NULL; +} + +#else // __APPLE__ (none macosx) + +// read regs and create thread from core file static bool core_handle_prstatus(struct ps_prochandle* ph, const char* buf, size_t nbytes) { // we have to read prstatus_t from buf // assert(nbytes == sizeof(prstaus_t), "size mismatch on prstatus_t"); prstatus_t* prstat = (prstatus_t*) buf; - thread_info* newthr; + sa_thread_info* newthr; print_debug("got integer regset for lwp %d\n", prstat->pr_pid); // we set pthread_t to -1 for core dump if((newthr = add_thread_info(ph, (pthread_t) -1, prstat->pr_pid)) == NULL) @@ -632,8 +1093,9 @@ notep->n_type, notep->n_descsz); if (notep->n_type == NT_PRSTATUS) { - if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true) + if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true) { return false; + } } p = descdata + ROUNDUP(notep->n_descsz, 4); } @@ -681,7 +1143,9 @@ for (core_php = phbuf, i = 0; i < core_ehdr->e_phnum; i++) { switch (core_php->p_type) { case PT_NOTE: - if (core_handle_note(ph, core_php) != true) goto err; + if (core_handle_note(ph, core_php) != true) { + goto err; + } break; case PT_LOAD: { @@ -800,7 +1264,6 @@ return false; } - #define FIRST_LINK_MAP_OFFSET offsetof(struct r_debug, r_map) #define LD_BASE_OFFSET offsetof(struct r_debug, r_ldbase) #define LINK_MAP_ADDR_OFFSET offsetof(struct link_map, l_addr) @@ -810,213 +1273,218 @@ // read shared library info from runtime linker's data structures. // This work is done by librtlb_db in Solaris static bool read_shared_lib_info(struct ps_prochandle* ph) { - uintptr_t addr = ph->core->dynamic_addr; - uintptr_t debug_base; - uintptr_t first_link_map_addr; - uintptr_t ld_base_addr; - uintptr_t link_map_addr; - uintptr_t lib_base_diff; - uintptr_t lib_base; - uintptr_t lib_name_addr; - char lib_name[BUF_SIZE]; - ELF_DYN dyn; - ELF_EHDR elf_ehdr; - int lib_fd; + uintptr_t addr = ph->core->dynamic_addr; + uintptr_t debug_base; + uintptr_t first_link_map_addr; + uintptr_t ld_base_addr; + uintptr_t link_map_addr; + uintptr_t lib_base_diff; + uintptr_t lib_base; + uintptr_t lib_name_addr; + char lib_name[BUF_SIZE]; + ELF_DYN dyn; + ELF_EHDR elf_ehdr; + int lib_fd; - // _DYNAMIC has information of the form - // [tag] [data] [tag] [data] ..... - // Both tag and data are pointer sized. - // We look for dynamic info with DT_DEBUG. This has shared object info. - // refer to struct r_debug in link.h + // _DYNAMIC has information of the form + // [tag] [data] [tag] [data] ..... + // Both tag and data are pointer sized. + // We look for dynamic info with DT_DEBUG. This has shared object info. + // refer to struct r_debug in link.h - dyn.d_tag = DT_NULL; - while (dyn.d_tag != DT_DEBUG) { - if (ps_pread(ph, (psaddr_t) addr, &dyn, sizeof(ELF_DYN)) != PS_OK) { - print_debug("can't read debug info from _DYNAMIC\n"); - return false; - } - addr += sizeof(ELF_DYN); - } + dyn.d_tag = DT_NULL; + while (dyn.d_tag != DT_DEBUG) { + if (ps_pread(ph, (psaddr_t) addr, &dyn, sizeof(ELF_DYN)) != PS_OK) { + print_debug("can't read debug info from _DYNAMIC\n"); + return false; + } + addr += sizeof(ELF_DYN); + } - // we have got Dyn entry with DT_DEBUG - debug_base = dyn.d_un.d_ptr; - // at debug_base we have struct r_debug. This has first link map in r_map field - if (ps_pread(ph, (psaddr_t) debug_base + FIRST_LINK_MAP_OFFSET, - &first_link_map_addr, sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read first link map address\n"); - return false; - } + // we have got Dyn entry with DT_DEBUG + debug_base = dyn.d_un.d_ptr; + // at debug_base we have struct r_debug. This has first link map in r_map field + if (ps_pread(ph, (psaddr_t) debug_base + FIRST_LINK_MAP_OFFSET, + &first_link_map_addr, sizeof(uintptr_t)) != PS_OK) { + print_debug("can't read first link map address\n"); + return false; + } - // read ld_base address from struct r_debug - // XXX: There is no r_ldbase member on BSD -/* - if (ps_pread(ph, (psaddr_t) debug_base + LD_BASE_OFFSET, &ld_base_addr, - sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read ld base address\n"); - return false; - } - ph->core->ld_base_addr = ld_base_addr; -*/ - ph->core->ld_base_addr = 0; + // read ld_base address from struct r_debug + // XXX: There is no r_ldbase member on BSD + /* + if (ps_pread(ph, (psaddr_t) debug_base + LD_BASE_OFFSET, &ld_base_addr, + sizeof(uintptr_t)) != PS_OK) { + print_debug("can't read ld base address\n"); + return false; + } + ph->core->ld_base_addr = ld_base_addr; + */ + ph->core->ld_base_addr = 0; - print_debug("interpreter base address is 0x%lx\n", ld_base_addr); + print_debug("interpreter base address is 0x%lx\n", ld_base_addr); - // now read segments from interp (i.e ld-elf.so.1) - if (read_interp_segments(ph) != true) - return false; + // now read segments from interp (i.e ld-elf.so.1) + if (read_interp_segments(ph) != true) + return false; - // after adding interpreter (ld.so) mappings sort again - if (sort_map_array(ph) != true) - return false; + // after adding interpreter (ld.so) mappings sort again + if (sort_map_array(ph) != true) + return false; - print_debug("first link map is at 0x%lx\n", first_link_map_addr); + print_debug("first link map is at 0x%lx\n", first_link_map_addr); - link_map_addr = first_link_map_addr; - while (link_map_addr != 0) { - // read library base address of the .so. Note that even though calls - // link_map->l_addr as "base address", this is * not * really base virtual - // address of the shared object. This is actually the difference b/w the virtual - // address mentioned in shared object and the actual virtual base where runtime - // linker loaded it. We use "base diff" in read_lib_segments call below. + link_map_addr = first_link_map_addr; + while (link_map_addr != 0) { + // read library base address of the .so. Note that even though calls + // link_map->l_addr as "base address", this is * not * really base virtual + // address of the shared object. This is actually the difference b/w the virtual + // address mentioned in shared object and the actual virtual base where runtime + // linker loaded it. We use "base diff" in read_lib_segments call below. - if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_ADDR_OFFSET, - &lib_base_diff, sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read shared object base address diff\n"); - return false; - } + if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_ADDR_OFFSET, + &lib_base_diff, sizeof(uintptr_t)) != PS_OK) { + print_debug("can't read shared object base address diff\n"); + return false; + } - // read address of the name - if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NAME_OFFSET, - &lib_name_addr, sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read address of shared object name\n"); - return false; - } + // read address of the name + if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NAME_OFFSET, + &lib_name_addr, sizeof(uintptr_t)) != PS_OK) { + print_debug("can't read address of shared object name\n"); + return false; + } - // read name of the shared object - if (read_string(ph, (uintptr_t) lib_name_addr, lib_name, sizeof(lib_name)) != true) { - print_debug("can't read shared object name\n"); - return false; - } + // read name of the shared object + if (read_string(ph, (uintptr_t) lib_name_addr, lib_name, sizeof(lib_name)) != true) { + print_debug("can't read shared object name\n"); + return false; + } - if (lib_name[0] != '\0') { - // ignore empty lib names - lib_fd = pathmap_open(lib_name); + if (lib_name[0] != '\0') { + // ignore empty lib names + lib_fd = pathmap_open(lib_name); - if (lib_fd < 0) { - print_debug("can't open shared object %s\n", lib_name); - // continue with other libraries... - } else { - if (read_elf_header(lib_fd, &elf_ehdr)) { - lib_base = lib_base_diff + find_base_address(lib_fd, &elf_ehdr); - print_debug("reading library %s @ 0x%lx [ 0x%lx ]\n", - lib_name, lib_base, lib_base_diff); - // while adding library mappings we need to use "base difference". - if (! read_lib_segments(ph, lib_fd, &elf_ehdr, lib_base_diff)) { - print_debug("can't read shared object's segments\n"); - close(lib_fd); - return false; - } - add_lib_info_fd(ph, lib_name, lib_fd, lib_base); - // Map info is added for the library (lib_name) so - // we need to re-sort it before calling the p_pdread. - if (sort_map_array(ph) != true) - return false; - } else { - print_debug("can't read ELF header for shared object %s\n", lib_name); - close(lib_fd); - // continue with other libraries... - } - } + if (lib_fd < 0) { + print_debug("can't open shared object %s\n", lib_name); + // continue with other libraries... + } else { + if (read_elf_header(lib_fd, &elf_ehdr)) { + lib_base = lib_base_diff + find_base_address(lib_fd, &elf_ehdr); + print_debug("reading library %s @ 0x%lx [ 0x%lx ]\n", + lib_name, lib_base, lib_base_diff); + // while adding library mappings we need to use "base difference". + if (! read_lib_segments(ph, lib_fd, &elf_ehdr, lib_base_diff)) { + print_debug("can't read shared object's segments\n"); + close(lib_fd); + return false; + } + add_lib_info_fd(ph, lib_name, lib_fd, lib_base); + // Map info is added for the library (lib_name) so + // we need to re-sort it before calling the p_pdread. + if (sort_map_array(ph) != true) + return false; + } else { + print_debug("can't read ELF header for shared object %s\n", lib_name); + close(lib_fd); + // continue with other libraries... + } } + } - // read next link_map address - if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NEXT_OFFSET, - &link_map_addr, sizeof(uintptr_t)) != PS_OK) { - print_debug("can't read next link in link_map\n"); - return false; - } - } + // read next link_map address + if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NEXT_OFFSET, + &link_map_addr, sizeof(uintptr_t)) != PS_OK) { + print_debug("can't read next link in link_map\n"); + return false; + } + } - return true; + return true; } // the one and only one exposed stuff from this file struct ps_prochandle* Pgrab_core(const char* exec_file, const char* core_file) { - ELF_EHDR core_ehdr; - ELF_EHDR exec_ehdr; + ELF_EHDR core_ehdr; + ELF_EHDR exec_ehdr; - struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle)); - if (ph == NULL) { - print_debug("can't allocate ps_prochandle\n"); - return NULL; - } + struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle)); + if (ph == NULL) { + print_debug("cant allocate ps_prochandle\n"); + return NULL; + } - if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) { - free(ph); - print_debug("can't allocate ps_prochandle\n"); - return NULL; - } + if ((ph->core = (struct core_data*) calloc(1, sizeof(struct core_data))) == NULL) { + free(ph); + print_debug("can't allocate ps_prochandle\n"); + return NULL; + } - // initialize ph - ph->ops = &core_ops; - ph->core->core_fd = -1; - ph->core->exec_fd = -1; - ph->core->interp_fd = -1; + // initialize ph + ph->ops = &core_ops; + ph->core->core_fd = -1; + ph->core->exec_fd = -1; + ph->core->interp_fd = -1; + + print_debug("exec: %s core: %s", exec_file, core_file); - // open the core file - if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) { - print_debug("can't open core file\n"); - goto err; - } + // open the core file + if ((ph->core->core_fd = open(core_file, O_RDONLY)) < 0) { + print_debug("can't open core file\n"); + goto err; + } - // read core file ELF header - if (read_elf_header(ph->core->core_fd, &core_ehdr) != true || core_ehdr.e_type != ET_CORE) { - print_debug("core file is not a valid ELF ET_CORE file\n"); - goto err; - } + // read core file ELF header + if (read_elf_header(ph->core->core_fd, &core_ehdr) != true || core_ehdr.e_type != ET_CORE) { + print_debug("core file is not a valid ELF ET_CORE file\n"); + goto err; + } - if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) { - print_debug("can't open executable file\n"); - goto err; - } + if ((ph->core->exec_fd = open(exec_file, O_RDONLY)) < 0) { + print_debug("can't open executable file\n"); + goto err; + } - if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true || exec_ehdr.e_type != ET_EXEC) { - print_debug("executable file is not a valid ELF ET_EXEC file\n"); - goto err; - } + if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true || exec_ehdr.e_type != ET_EXEC) { + print_debug("executable file is not a valid ELF ET_EXEC file\n"); + goto err; + } - // process core file segments - if (read_core_segments(ph, &core_ehdr) != true) - goto err; + // process core file segments + if (read_core_segments(ph, &core_ehdr) != true) + goto err; - // process exec file segments - if (read_exec_segments(ph, &exec_ehdr) != true) - goto err; + // process exec file segments + if (read_exec_segments(ph, &exec_ehdr) != true) + goto err; - // exec file is also treated like a shared object for symbol search - if (add_lib_info_fd(ph, exec_file, ph->core->exec_fd, - (uintptr_t)0 + find_base_address(ph->core->exec_fd, &exec_ehdr)) == NULL) - goto err; + // exec file is also treated like a shared object for symbol search + if (add_lib_info_fd(ph, exec_file, ph->core->exec_fd, + (uintptr_t)0 + find_base_address(ph->core->exec_fd, &exec_ehdr)) == NULL) + goto err; - // allocate and sort maps into map_array, we need to do this - // here because read_shared_lib_info needs to read from debuggee - // address space - if (sort_map_array(ph) != true) - goto err; + // allocate and sort maps into map_array, we need to do this + // here because read_shared_lib_info needs to read from debuggee + // address space + if (sort_map_array(ph) != true) + goto err; - if (read_shared_lib_info(ph) != true) - goto err; + if (read_shared_lib_info(ph) != true) + goto err; - // sort again because we have added more mappings from shared objects - if (sort_map_array(ph) != true) - goto err; + // sort again because we have added more mappings from shared objects + if (sort_map_array(ph) != true) + goto err; - if (init_classsharing_workaround(ph) != true) - goto err; + if (init_classsharing_workaround(ph) != true) + goto err; - return ph; + print_debug("Leave Pgrab_core\n"); + return ph; err: - Prelease(ph); - return NULL; + Prelease(ph); + return NULL; } + +#endif // __APPLE__ diff -r 3d641132f83b -r 124ca22437b1 agent/src/os/bsd/symtab.c --- a/agent/src/os/bsd/symtab.c Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/os/bsd/symtab.c Fri Apr 12 10:14:42 2013 +0100 @@ -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 #include #include + +#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 @@ 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 @@ 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 @@ int n = 0; if (!symtab) return NULL; for (; n < symtab->num_symbols; n++) { - struct elf_symbol* sym = &(symtab->symbols[n]); + symtab_symbol* sym = &(symtab->symbols[n]); if (sym->name != NULL && offset >= sym->offset && offset < sym->offset + sym->size) { if (poffset) *poffset = (offset - sym->offset); diff -r 3d641132f83b -r 124ca22437b1 agent/src/os/bsd/symtab.h --- a/agent/src/os/bsd/symtab.h Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/os/bsd/symtab.h Fri Apr 12 10:14:42 2013 +0100 @@ -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 -// interface to manage ELF symbol tables +// interface to manage ELF or MachO symbol tables struct symtab; -// build symbol table for a given ELF file descriptor +// build symbol table for a given ELF or MachO file escriptor struct symtab* build_symtab(int fd); // destroy the symbol table diff -r 3d641132f83b -r 124ca22437b1 agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java --- a/agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java Fri Apr 12 10:14:42 2013 +0100 @@ -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 BsdVtblAccess(SymbolLookup symbolLookup, String[] dllNames) { super(symbolLookup, dllNames); - - if (symbolLookup.lookup("libjvm.so", "__vt_10JavaThread") != null || - symbolLookup.lookup("libjvm_g.so", "__vt_10JavaThread") != null) { + boolean oldVT = false; + boolean isDarwin = dllNames[0].lastIndexOf(".dylib") != -1; + String vtJavaThread = isDarwin ? "_vt_10JavaThread" : "__vt_10JavaThread"; + for (String dllName : dllNames) { + if (symbolLookup.lookup(dllName, vtJavaThread) != null) { + oldVT = true; + break; + } + } + if (oldVT) { // old C++ ABI - vt = "__vt_"; + vt = isDarwin ? "_vt_" : "__vt_"; } else { // new C++ ABI vt = "_ZTV"; diff -r 3d641132f83b -r 124ca22437b1 agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java --- a/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Fri Apr 12 10:14:42 2013 +0100 @@ -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 @@ 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 @@ 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 @@ ByteArrayOutputStream bos = new ByteArrayOutputStream(); thread.printThreadIDOn(new PrintStream(bos)); if (all || bos.toString().equals(name)) { - out.println(bos.toString() + " = " + thread.getAddress()); + out.println("Thread " + bos.toString() + " Address " + thread.getAddress()); if (!all) return; } } diff -r 3d641132f83b -r 124ca22437b1 agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java --- a/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java Fri Apr 12 10:14:42 2013 +0100 @@ -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 @@ 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 @@ 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 @@ setupJVMLibNamesLinux(); } else if (os.equals("bsd")) { setupJVMLibNamesBsd(); + } else if (os.equals("darwin")) { + setupJVMLibNamesDarwin(); } else { throw new RuntimeException("Unknown OS type"); } @@ -567,6 +575,29 @@ jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" }; } + // + // Darwin + // + + private void setupDebuggerDarwin() { + setupJVMLibNamesDarwin(); + + if (cpu.equals("amd64") || cpu.equals("x86_64")) { + machDesc = new MachineDescriptionAMD64(); + } else { + throw new DebuggerException("Darwin only supported on x86_64. Current arch: " + cpu); + } + + BsdDebuggerLocal dbg = new BsdDebuggerLocal(machDesc, !isServer); + debugger = dbg; + + attachDebugger(); + } + + private void setupJVMLibNamesDarwin() { + jvmLibNames = new String[] { "libjvm.dylib", "libjvm_g.dylib" }; + } + /** Convenience routine which should be called by per-platform debugger setup. Should not be called when startupMode is REMOTE_MODE. */ diff -r 3d641132f83b -r 124ca22437b1 agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java Fri Apr 12 10:14:42 2013 +0100 @@ -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.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.*; /**

An implementation of the JVMDebugger interface. The basic debug @@ -51,10 +54,11 @@ 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 @@ } } + isDarwin = getOS().equals("darwin"); workerThread = new BsdDebuggerLocalWorkerThread(this); workerThread.start(); } @@ -240,8 +245,11 @@ /* 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 @@ } 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 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 @@ throw new DebuggerException("Unimplemented"); } + /** this functions used for core file reading and called from native attach0, + it returns an array of long integers as + [thread_id, stack_start, stack_end, thread_id, stack_start, stack_end, ....] for + all java threads recorded in Threads. Also adds the ThreadProxy to threadList */ + public long[] getJavaThreadsInfo() { + requireAttach(); + Threads threads = VM.getVM().getThreads(); + int len = threads.getNumberOfThreads(); + long[] result = new long[len * 3]; // triple + JavaThread t = threads.first(); + long beg, end; + int i = 0; + while (t != null) { + end = t.getStackBaseValue(); + beg = end - t.getStackSize(); + BsdThread bsdt = (BsdThread)t.getThreadProxy(); + long uid = bsdt.getUniqueThreadId(); + if (threadList != null) threadList.add(bsdt); + result[i] = uid; + result[i + 1] = beg; + result[i + 2] = end; + t = t.next(); + i += 3; + } + return result; + } + static { System.loadLibrary("saproc"); init0(); diff -r 3d641132f83b -r 124ca22437b1 agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java Fri Apr 12 10:14:42 2013 +0100 @@ -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 @@ 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 @@ 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 @@ throws IllegalThreadStateException, DebuggerException { throw new DebuggerException("Unimplemented"); } + + /** this is not interface function, used in core file to get unique thread id on Macosx*/ + public long getUniqueThreadId() { + return unique_thread_id; + } } diff -r 3d641132f83b -r 124ca22437b1 agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java Fri Apr 12 10:14:42 2013 +0100 @@ -572,9 +572,14 @@ DTFWHome = sysRoot + File.separator + ".." + File.separator + "Program Files" + File.separator + "Debugging Tools For Windows"; searchList.add(DTFWHome); - searchList.add(DTFWHome + " (x86)"); - searchList.add(DTFWHome + " (x64)"); + // Only add the search path for the current CPU architecture: + String cpu = PlatformInfo.getCPU(); + if (cpu.equals("x86")) { + searchList.add(DTFWHome + " (x86)"); + } else if (cpu.equals("amd64")) { + searchList.add(DTFWHome + " (x64)"); + } // The last place to search is the system directory: searchList.add(sysRoot + File.separator + "system32"); } diff -r 3d641132f83b -r 124ca22437b1 agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java --- a/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java Fri Apr 12 10:14:42 2013 +0100 @@ -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 @@ if (doVMFields) { visitor.doCInt(mark, true); if (VM.getVM().isCompressedKlassPointersEnabled()) { - throw new InternalError("unimplemented"); + visitor.doMetadata(compressedKlass, true); } else { visitor.doMetadata(klass, true); } diff -r 3d641132f83b -r 124ca22437b1 agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Fri Apr 12 10:14:42 2013 +0100 @@ -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 @@ return stackBaseField.getValue(addr); } + public long getStackBaseValue() { + return VM.getVM().getAddressValue(getStackBase()); + } + public long getStackSize() { return stackSizeField.getValue(addr); } diff -r 3d641132f83b -r 124ca22437b1 agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java Fri Apr 12 10:14:42 2013 +0100 @@ -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 @@ 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 @@ 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 @@ } 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 @@ return createJavaThreadWrapper(threadAddr); } + public int getNumberOfThreads() { + return (int) numOfThreadsField.getValue(); + } + /** Routine for instantiating appropriately-typed wrapper for a JavaThread. Currently needs to be public for OopUtilities to access it. */ diff -r 3d641132f83b -r 124ca22437b1 agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java Fri Apr 12 10:14:42 2013 +0100 @@ -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.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 void run(PrintStream out, Debugger dbg) { + if (PlatformInfo.getOS().equals("darwin")) { + out.println("Not available on Darwin"); + return; + } + CDebugger cdbg = dbg.getCDebugger(); if (cdbg != null) { ConcurrentLocksPrinter concLocksPrinter = null; diff -r 3d641132f83b -r 124ca22437b1 agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java --- a/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java Fri Apr 12 10:14:42 2013 +0100 @@ -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; /**

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 @@ return VM.getVM().getOopSize(); } - static HashMap typeToVtbl = new HashMap(); + HashMap typeToVtbl = new HashMap(); private Address vtblForType(Type type) { Address vtblAddr = (Address)typeToVtbl.get(type); diff -r 3d641132f83b -r 124ca22437b1 agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java --- a/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java Fri Apr 12 10:14:42 2013 +0100 @@ -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 @@ return "bsd"; } else if (os.equals("OpenBSD")) { return "bsd"; - } else if (os.equals("Darwin") || os.contains("OS X")) { - return "bsd"; + } else if (os.contains("Darwin") || os.contains("OS X")) { + return "darwin"; } else if (os.startsWith("Windows")) { return "win32"; } else { diff -r 3d641132f83b -r 124ca22437b1 agent/src/share/native/sadis.c --- a/agent/src/share/native/sadis.c Tue Feb 26 16:16:54 2013 -0800 +++ b/agent/src/share/native/sadis.c Fri Apr 12 10:14:42 2013 +0100 @@ -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 #include + +#ifndef __APPLE__ #include +#endif #endif @@ -109,9 +112,7 @@ 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 @@ 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 @@ end - start, &event_to_env, (void*) &denv, &printf_to_env, (void*) &denv, - options); + options, 0 /* newline */); /* cleanup */ (*env)->ReleaseByteArrayElements(env, code, start, JNI_ABORT); diff -r 3d641132f83b -r 124ca22437b1 make/Makefile --- a/make/Makefile Tue Feb 26 16:16:54 2013 -0800 +++ b/make/Makefile Fri Apr 12 10:14:42 2013 +0100 @@ -532,6 +532,39 @@ $(TAR) -cf - *) | \ ($(CD) $(JDK_IMAGE_DIR) && $(TAR) -xf -) + +# Testing the built JVM +RUN_JVM=JAVA_HOME=$(JDK_IMPORT_PATH) $(JDK_IMPORT_PATH)/bin/java -d$(ARCH_DATA_MODEL) -Dsun.java.launcher=gamma +generic_test: + @$(ECHO) "Running with: $(ALTJVM_DIR)" + @$(RUN_JVM) -XXaltjvm=$(ALTJVM_DIR) -Xinternalversion + @$(RUN_JVM) -XXaltjvm=$(ALTJVM_DIR) -showversion -help + +# C2 test targets +test_product test_optimized test_fastdebug test_jvmg: + @$(MAKE) generic_test ALTJVM_DIR="$(C2_DIR)/$(@:test_%=%)" + +# C1 test targets +test_product1 test_optimized1 test_fastdebug1 test_jvmg1: + ifeq ($(ARCH_DATA_MODEL), 32) + @$(MAKE) generic_test ALTJVM_DIR="$(C1_DIR)/$(@:test_%1=%)" + else + @$(ECHO) "No compiler1 ($(@:test_%=%)) for ARCH_DATA_MODEL=$(ARCH_DATA_MODEL)" + endif + +# Zero test targets +test_productzero test_optimizedzero test_fastdebugzero test_jvmgzero: + @$(MAKE) generic_test ALTJVM_DIR="$(ZERO_DIR)/$(@:test_%zero=%)" + +# Shark test targets +test_productshark test_optimizedshark test_fastdebugshark test_jvmgshark: + @$(MAKE) generic_test ALTJVM_DIR="$(SHARK_DIR)/$(@:test_%shark=%)" + +# Minimal1 test targets +test_productminimal1 test_optimizedminimal1 test_fastdebugminimal1 test_jvmgminimal1: + @$(MAKE) generic_test ALTJVM_DIR="$(MINIMAL1_DIR)/$(@:test_%minimal1=%)" + + test_jdk: ifeq ($(JVM_VARIANT_CLIENT), true) $(JDK_IMAGE_DIR)/bin/java -d$(ARCH_DATA_MODEL) -client -Xinternalversion diff -r 3d641132f83b -r 124ca22437b1 make/bsd/Makefile --- a/make/bsd/Makefile Tue Feb 26 16:16:54 2013 -0800 +++ b/make/bsd/Makefile Fri Apr 12 10:14:42 2013 +0100 @@ -299,63 +299,42 @@ $(TARGETS_C2): $(SUBDIRS_C2) cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS) install endif $(TARGETS_TIERED): $(SUBDIRS_TIERED) cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_C1): $(SUBDIRS_C1) cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_CORE): $(SUBDIRS_CORE) cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_ZERO): $(SUBDIRS_ZERO) cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_SHARK): $(SUBDIRS_SHARK) cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_MINIMAL1): $(SUBDIRS_MINIMAL1) cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && $(MAKE) $(MFLAGS) install endif diff -r 3d641132f83b -r 124ca22437b1 make/bsd/build.sh --- a/make/bsd/build.sh Tue Feb 26 16:16:54 2013 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -#! /bin/sh -# -# Copyright (c) 1999, 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. -# -# - -# Make sure the variable JAVA_HOME is set before running this script. - -set -u - - -if [ $# != 2 ]; then - echo "Usage : $0 Build_Options Location" - echo "Build Options : debug or optimized or basicdebug or basic or clean" - echo "Location : specify any workspace which has gamma sources" - exit 1 -fi - -# Just in case: -case ${JAVA_HOME} in -/*) true;; -?*) JAVA_HOME=`( cd $JAVA_HOME; pwd )`;; -esac - -case `uname -m` in - i386|i486|i586|i686) - mach=i386 - ;; - *) - echo "Unsupported machine: " `uname -m` - exit 1 - ;; -esac - -if [ "${JAVA_HOME}" = "" -o ! -d "${JAVA_HOME}" -o ! -d ${JAVA_HOME}/jre/lib/${mach} ]; then - echo "JAVA_HOME needs to be set to a valid JDK path" - echo "ksh : export JAVA_HOME=/net/tetrasparc/export/gobi/JDK1.2_fcs_V/bsd" - echo "csh : setenv JAVA_HOME /net/tetrasparc/export/gobi/JDK1.2_fcs_V/bsd" - exit 1 -fi - - -LD_LIBRARY_PATH=${JAVA_HOME}/jre/lib/`uname -p`:\ -${JAVA_HOME}/jre/lib/`uname -p`/native_threads:${LD_LIBRARY_PATH-.} - -# This is necessary as long as we are using the old launcher -# with the new distribution format: -CLASSPATH=${JAVA_HOME}/jre/lib/rt.jar:${CLASSPATH-.} - - -for gm in gmake gnumake -do - if [ "${GNUMAKE-}" != "" ]; then break; fi - ($gm --version >/dev/null) 2>/dev/null && GNUMAKE=$gm -done -: ${GNUMAKE:?'Cannot locate the gnumake program. Stop.'} - - -echo "### ENVIRONMENT SETTINGS:" -export JAVA_HOME ; echo "JAVA_HOME=$JAVA_HOME" -export LD_LIBRARY_PATH ; echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" -export CLASSPATH ; echo "CLASSPATH=$CLASSPATH" -export GNUMAKE ; echo "GNUMAKE=$GNUMAKE" -echo "###" - -Build_Options=$1 -Location=$2 - -case ${Location} in -/*) true;; -?*) Location=`(cd ${Location}; pwd)`;; -esac - -echo \ -${GNUMAKE} -f ${Location}/make/bsd/Makefile $Build_Options GAMMADIR=${Location} -${GNUMAKE} -f ${Location}/make/bsd/Makefile $Build_Options GAMMADIR=${Location} diff -r 3d641132f83b -r 124ca22437b1 make/bsd/makefiles/buildtree.make --- a/make/bsd/makefiles/buildtree.make Tue Feb 26 16:16:54 2013 -0800 +++ b/make/bsd/makefiles/buildtree.make Fri Apr 12 10:14:42 2013 +0100 @@ -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 @@ -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 @@ # '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 @@ # 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) @@ -194,6 +190,17 @@ # literal "$(GAMMADIR)/" suitable for inclusion in a Makefile. gamma-path=$(subst $(GAMMADIR),\$$(GAMMADIR),$(call $(1),$(HS_COMMON_SRC)/$(2))) +# 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 + +DATA_MODE/i486 = 32 +DATA_MODE/amd64 = 64 + +DATA_MODE = $(DATA_MODE/$(BUILDARCH)) + flags.make: $(BUILDTREE_MAKE) ../shared_dirs.lst @echo Creating $@ ... $(QUIETLY) ( \ @@ -216,6 +223,7 @@ echo "HOTSPOT_BUILD_USER = $(HOTSPOT_BUILD_USER)"; \ echo "HOTSPOT_VM_DISTRO = $(HOTSPOT_VM_DISTRO)"; \ echo "OPENJDK = $(OPENJDK)"; \ + echo "$(LP64_SETTING/$(DATA_MODE))"; \ echo; \ echo "# Used for platform dispatching"; \ echo "TARGET_DEFINES = -DTARGET_OS_FAMILY_\$$(Platform_os_family)"; \ @@ -352,7 +360,7 @@ @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 +372,7 @@ @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 +383,6 @@ echo "JDK=${JAVA_HOME}"; \ ) > $@ -.dbxrc: $(BUILDTREE_MAKE) - @echo Creating $@ ... - $(QUIETLY) ( \ - echo "echo '# Loading $(PLATFORM_DIR)/$(TARGET)/.dbxrc'"; \ - echo "if [ -f \"\$${HOTSPOT_DBXWARE}\" ]"; \ - echo "then"; \ - echo " source \"\$${HOTSPOT_DBXWARE}\""; \ - echo "elif [ -f \"\$$HOME/.dbxrc\" ]"; \ - echo "then"; \ - echo " source \"\$$HOME/.dbxrc\""; \ - echo "fi"; \ - ) > $@ - -# Skip the test for product builds (which only work when installed in a JDK), to -# avoid exiting with an error and causing make to halt. -NO_TEST_MSG = \ - echo "$@: skipping the test--this build must be tested in a JDK." - -NO_JAVA_HOME_MSG = \ - echo "JAVA_HOME must be set to run this test." - -DATA_MODE = $(DATA_MODE/$(BUILDARCH)) -JAVA_FLAG = $(JAVA_FLAG/$(DATA_MODE)) - -DATA_MODE/i486 = 32 -DATA_MODE/sparc = 32 -DATA_MODE/sparcv9 = 64 -DATA_MODE/amd64 = 64 -DATA_MODE/ia64 = 64 -DATA_MODE/zero = $(ARCH_DATA_MODEL) - -JAVA_FLAG/32 = -d32 -JAVA_FLAG/64 = -d64 - -WRONG_DATA_MODE_MSG = \ - echo "JAVA_HOME must point to a $(DATA_MODE)-bit OpenJDK." - -CROSS_COMPILING_MSG = \ - echo "Cross compiling for ARCH $(CROSS_COMPILE_ARCH), skipping gamma run." - -test_gamma: $(BUILDTREE_MAKE) $(GAMMADIR)/make/test/Queens.java - @echo Creating $@ ... - $(QUIETLY) ( \ - echo "#!/bin/sh"; \ - echo ""; \ - $(BUILDTREE_COMMENT); \ - echo ""; \ - echo "# Include environment settings for gamma run"; \ - echo ""; \ - echo ". ./env.sh"; \ - echo ""; \ - echo "# Do not run gamma test for cross compiles"; \ - echo ""; \ - echo "if [ -n \"$(CROSS_COMPILE_ARCH)\" ]; then "; \ - echo " $(CROSS_COMPILING_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "# Make sure JAVA_HOME is set as it is required for gamma"; \ - echo ""; \ - echo "if [ -z \"\$${JAVA_HOME}\" ]; then "; \ - echo " $(NO_JAVA_HOME_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "# Check JAVA_HOME version to be used for the test"; \ - echo ""; \ - echo "\$${JAVA_HOME}/bin/java $(JAVA_FLAG) -fullversion > /dev/null 2>&1"; \ - echo "if [ \$$? -ne 0 ]; then "; \ - echo " $(WRONG_DATA_MODE_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "GAMMA_PROG=gamma"; \ - echo ""; \ - echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \ - echo " # Ensure architecture for gamma and JAVA_HOME is the same."; \ - echo " # NOTE: gamma assumes the OpenJDK directory layout."; \ - echo ""; \ - echo " GAMMA_ARCH=\"\`file \$${GAMMA_PROG} | awk '{print \$$NF}'\`\""; \ - echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/libjava.$(LIBRARY_SUFFIX)\""; \ - echo " if [ ! -f \$${JVM_LIB} ]; then"; \ - echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/$${LIBARCH}/libjava.$(LIBRARY_SUFFIX)\""; \ - echo " fi"; \ - echo " if [ ! -f \$${JVM_LIB} ] || [ -z \"\`file \$${JVM_LIB} | grep \$${GAMMA_ARCH}\`\" ]; then "; \ - echo " $(WRONG_DATA_MODE_MSG)"; \ - echo " exit 0"; \ - echo " fi"; \ - echo "fi"; \ - echo ""; \ - echo "# Compile Queens program for test"; \ - echo ""; \ - echo "rm -f Queens.class"; \ - echo "\$${JAVA_HOME}/bin/javac -d . $(GAMMADIR)/make/test/Queens.java"; \ - echo ""; \ - echo "# Set library path solely for gamma launcher test run"; \ - echo ""; \ - echo "LD_LIBRARY_PATH=.:$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \ - echo "export LD_LIBRARY_PATH"; \ - echo "unset LD_LIBRARY_PATH_32"; \ - echo "unset LD_LIBRARY_PATH_64"; \ - echo ""; \ - echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \ - echo " DYLD_LIBRARY_PATH=.:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/native_threads:\$${JAVA_HOME}/jre/lib:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \ - echo " export DYLD_LIBRARY_PATH"; \ - echo "fi"; \ - echo ""; \ - echo "# Use the gamma launcher and JAVA_HOME to run the test"; \ - echo ""; \ - echo "./\$${GAMMA_PROG} $(TESTFLAGS) Queens < /dev/null"; \ - ) > $@ - $(QUIETLY) chmod +x $@ - FORCE: .PHONY: all FORCE diff -r 3d641132f83b -r 124ca22437b1 make/bsd/makefiles/mapfile-vers-debug --- a/make/bsd/makefiles/mapfile-vers-debug Tue Feb 26 16:16:54 2013 -0800 +++ b/make/bsd/makefiles/mapfile-vers-debug Fri Apr 12 10:14:42 2013 +0100 @@ -135,6 +135,7 @@ JVM_GetEnclosingMethodInfo; JVM_GetFieldAnnotations; JVM_GetFieldIxModifiers; + JVM_GetFieldTypeAnnotations; JVM_GetHostName; JVM_GetInheritedAccessControlContext; JVM_GetInterfaceVersion; @@ -156,6 +157,7 @@ JVM_GetMethodIxSignatureUTF; JVM_GetMethodParameterAnnotations; JVM_GetMethodParameters; + JVM_GetMethodTypeAnnotations; JVM_GetPrimitiveArrayElement; JVM_GetProtectionDomain; JVM_GetSockName; diff -r 3d641132f83b -r 124ca22437b1 make/bsd/makefiles/mapfile-vers-product --- a/make/bsd/makefiles/mapfile-vers-product Tue Feb 26 16:16:54 2013 -0800 +++ b/make/bsd/makefiles/mapfile-vers-product Fri Apr 12 10:14:42 2013 +0100 @@ -135,6 +135,7 @@ JVM_GetEnclosingMethodInfo; JVM_GetFieldAnnotations; JVM_GetFieldIxModifiers; + JVM_GetFieldTypeAnnotations; JVM_GetHostName; JVM_GetInheritedAccessControlContext; JVM_GetInterfaceVersion; @@ -156,6 +157,7 @@ JVM_GetMethodIxSignatureUTF; JVM_GetMethodParameterAnnotations; JVM_GetMethodParameters; + JVM_GetMethodTypeAnnotations; JVM_GetPrimitiveArrayElement; JVM_GetProtectionDomain; JVM_GetSockName; diff -r 3d641132f83b -r 124ca22437b1 make/bsd/makefiles/saproc.make --- a/make/bsd/makefiles/saproc.make Tue Feb 26 16:16:54 2013 -0800 +++ b/make/bsd/makefiles/saproc.make Fri Apr 12 10:14:42 2013 +0100 @@ -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 @@ 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 @@ $(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 @@ fi @echo Making SA debugger back-end... $(QUIETLY) $(CC) -D$(BUILDARCH) -D_GNU_SOURCE \ - $(SYMFLAG) $(SAARCH) $(SHARED_FLAG) $(PICFLAG) \ + $(SYMFLAG) $(SAARCH) $(SHARED_FLAG) $(PICFLAG) \ -I$(SASRCDIR) \ -I$(GENERATED) \ $(BOOT_JAVA_INCLUDES) \ diff -r 3d641132f83b -r 124ca22437b1 make/build.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/build.sh Fri Apr 12 10:14:42 2013 +0100 @@ -0,0 +1,92 @@ +#! /bin/sh +# +# Copyright (c) 1998, 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 +# 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. +# +# + +# Make sure the variable JAVA_HOME is set before running this script. + +set -u + + +if [ $# -lt 1 ]; then + echo "Usage : $0 BuildTarget [LP64=1] [BuildOptions]" + echo " Server VM | Client VM" + echo "BuildTarget : debug | debug1" + echo " fastdebug | fastdebug1" + echo " jvmg | jvmg1" + echo " optimized | optimized1" + echo " profiled | profiled1" + echo " product | product1" + exit 1 +fi + +if [ "${JAVA_HOME-}" = "" -o ! -d "${JAVA_HOME-}" -o ! -d ${JAVA_HOME-}/jre/lib/ ]; then + echo "JAVA_HOME needs to be set to a valid JDK path" + echo "JAVA_HOME: ${JAVA_HOME-}" + exit 1 +fi + +# Just in case: +JAVA_HOME=`( cd $JAVA_HOME; pwd )` + +if [ "${ALT_BOOTDIR-}" = "" -o ! -d "${ALT_BOOTDIR-}" -o ! -d ${ALT_BOOTDIR-}/jre/lib/ ]; then + ALT_BOOTDIR=${JAVA_HOME} +fi + +# build in current directory by default +if [ "${ALT_OUTPUTDIR-}" = "" -o ! -d "${ALT_OUTPUTDIR-}" ]; then + ALT_OUTPUTDIR=`(pwd)` +fi + +HOTSPOT_SRC=`(dirname $0)`/.. +HOTSPOT_SRC=`(cd ${HOTSPOT_SRC}; pwd)` + +for gm in gmake gnumake +do + if [ "${GNUMAKE-}" != "" ]; then break; fi + ($gm --version >/dev/null) 2>/dev/null && GNUMAKE=$gm +done +: ${GNUMAKE:?'Cannot locate the gnumake program. Stop.'} + +# quiet build by default +Quiet="MAKE_VERBOSE=" + +# no debug info by default +NoDebugInfo="ENABLE_FULL_DEBUG_SYMBOLS=" + +LANG=C + +echo "### ENVIRONMENT SETTINGS:" +export HOTSPOT_SRC ; echo "HOTSPOT_SRC=$HOTSPOT_SRC" +export JAVA_HOME ; echo "JAVA_HOME=$JAVA_HOME" +export ALT_BOOTDIR ; echo "ALT_BOOTDIR=$ALT_BOOTDIR" +export ALT_OUTPUTDIR ; echo "ALT_OUTPUTDIR=$ALT_OUTPUTDIR" +export GNUMAKE ; echo "GNUMAKE=$GNUMAKE" +export LANG ; echo "LANG=$LANG" +echo "###" + +BuildOptions="$Quiet $NoDebugInfo $*" + +echo \ +${GNUMAKE} -f ${HOTSPOT_SRC}/make/Makefile $BuildOptions GAMMADIR=${HOTSPOT_SRC} +${GNUMAKE} -f ${HOTSPOT_SRC}/make/Makefile $BuildOptions GAMMADIR=${HOTSPOT_SRC} diff -r 3d641132f83b -r 124ca22437b1 make/defs.make --- a/make/defs.make Tue Feb 26 16:16:54 2013 -0800 +++ b/make/defs.make Fri Apr 12 10:14:42 2013 +0100 @@ -302,7 +302,7 @@ 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)/$(JDK_INCLUDE_SUBDIR)/jni_md.h EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jmm.h -# By default, run Queens test after building -TEST_IN_BUILD ?= true - ifndef JAVASE_EMBEDDED EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jfr.h endif diff -r 3d641132f83b -r 124ca22437b1 make/excludeSrc.make --- a/make/excludeSrc.make Tue Feb 26 16:16:54 2013 -0800 +++ b/make/excludeSrc.make Fri Apr 12 10:14:42 2013 +0100 @@ -28,7 +28,8 @@ Src_Files_EXCLUDE += jvmtiGetLoadedClasses.cpp forte.cpp jvmtiThreadState.cpp jvmtiExtensions.cpp \ jvmtiImpl.cpp jvmtiManageCapabilities.cpp jvmtiRawMonitor.cpp jvmtiUtil.cpp jvmtiTrace.cpp \ jvmtiCodeBlobEvents.cpp jvmtiEnv.cpp jvmtiRedefineClasses.cpp jvmtiEnvBase.cpp jvmtiEnvThreadState.cpp \ - jvmtiTagMap.cpp jvmtiEventController.cpp evmCompat.cpp jvmtiEnter.xsl jvmtiExport.cpp + jvmtiTagMap.cpp jvmtiEventController.cpp evmCompat.cpp jvmtiEnter.xsl jvmtiExport.cpp \ + jvmtiClassFileReconstituter.cpp endif ifeq ($(INCLUDE_FPROF), false) diff -r 3d641132f83b -r 124ca22437b1 make/hotspot_version --- a/make/hotspot_version Tue Feb 26 16:16:54 2013 -0800 +++ b/make/hotspot_version Fri Apr 12 10:14:42 2013 +0100 @@ -35,7 +35,7 @@ HS_MAJOR_VER=25 HS_MINOR_VER=0 -HS_BUILD_NUMBER=23 +HS_BUILD_NUMBER=27 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 diff -r 3d641132f83b -r 124ca22437b1 make/jprt.properties --- a/make/jprt.properties Tue Feb 26 16:16:54 2013 -0800 +++ b/make/jprt.properties Fri Apr 12 10:14:42 2013 +0100 @@ -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.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.armvfphflt.jdk8=linux_armvfphflt_2.6 +jprt.my.linux.armvfphflt=${jprt.my.linux.armvfphflt.${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}} +# 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.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.my.linux.ppc}-{productEmb|fastdebugEmb}, \ ${jprt.my.linux.ppcv2}-{productEmb|fastdebugEmb}, \ ${jprt.my.linux.ppcsflt}-{productEmb|fastdebugEmb}, \ - ${jprt.my.linux.armvfp}-{productEmb|fastdebugEmb}, \ + ${jprt.my.linux.armvfpsflt}-{productEmb|fastdebugEmb}, \ + ${jprt.my.linux.armvfphflt}-{productEmb|fastdebugEmb}, \ ${jprt.my.linux.armsflt}-{productEmb|fastdebugEmb} jprt.build.targets.all=${jprt.build.targets.standard}, \ diff -r 3d641132f83b -r 124ca22437b1 make/linux/Makefile --- a/make/linux/Makefile Tue Feb 26 16:16:54 2013 -0800 +++ b/make/linux/Makefile Fri Apr 12 10:14:42 2013 +0100 @@ -300,63 +300,42 @@ $(TARGETS_C2): $(SUBDIRS_C2) cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS) install endif $(TARGETS_TIERED): $(SUBDIRS_TIERED) cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_C1): $(SUBDIRS_C1) cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_CORE): $(SUBDIRS_CORE) cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_ZERO): $(SUBDIRS_ZERO) cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_SHARK): $(SUBDIRS_SHARK) cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_MINIMAL1): $(SUBDIRS_MINIMAL1) cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_minimal1/$(patsubst %minimal1,%,$@) && $(MAKE) $(MFLAGS) install endif diff -r 3d641132f83b -r 124ca22437b1 make/linux/build.sh --- a/make/linux/build.sh Tue Feb 26 16:16:54 2013 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -#! /bin/sh -# -# Copyright (c) 1999, 2011, 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. -# -# - -# Make sure the variable JAVA_HOME is set before running this script. - -set -u - - -if [ $# != 2 ]; then - echo "Usage : $0 Build_Options Location" - echo "Build Options : debug or optimized or basicdebug or basic or clean" - echo "Location : specify any workspace which has gamma sources" - exit 1 -fi - -# Just in case: -case ${JAVA_HOME} in -/*) true;; -?*) JAVA_HOME=`( cd $JAVA_HOME; pwd )`;; -esac - -case `uname -m` in - i386|i486|i586|i686) - mach=i386 - ;; - x86_64) - mach=amd64 - ;; - *) - echo "Unsupported machine: " `uname -m` - exit 1 - ;; -esac - -if [ "${JAVA_HOME}" = "" -o ! -d "${JAVA_HOME}" -o ! -d ${JAVA_HOME}/jre/lib/${mach} ]; then - echo "JAVA_HOME needs to be set to a valid JDK path" - echo "ksh : export JAVA_HOME=/net/tetrasparc/export/gobi/JDK1.2_fcs_V/linux" - echo "csh : setenv JAVA_HOME /net/tetrasparc/export/gobi/JDK1.2_fcs_V/linux" - exit 1 -fi - - -LD_LIBRARY_PATH=${JAVA_HOME}/jre/lib/`uname -p`:\ -${JAVA_HOME}/jre/lib/`uname -p`/native_threads:${LD_LIBRARY_PATH-.} - -# This is necessary as long as we are using the old launcher -# with the new distribution format: -CLASSPATH=${JAVA_HOME}/jre/lib/rt.jar:${CLASSPATH-.} - - -for gm in gmake gnumake -do - if [ "${GNUMAKE-}" != "" ]; then break; fi - ($gm --version >/dev/null) 2>/dev/null && GNUMAKE=$gm -done -: ${GNUMAKE:?'Cannot locate the gnumake program. Stop.'} - - -echo "### ENVIRONMENT SETTINGS:" -export JAVA_HOME ; echo "JAVA_HOME=$JAVA_HOME" -export LD_LIBRARY_PATH ; echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" -export CLASSPATH ; echo "CLASSPATH=$CLASSPATH" -export GNUMAKE ; echo "GNUMAKE=$GNUMAKE" -echo "###" - -Build_Options=$1 -Location=$2 - -case ${Location} in -/*) true;; -?*) Location=`(cd ${Location}; pwd)`;; -esac - -echo \ -${GNUMAKE} -f ${Location}/make/linux/Makefile $Build_Options GAMMADIR=${Location} -${GNUMAKE} -f ${Location}/make/linux/Makefile $Build_Options GAMMADIR=${Location} diff -r 3d641132f83b -r 124ca22437b1 make/linux/makefiles/buildtree.make --- a/make/linux/makefiles/buildtree.make Tue Feb 26 16:16:54 2013 -0800 +++ b/make/linux/makefiles/buildtree.make Fri Apr 12 10:14:42 2013 +0100 @@ -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 @@ -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 @@ # '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 @@ 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) @@ -187,6 +183,19 @@ # literal "$(GAMMADIR)/" suitable for inclusion in a Makefile. gamma-path=$(subst $(GAMMADIR),\$$(GAMMADIR),$(call $(1),$(HS_COMMON_SRC)/$(2))) +# 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 + +DATA_MODE/i486 = 32 +DATA_MODE/sparc = 32 +DATA_MODE/sparcv9 = 64 +DATA_MODE/amd64 = 64 + +DATA_MODE = $(DATA_MODE/$(BUILDARCH)) + flags.make: $(BUILDTREE_MAKE) ../shared_dirs.lst @echo Creating $@ ... $(QUIETLY) ( \ @@ -209,6 +218,7 @@ echo "HOTSPOT_BUILD_USER = $(HOTSPOT_BUILD_USER)"; \ echo "HOTSPOT_VM_DISTRO = $(HOTSPOT_VM_DISTRO)"; \ echo "OPENJDK = $(OPENJDK)"; \ + echo "$(LP64_SETTING/$(DATA_MODE))"; \ echo; \ echo "# Used for platform dispatching"; \ echo "TARGET_DEFINES = -DTARGET_OS_FAMILY_\$$(Platform_os_family)"; \ @@ -345,7 +355,7 @@ @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 +367,7 @@ @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 +378,6 @@ echo "JDK=${JAVA_HOME}"; \ ) > $@ -.dbxrc: $(BUILDTREE_MAKE) - @echo Creating $@ ... - $(QUIETLY) ( \ - echo "echo '# Loading $(PLATFORM_DIR)/$(TARGET)/.dbxrc'"; \ - echo "if [ -f \"\$${HOTSPOT_DBXWARE}\" ]"; \ - echo "then"; \ - echo " source \"\$${HOTSPOT_DBXWARE}\""; \ - echo "elif [ -f \"\$$HOME/.dbxrc\" ]"; \ - echo "then"; \ - echo " source \"\$$HOME/.dbxrc\""; \ - echo "fi"; \ - ) > $@ - -# Skip the test for product builds (which only work when installed in a JDK), to -# avoid exiting with an error and causing make to halt. -NO_TEST_MSG = \ - echo "$@: skipping the test--this build must be tested in a JDK." - -NO_JAVA_HOME_MSG = \ - echo "JAVA_HOME must be set to run this test." - -DATA_MODE = $(DATA_MODE/$(BUILDARCH)) -JAVA_FLAG = $(JAVA_FLAG/$(DATA_MODE)) - -DATA_MODE/i486 = 32 -DATA_MODE/sparc = 32 -DATA_MODE/sparcv9 = 64 -DATA_MODE/amd64 = 64 -DATA_MODE/ia64 = 64 -DATA_MODE/zero = $(ARCH_DATA_MODEL) - -JAVA_FLAG/32 = -d32 -JAVA_FLAG/64 = -d64 - -WRONG_DATA_MODE_MSG = \ - echo "JAVA_HOME must point to a $(DATA_MODE)-bit OpenJDK." - -CROSS_COMPILING_MSG = \ - echo "Cross compiling for ARCH $(CROSS_COMPILE_ARCH), skipping gamma run." - -test_gamma: $(BUILDTREE_MAKE) $(GAMMADIR)/make/test/Queens.java - @echo Creating $@ ... - $(QUIETLY) ( \ - echo "#!/bin/sh"; \ - echo ""; \ - $(BUILDTREE_COMMENT); \ - echo ""; \ - echo "# Include environment settings for gamma run"; \ - echo ""; \ - echo ". ./env.sh"; \ - echo ""; \ - echo "# Do not run gamma test for cross compiles"; \ - echo ""; \ - echo "if [ -n \"$(CROSS_COMPILE_ARCH)\" ]; then "; \ - echo " $(CROSS_COMPILING_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "# Make sure JAVA_HOME is set as it is required for gamma"; \ - echo ""; \ - echo "if [ -z \"\$${JAVA_HOME}\" ]; then "; \ - echo " $(NO_JAVA_HOME_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "# Check JAVA_HOME version to be used for the test"; \ - echo ""; \ - echo "\$${JAVA_HOME}/bin/java $(JAVA_FLAG) -fullversion > /dev/null 2>&1"; \ - echo "if [ \$$? -ne 0 ]; then "; \ - echo " $(WRONG_DATA_MODE_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "GAMMA_PROG=gamma"; \ - echo ""; \ - echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \ - echo " # Ensure architecture for gamma and JAVA_HOME is the same."; \ - echo " # NOTE: gamma assumes the OpenJDK directory layout."; \ - echo ""; \ - echo " GAMMA_ARCH=\"\`file \$${GAMMA_PROG} | awk '{print \$$NF}'\`\""; \ - echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/libjava.$(LIBRARY_SUFFIX)\""; \ - echo " if [ ! -f \$${JVM_LIB} ]; then"; \ - echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/$${LIBARCH}/libjava.$(LIBRARY_SUFFIX)\""; \ - echo " fi"; \ - echo " if [ ! -f \$${JVM_LIB} ] || [ -z \"\`file \$${JVM_LIB} | grep \$${GAMMA_ARCH}\`\" ]; then "; \ - echo " $(WRONG_DATA_MODE_MSG)"; \ - echo " exit 0"; \ - echo " fi"; \ - echo "fi"; \ - echo ""; \ - echo "# Compile Queens program for test"; \ - echo ""; \ - echo "rm -f Queens.class"; \ - echo "\$${JAVA_HOME}/bin/javac -d . $(GAMMADIR)/make/test/Queens.java"; \ - echo ""; \ - echo "# Set library path solely for gamma launcher test run"; \ - echo ""; \ - echo "LD_LIBRARY_PATH=.:$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \ - echo "export LD_LIBRARY_PATH"; \ - echo "unset LD_LIBRARY_PATH_32"; \ - echo "unset LD_LIBRARY_PATH_64"; \ - echo ""; \ - echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \ - echo " DYLD_LIBRARY_PATH=.:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/native_threads:\$${JAVA_HOME}/jre/lib:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \ - echo " export DYLD_LIBRARY_PATH"; \ - echo "fi"; \ - echo ""; \ - echo "# Use the gamma launcher and JAVA_HOME to run the test"; \ - echo ""; \ - echo "./\$${GAMMA_PROG} $(TESTFLAGS) Queens < /dev/null"; \ - ) > $@ - $(QUIETLY) chmod +x $@ - FORCE: .PHONY: all FORCE diff -r 3d641132f83b -r 124ca22437b1 make/linux/makefiles/gcc.make --- a/make/linux/makefiles/gcc.make Tue Feb 26 16:16:54 2013 -0800 +++ b/make/linux/makefiles/gcc.make Fri Apr 12 10:14:42 2013 +0100 @@ -126,14 +126,12 @@ # Compiler warnings are treated as errors WARNINGS_ARE_ERRORS = -Werror -# Except for a few acceptable ones +WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef -Wunused-function + # Since GCC 4.3, -Wconversion has changed its meanings to warn these implicit -# conversions which might affect the values. To avoid that, we need to turn -# it off explicitly. -ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" -WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef -else -WARNING_FLAGS = -Wpointer-arith -Wconversion -Wsign-compare -Wundef +# conversions which might affect the values. Only enable it in earlier versions. +ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" +WARNING_FLAGS += -Wconversion endif CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(WARNING_FLAGS) diff -r 3d641132f83b -r 124ca22437b1 make/linux/makefiles/mapfile-vers-debug --- a/make/linux/makefiles/mapfile-vers-debug Tue Feb 26 16:16:54 2013 -0800 +++ b/make/linux/makefiles/mapfile-vers-debug Fri Apr 12 10:14:42 2013 +0100 @@ -131,6 +131,7 @@ JVM_GetEnclosingMethodInfo; JVM_GetFieldAnnotations; JVM_GetFieldIxModifiers; + JVM_GetFieldTypeAnnotations; JVM_GetHostName; JVM_GetInheritedAccessControlContext; JVM_GetInterfaceVersion; @@ -152,6 +153,7 @@ JVM_GetMethodIxSignatureUTF; JVM_GetMethodParameterAnnotations; JVM_GetMethodParameters; + JVM_GetMethodTypeAnnotations; JVM_GetPrimitiveArrayElement; JVM_GetProtectionDomain; JVM_GetSockName; diff -r 3d641132f83b -r 124ca22437b1 make/linux/makefiles/mapfile-vers-product --- a/make/linux/makefiles/mapfile-vers-product Tue Feb 26 16:16:54 2013 -0800 +++ b/make/linux/makefiles/mapfile-vers-product Fri Apr 12 10:14:42 2013 +0100 @@ -131,6 +131,7 @@ JVM_GetEnclosingMethodInfo; JVM_GetFieldAnnotations; JVM_GetFieldIxModifiers; + JVM_GetFieldTypeAnnotations; JVM_GetHostName; JVM_GetInheritedAccessControlContext; JVM_GetInterfaceVersion; @@ -152,6 +153,7 @@ JVM_GetMethodIxSignatureUTF; JVM_GetMethodParameterAnnotations; JVM_GetMethodParameters; + JVM_GetMethodTypeAnnotations; JVM_GetPrimitiveArrayElement; JVM_GetProtectionDomain; JVM_GetSockName; diff -r 3d641132f83b -r 124ca22437b1 make/solaris/Makefile --- a/make/solaris/Makefile Tue Feb 26 16:16:54 2013 -0800 +++ b/make/solaris/Makefile Fri Apr 12 10:14:42 2013 +0100 @@ -231,36 +231,24 @@ $(TARGETS_C2): $(SUBDIRS_C2) cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_compiler2/$@ && $(MAKE) $(MFLAGS) install endif $(TARGETS_TIERED): $(SUBDIRS_TIERED) cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_tiered/$(patsubst %tiered,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_C1): $(SUBDIRS_C1) cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_compiler1/$(patsubst %1,%,$@) && $(MAKE) $(MFLAGS) install endif $(TARGETS_CORE): $(SUBDIRS_CORE) cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && ./test_gamma -endif ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS) install endif diff -r 3d641132f83b -r 124ca22437b1 make/solaris/build.sh --- a/make/solaris/build.sh Tue Feb 26 16:16:54 2013 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -#! /bin/sh -# -# Copyright (c) 1998, 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. -# -# - -# Make sure the variable JAVA_HOME is set before running this script. - -set -u - - -usage() { - ( - echo "Usage : $0 [-sb | -sbfast] config ws_path" - echo "" - echo "Where:" - echo " -sb ::= enable source browser info generation for" - echo " all configs during compilation" - echo "" - echo " -sbfast ::= enable source browser info generation for" - echo " all configs without compilation" - echo "" - echo " config ::= debug | debug1 | debugcore" - echo " fastdebug | fastdebug1 | fastdebugcore" - echo " jvmg | jvmg1 | jvmgcore" - echo " optimized | optimized1 | optimizedcore" - echo " profiled | profiled1 | profiledcore" - echo " product | product1 | productcore" - echo "" - echo " ws_path ::= path to HotSpot workspace" - ) >&2 - exit 1 -} - -# extract possible options -options="" -if [ $# -gt 2 ]; then - case "$1" in - -sb) - options="CFLAGS_BROWSE=-xsb" - shift - ;; - -sbfast) - options="CFLAGS_BROWSE=-xsbfast" - shift - ;; - *) - echo "Unknown option: '$1'" >&2 - usage - ;; - esac -fi - -# should be just two args left at this point -if [ $# != 2 ]; then - usage -fi - -# Just in case: -case ${JAVA_HOME} in -/*) true;; -?*) JAVA_HOME=`( cd $JAVA_HOME; pwd )`;; -esac - -if [ "${JAVA_HOME}" = "" -o ! -d "${JAVA_HOME}" -o ! -d ${JAVA_HOME}/jre/lib/`uname -p` ]; then - echo "JAVA_HOME needs to be set to a valid JDK path" - echo "ksh : export JAVA_HOME=/net/tetrasparc/export/gobi/JDK1.2_fcs_V/solaris" - echo "csh : setenv JAVA_HOME /net/tetrasparc/export/gobi/JDK1.2_fcs_V/solaris" - exit 1 -fi - - -LD_LIBRARY_PATH=${JAVA_HOME}/jre/lib/`uname -p`:\ -${JAVA_HOME}/jre/lib/`uname -p`/native_threads:${LD_LIBRARY_PATH-.} - -# This is necessary as long as we are using the old launcher -# with the new distribution format: -CLASSPATH=${JAVA_HOME}/jre/lib/rt.jar:${CLASSPATH-.} - - -for gm in gmake gnumake -do - if [ "${GNUMAKE-}" != "" ]; then break; fi - ($gm --version >/dev/null) 2>/dev/null && GNUMAKE=$gm -done -: ${GNUMAKE:?'Cannot locate the gnumake program. Stop.'} - - -echo "### ENVIRONMENT SETTINGS:" -export JAVA_HOME ; echo "JAVA_HOME=$JAVA_HOME" -export LD_LIBRARY_PATH ; echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" -export CLASSPATH ; echo "CLASSPATH=$CLASSPATH" -export GNUMAKE ; echo "GNUMAKE=$GNUMAKE" -echo "###" - -config=$1 -ws_path=$2 - -case ${ws_path} in -/*) true;; -?*) ws_path=`(cd ${ws_path}; pwd)`;; -esac - -echo \ -${GNUMAKE} -f ${ws_path}/make/solaris/Makefile \ - $config GAMMADIR=${ws_path} $options -${GNUMAKE} -f ${ws_path}/make/solaris/Makefile \ - $config GAMMADIR=${ws_path} $options diff -r 3d641132f83b -r 124ca22437b1 make/solaris/makefiles/buildtree.make --- a/make/solaris/makefiles/buildtree.make Tue Feb 26 16:16:54 2013 -0800 +++ b/make/solaris/makefiles/buildtree.make Fri Apr 12 10:14:42 2013 +0100 @@ -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 @@ -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 @@ 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) @@ -178,6 +176,19 @@ # literal "$(GAMMADIR)/" suitable for inclusion in a Makefile. gamma-path=$(subst $(GAMMADIR),\$$(GAMMADIR),$(call $(1),$(HS_COMMON_SRC)/$(2))) +# 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 + +DATA_MODE/i486 = 32 +DATA_MODE/sparc = 32 +DATA_MODE/sparcv9 = 64 +DATA_MODE/amd64 = 64 + +DATA_MODE = $(DATA_MODE/$(BUILDARCH)) + flags.make: $(BUILDTREE_MAKE) ../shared_dirs.lst @echo Creating $@ ... $(QUIETLY) ( \ @@ -334,7 +345,7 @@ @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 +357,7 @@ @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 +368,6 @@ echo "JDK=${JAVA_HOME}"; \ ) > $@ -.dbxrc: $(BUILDTREE_MAKE) - @echo Creating $@ ... - $(QUIETLY) ( \ - echo "echo '# Loading $(PLATFORM_DIR)/$(TARGET)/.dbxrc'"; \ - echo "if [ -f \"\$${HOTSPOT_DBXWARE}\" ]"; \ - echo "then"; \ - echo " source \"\$${HOTSPOT_DBXWARE}\""; \ - echo "elif [ -f \"\$$HOME/.dbxrc\" ]"; \ - echo "then"; \ - echo " source \"\$$HOME/.dbxrc\""; \ - echo "fi"; \ - ) > $@ - -# Skip the test for product builds (which only work when installed in a JDK), to -# avoid exiting with an error and causing make to halt. -NO_TEST_MSG = \ - echo "$@: skipping the test--this build must be tested in a JDK." - -NO_JAVA_HOME_MSG = \ - echo "JAVA_HOME must be set to run this test." - -DATA_MODE = $(DATA_MODE/$(BUILDARCH)) -JAVA_FLAG = $(JAVA_FLAG/$(DATA_MODE)) - -DATA_MODE/i486 = 32 -DATA_MODE/sparc = 32 -DATA_MODE/sparcv9 = 64 -DATA_MODE/amd64 = 64 -DATA_MODE/ia64 = 64 - -# This bit is needed to enable local rebuilds. -# Unless the makefile itself sets LP64, any environmental -# setting of LP64 will interfere with the build. -LP64_SETTING/32 = LP64 = \#empty -LP64_SETTING/64 = LP64 = 1 - -JAVA_FLAG/32 = -d32 -JAVA_FLAG/64 = -d64 - -WRONG_DATA_MODE_MSG = \ - echo "JAVA_HOME must point to a $(DATA_MODE)-bit OpenJDK." - -CROSS_COMPILING_MSG = \ - echo "Cross compiling for ARCH $(CROSS_COMPILE_ARCH), skipping gamma run." - -test_gamma: $(BUILDTREE_MAKE) $(GAMMADIR)/make/test/Queens.java - @echo Creating $@ ... - $(QUIETLY) ( \ - echo "#!/bin/sh"; \ - echo ""; \ - $(BUILDTREE_COMMENT); \ - echo ""; \ - echo "# Include environment settings for gamma run"; \ - echo ""; \ - echo ". ./env.sh"; \ - echo ""; \ - echo "# Do not run gamma test for cross compiles"; \ - echo ""; \ - echo "if [ -n \"$(CROSS_COMPILE_ARCH)\" ]; then "; \ - echo " $(CROSS_COMPILING_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "# Make sure JAVA_HOME is set as it is required for gamma"; \ - echo ""; \ - echo "if [ -z \"\$${JAVA_HOME}\" ]; then "; \ - echo " $(NO_JAVA_HOME_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "# Check JAVA_HOME version to be used for the test"; \ - echo ""; \ - echo "\$${JAVA_HOME}/bin/java $(JAVA_FLAG) -fullversion > /dev/null 2>&1"; \ - echo "if [ \$$? -ne 0 ]; then "; \ - echo " $(WRONG_DATA_MODE_MSG)"; \ - echo " exit 0"; \ - echo "fi"; \ - echo ""; \ - echo "GAMMA_PROG=gamma"; \ - echo ""; \ - echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \ - echo " # Ensure architecture for gamma and JAVA_HOME is the same."; \ - echo " # NOTE: gamma assumes the OpenJDK directory layout."; \ - echo ""; \ - echo " GAMMA_ARCH=\"\`file \$${GAMMA_PROG} | awk '{print \$$NF}'\`\""; \ - echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/libjava.$(LIBRARY_SUFFIX)\""; \ - echo " if [ ! -f \$${JVM_LIB} ]; then"; \ - echo " JVM_LIB=\"\$${JAVA_HOME}/jre/lib/$${LIBARCH}/libjava.$(LIBRARY_SUFFIX)\""; \ - echo " fi"; \ - echo " if [ ! -f \$${JVM_LIB} ] || [ -z \"\`file \$${JVM_LIB} | grep \$${GAMMA_ARCH}\`\" ]; then "; \ - echo " $(WRONG_DATA_MODE_MSG)"; \ - echo " exit 0"; \ - echo " fi"; \ - echo "fi"; \ - echo ""; \ - echo "# Compile Queens program for test"; \ - echo ""; \ - echo "rm -f Queens.class"; \ - echo "\$${JAVA_HOME}/bin/javac -d . $(GAMMADIR)/make/test/Queens.java"; \ - echo ""; \ - echo "# Set library path solely for gamma launcher test run"; \ - echo ""; \ - echo "LD_LIBRARY_PATH=.:$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \ - echo "export LD_LIBRARY_PATH"; \ - echo "unset LD_LIBRARY_PATH_32"; \ - echo "unset LD_LIBRARY_PATH_64"; \ - echo ""; \ - echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \ - echo " DYLD_LIBRARY_PATH=.:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/native_threads:\$${JAVA_HOME}/jre/lib:$${DYLD_LIBRARY_PATH:+$$DYLD_LIBRARY_PATH:}\$${JAVA_HOME}/jre/lib/${LIBARCH}/native_threads:\$${JAVA_HOME}/jre/lib/${LIBARCH}:${GCC_LIB}"; \ - echo " export DYLD_LIBRARY_PATH"; \ - echo "fi"; \ - echo ""; \ - echo "# Use the gamma launcher and JAVA_HOME to run the test"; \ - echo ""; \ - echo "./\$${GAMMA_PROG} $(TESTFLAGS) Queens < /dev/null"; \ - ) > $@ - $(QUIETLY) chmod +x $@ - FORCE: .PHONY: all FORCE diff -r 3d641132f83b -r 124ca22437b1 make/solaris/makefiles/mapfile-vers --- a/make/solaris/makefiles/mapfile-vers Tue Feb 26 16:16:54 2013 -0800 +++ b/make/solaris/makefiles/mapfile-vers Fri Apr 12 10:14:42 2013 +0100 @@ -131,6 +131,7 @@ JVM_GetEnclosingMethodInfo; JVM_GetFieldAnnotations; JVM_GetFieldIxModifiers; + JVM_GetFieldTypeAnnotations; JVM_GetHostName; JVM_GetInheritedAccessControlContext; JVM_GetInterfaceVersion; @@ -152,6 +153,7 @@ JVM_GetMethodIxSignatureUTF; JVM_GetMethodParameterAnnotations; JVM_GetMethodParameters; + JVM_GetMethodTypeAnnotations; JVM_GetPrimitiveArrayElement; JVM_GetProtectionDomain; JVM_GetSockName; diff -r 3d641132f83b -r 124ca22437b1 make/test/Queens.java --- a/make/test/Queens.java Tue Feb 26 16:16:54 2013 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2006, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -import java.util.*; - -// Copyright 1996, Animorphic Systems -// gri 28 Aug 92 / 15 Jan 93 / 8 Dec 95 - -class Queens { - - static void try_i(boolean a[], boolean b[], boolean c[], int x[], int i) { - int adj = 7; - - for (int j = 1; j <= 8; j++) { - if (b[j] && a[i+j] && c[adj+i-j]) { - x[i] = j; - b[j] = false; - a[i+j] = false; - c[adj+i-j] = false; - if (i < 8) try_i(a, b, c, x, i+1); - else print(x); - b[j] = true; - a[i+j] = true; - c[adj+i-j] = true; - } - } - } - - public static void main(String s[]) { - boolean a[] = new boolean[16+1]; - boolean b[] = new boolean[ 8+1]; - boolean c[] = new boolean[14+1]; - int x[] = new int[8+1]; - int adj = 7; - - for (int i = -7; i <= 16; i++) { - if (i >= 1 && i <= 8) b[i] = true; - if (i >= 2) a[i] = true; - if (i <= 7) c[adj+i] = true; - } - - x[0] = 0; // solution counter - - try_i(a, b, c, x, 1); - } - - static void print(int x[]) { - // first correct solution: A1 B5 C8 D6 E3 F7 G2 H4 - - char LF = (char)0xA; - char CR = (char)0xD; - - x[0]++; - if (x[0] < 10) - System.out.print(" "); - System.out.print(x[0] + ". "); - for (int i = 1; i <= 8; i++) { - char p = (char)('A' + i - 1); - System.out.print(p); - System.out.print (x[i] + " "); - } - System.out.println(); - } - -}; diff -r 3d641132f83b -r 124ca22437b1 make/windows/build.make --- a/make/windows/build.make Tue Feb 26 16:16:54 2013 -0800 +++ b/make/windows/build.make Fri Apr 12 10:14:42 2013 +0100 @@ -110,8 +110,6 @@ !endif !elseif "$(Variant)" == "tiered" VARIANT_TEXT=Tiered -!elseif "$(Variant)" == "kernel" -VARIANT_TEXT=Kernel !endif ######################################################################### @@ -305,9 +303,9 @@ checks: checkVariant checkWorkSpace checkSA checkVariant: - @ if "$(Variant)"=="" echo Need to specify "Variant=[tiered|compiler2|compiler1|kernel|core]" && false - @ if "$(Variant)" NEQ "tiered" if "$(Variant)" NEQ "compiler2" if "$(Variant)" NEQ "compiler1" if "$(Variant)" NEQ "kernel" if "$(Variant)" NEQ "core" \ - echo Need to specify "Variant=[tiered|compiler2|compiler1|kernel|core]" && false + @ if "$(Variant)"=="" echo Need to specify "Variant=[tiered|compiler2|compiler1|core]" && false + @ if "$(Variant)" NEQ "tiered" if "$(Variant)" NEQ "compiler2" if "$(Variant)" NEQ "compiler1" if "$(Variant)" NEQ "core" \ + echo Need to specify "Variant=[tiered|compiler2|compiler1|core]" && false checkWorkSpace: @ if "$(WorkSpace)"=="" echo Need to specify "WorkSpace=..." && false diff -r 3d641132f83b -r 124ca22437b1 make/windows/create.bat --- a/make/windows/create.bat Tue Feb 26 16:16:54 2013 -0800 +++ b/make/windows/create.bat Fri Apr 12 10:14:42 2013 +0100 @@ -148,7 +148,7 @@ REM This is now safe to do. :copyfiles -for /D %%i in (compiler1, compiler2, tiered, core, kernel) do ( +for /D %%i in (compiler1, compiler2, tiered, core) do ( if NOT EXIST %HotSpotBuildSpace%\%%i\generated mkdir %HotSpotBuildSpace%\%%i\generated copy %HotSpotWorkSpace%\make\windows\projectfiles\%%i\* %HotSpotBuildSpace%\%%i\generated > NUL ) @@ -156,7 +156,7 @@ REM force regneration of ProjectFile if exist %ProjectFile% del %ProjectFile% -for /D %%i in (compiler1, compiler2, tiered, core, kernel) do ( +for /D %%i in (compiler1, compiler2, tiered, core) do ( echo -- %%i -- echo # Generated file! > %HotSpotBuildSpace%\%%i\local.make echo # Changing a variable below and then deleting %ProjectFile% will cause >> %HotSpotBuildSpace%\%%i\local.make diff -r 3d641132f83b -r 124ca22437b1 make/windows/makefiles/compile.make --- a/make/windows/makefiles/compile.make Tue Feb 26 16:16:54 2013 -0800 +++ b/make/windows/makefiles/compile.make Fri Apr 12 10:14:42 2013 +0100 @@ -221,13 +221,6 @@ !endif !endif -# Compile for space above time. -!if "$(Variant)" == "kernel" -PRODUCT_OPT_OPTION = /O1 /Oy- -FASTDEBUG_OPT_OPTION = /O1 /Oy- -DEBUG_OPT_OPTION = /Od -!endif - # If NO_OPTIMIZATIONS is defined in the environment, turn everything off !ifdef NO_OPTIMIZATIONS PRODUCT_OPT_OPTION = $(DEBUG_OPT_OPTION) diff -r 3d641132f83b -r 124ca22437b1 make/windows/makefiles/product.make --- a/make/windows/makefiles/product.make Tue Feb 26 16:16:54 2013 -0800 +++ b/make/windows/makefiles/product.make Fri Apr 12 10:14:42 2013 +0100 @@ -51,13 +51,6 @@ # Force resources to be rebuilt every time $(Res_Files): FORCE -# Kernel doesn't need exported vtbl symbols. -!if "$(Variant)" == "kernel" -$(AOUT): $(Res_Files) $(Obj_Files) - $(LD) @<< - $(LD_FLAGS) /out:$@ /implib:$*.lib $(Obj_Files) $(Res_Files) -<< -!else vm.def: $(Obj_Files) sh $(WorkSpace)/make/windows/build_vm_def.sh @@ -65,7 +58,6 @@ $(LD) @<< $(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) << -!endif !if "$(MT)" != "" # The previous link command created a .manifest file that we want to # insert into the linked artifact so we do not need to track it diff -r 3d641132f83b -r 124ca22437b1 make/windows/makefiles/vm.make --- a/make/windows/makefiles/vm.make Tue Feb 26 16:16:54 2013 -0800 +++ b/make/windows/makefiles/vm.make Fri Apr 12 10:14:42 2013 +0100 @@ -89,12 +89,8 @@ # AsyncGetCallTrace is not supported on IA64 yet AGCT_EXPORT= !else -!if "$(Variant)" == "kernel" -AGCT_EXPORT= -!else AGCT_EXPORT=/export:AsyncGetCallTrace !endif -!endif # If you modify exports below please do the corresponding changes in # src/share/tools/ProjectCreator/WinGammaPlatformVC7.java diff -r 3d641132f83b -r 124ca22437b1 make/windows/projectfiles/kernel/Makefile --- a/make/windows/projectfiles/kernel/Makefile Tue Feb 26 16:16:54 2013 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -# -# Copyright (c) 2007, 2010, 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. -# -# - -!include ../local.make - -!include $(HOTSPOTWORKSPACE)/make/windows/projectfiles/common/Makefile diff -r 3d641132f83b -r 124ca22437b1 make/windows/projectfiles/kernel/vm.def --- a/make/windows/projectfiles/kernel/vm.def Tue Feb 26 16:16:54 2013 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -; -; This .DEF file is a placeholder for one which is automatically -; generated during the build process. See -; make\windows\build_vm_def.sh and -; make\windows\makefiles\projectcreator.make (esp. the "-prelink" -; options). -; diff -r 3d641132f83b -r 124ca22437b1 make/windows/projectfiles/kernel/vm.dsw --- a/make/windows/projectfiles/kernel/vm.dsw Tue Feb 26 16:16:54 2013 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "vm"=.\vm.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff -r 3d641132f83b -r 124ca22437b1 src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp --- a/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -51,6 +51,16 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); + if (_info->deoptimize_on_exception()) { + address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id); + __ call(a, relocInfo::runtime_call_type); + __ delayed()->nop(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ should_not_reach_here()); + return; + } + if (_index->is_register()) { __ mov(_index->as_register(), G4); } else { @@ -64,11 +74,22 @@ __ delayed()->nop(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); -#ifdef ASSERT - __ should_not_reach_here(); -#endif + debug_only(__ should_not_reach_here()); +} + +PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) { + _info = new CodeEmitInfo(info); } +void PredicateFailedStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id); + __ call(a, relocInfo::runtime_call_type); + __ delayed()->nop(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ should_not_reach_here()); +} void CounterOverflowStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); @@ -99,10 +120,17 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { + address a; + if (_info->deoptimize_on_exception()) { + // Deoptimize, do not throw the exception, because it is probably wrong to do it here. + a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id); + } else { + a = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id); + } + ce->compilation()->implicit_exception_table()->append(_offset, __ offset()); __ bind(_entry); - __ call(Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id), - relocInfo::runtime_call_type); + __ call(a, relocInfo::runtime_call_type); __ delayed()->nop(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); diff -r 3d641132f83b -r 124ca22437b1 src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp --- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -3361,6 +3361,45 @@ __ mov(G2_thread, result_reg->as_register()); } +#ifdef ASSERT +// emit run-time assertion +void LIR_Assembler::emit_assert(LIR_OpAssert* op) { + assert(op->code() == lir_assert, "must be"); + + if (op->in_opr1()->is_valid()) { + assert(op->in_opr2()->is_valid(), "both operands must be valid"); + comp_op(op->condition(), op->in_opr1(), op->in_opr2(), op); + } else { + assert(op->in_opr2()->is_illegal(), "both operands must be illegal"); + assert(op->condition() == lir_cond_always, "no other conditions allowed"); + } + + Label ok; + if (op->condition() != lir_cond_always) { + Assembler::Condition acond; + switch (op->condition()) { + case lir_cond_equal: acond = Assembler::equal; break; + case lir_cond_notEqual: acond = Assembler::notEqual; break; + case lir_cond_less: acond = Assembler::less; break; + case lir_cond_lessEqual: acond = Assembler::lessEqual; break; + case lir_cond_greaterEqual: acond = Assembler::greaterEqual; break; + case lir_cond_greater: acond = Assembler::greater; break; + case lir_cond_aboveEqual: acond = Assembler::greaterEqualUnsigned; break; + case lir_cond_belowEqual: acond = Assembler::lessEqualUnsigned; break; + default: ShouldNotReachHere(); + }; + __ br(acond, false, Assembler::pt, ok); + __ delayed()->nop(); + } + if (op->halt()) { + const char* str = __ code_string(op->msg()); + __ stop(str); + } else { + breakpoint(); + } + __ bind(ok); +} +#endif void LIR_Assembler::peephole(LIR_List* lir) { LIR_OpList* inst = lir->instructions_list(); diff -r 3d641132f83b -r 124ca22437b1 src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp --- a/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -324,7 +324,7 @@ void LIRGenerator::do_StoreIndexed(StoreIndexed* x) { assert(x->is_pinned(),""); - bool needs_range_check = true; + bool needs_range_check = x->compute_needs_range_check(); bool use_length = x->length() != NULL; bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT; bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL || @@ -339,12 +339,9 @@ array.load_item(); index.load_nonconstant(); - if (use_length) { - needs_range_check = x->compute_needs_range_check(); - if (needs_range_check) { - length.set_instruction(x->length()); - length.load_item(); - } + if (use_length && needs_range_check) { + length.set_instruction(x->length()); + length.load_item(); } if (needs_store_check) { value.load_item(); diff -r 3d641132f83b -r 124ca22437b1 src/cpu/sparc/vm/c1_Runtime1_sparc.cpp --- a/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -987,6 +987,25 @@ break; #endif // INCLUDE_ALL_GCS + case predicate_failed_trap_id: + { + __ set_info("predicate_failed_trap", dont_gc_arguments); + OopMap* oop_map = save_live_registers(sasm); + + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, predicate_failed_trap)); + + oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + + DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); + assert(deopt_blob != NULL, "deoptimization blob must have been created"); + restore_live_registers(sasm); + __ restore(); + __ br(Assembler::always, false, Assembler::pt, deopt_blob->unpack_with_reexecution(), relocInfo::runtime_call_type); + __ delayed()->nop(); + } + break; + default: { __ set_info("unimplemented entry", dont_gc_arguments); __ save_frame(0); diff -r 3d641132f83b -r 124ca22437b1 src/cpu/sparc/vm/macroAssembler_sparc.cpp --- a/src/cpu/sparc/vm/macroAssembler_sparc.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/sparc/vm/macroAssembler_sparc.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -1385,13 +1385,13 @@ } #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 @@ // 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 @@ // in order to run automated test scripts on the VM // Use the flag ShowMessageBoxOnError - char* b = new char[1024]; - sprintf(b, "untested: %s", what); - + const char* b = NULL; + { + ResourceMark rm; + stringStream ss; + ss.print("untested: %s", what); + b = code_string(ss.as_string()); + } if (ShowMessageBoxOnError) { STOP(b); } else { warn(b); } } diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/assembler_x86.cpp --- a/src/cpu/x86/vm/assembler_x86.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/assembler_x86.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -214,14 +214,6 @@ return enc; } -static int encode(XMMRegister r) { - int enc = r->encoding(); - if (enc >= 8) { - enc -= 8; - } - return enc; -} - void Assembler::emit_arith_b(int op1, int op2, Register dst, int imm8) { assert(dst->has_byte_register(), "must have byte register"); assert(isByte(op1) && isByte(op2), "wrong opcode"); diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/c1_CodeStubs_x86.cpp --- a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -101,6 +101,15 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); + if (_info->deoptimize_on_exception()) { + address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id); + __ call(RuntimeAddress(a)); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ should_not_reach_here()); + return; + } + // pass the array index on stack because all registers must be preserved if (_index->is_cpu_register()) { ce->store_parameter(_index->as_register(), 0); @@ -115,9 +124,22 @@ } __ call(RuntimeAddress(Runtime1::entry_for(stub_id))); ce->add_call_info_here(_info); + ce->verify_oop_map(_info); debug_only(__ should_not_reach_here()); } +PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) { + _info = new CodeEmitInfo(info); +} + +void PredicateFailedStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id); + __ call(RuntimeAddress(a)); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ should_not_reach_here()); +} void DivByZeroStub::emit_code(LIR_Assembler* ce) { if (_offset != -1) { @@ -414,10 +436,19 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { + address a; + if (_info->deoptimize_on_exception()) { + // Deoptimize, do not throw the exception, because it is probably wrong to do it here. + a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id); + } else { + a = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id); + } + ce->compilation()->implicit_exception_table()->append(_offset, __ offset()); __ bind(_entry); - __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id))); + __ call(RuntimeAddress(a)); ce->add_call_info_here(_info); + ce->verify_oop_map(_info); debug_only(__ should_not_reach_here()); } diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/c1_LIRAssembler_x86.cpp --- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -3755,6 +3755,44 @@ } } +#ifdef ASSERT +// emit run-time assertion +void LIR_Assembler::emit_assert(LIR_OpAssert* op) { + assert(op->code() == lir_assert, "must be"); + + if (op->in_opr1()->is_valid()) { + assert(op->in_opr2()->is_valid(), "both operands must be valid"); + comp_op(op->condition(), op->in_opr1(), op->in_opr2(), op); + } else { + assert(op->in_opr2()->is_illegal(), "both operands must be illegal"); + assert(op->condition() == lir_cond_always, "no other conditions allowed"); + } + + Label ok; + if (op->condition() != lir_cond_always) { + Assembler::Condition acond = Assembler::zero; + switch (op->condition()) { + case lir_cond_equal: acond = Assembler::equal; break; + case lir_cond_notEqual: acond = Assembler::notEqual; break; + case lir_cond_less: acond = Assembler::less; break; + case lir_cond_lessEqual: acond = Assembler::lessEqual; break; + case lir_cond_greaterEqual: acond = Assembler::greaterEqual;break; + case lir_cond_greater: acond = Assembler::greater; break; + case lir_cond_belowEqual: acond = Assembler::belowEqual; break; + case lir_cond_aboveEqual: acond = Assembler::aboveEqual; break; + default: ShouldNotReachHere(); + } + __ jcc(acond, ok); + } + if (op->halt()) { + const char* str = __ code_string(op->msg()); + __ stop(str); + } else { + breakpoint(); + } + __ bind(ok); +} +#endif void LIR_Assembler::membar() { // QQQ sparc TSO uses this, diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/c1_LIRGenerator_x86.cpp --- a/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -263,7 +263,7 @@ void LIRGenerator::do_StoreIndexed(StoreIndexed* x) { assert(x->is_pinned(),""); - bool needs_range_check = true; + bool needs_range_check = x->compute_needs_range_check(); bool use_length = x->length() != NULL; bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT; bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL || @@ -278,12 +278,10 @@ array.load_item(); index.load_nonconstant(); - if (use_length) { - needs_range_check = x->compute_needs_range_check(); - if (needs_range_check) { - length.set_instruction(x->length()); - length.load_item(); - } + if (use_length && needs_range_check) { + length.set_instruction(x->length()); + length.load_item(); + } if (needs_store_check) { value.load_item(); diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/c1_LinearScan_x86.cpp --- a/src/cpu/x86/vm/c1_LinearScan_x86.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/c1_LinearScan_x86.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -675,7 +675,8 @@ switch (op2->code()) { case lir_cmp: case lir_cmp_fd2i: - case lir_ucmp_fd2i: { + case lir_ucmp_fd2i: + case lir_assert: { assert(left->is_fpu_register(), "invalid LIR"); assert(right->is_fpu_register(), "invalid LIR"); diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/c1_Runtime1_x86.cpp --- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -1807,6 +1807,24 @@ break; #endif // INCLUDE_ALL_GCS + case predicate_failed_trap_id: + { + StubFrame f(sasm, "predicate_failed_trap", dont_gc_arguments); + + OopMap* map = save_live_registers(sasm, 1); + + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, predicate_failed_trap)); + oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, map); + restore_live_registers(sasm); + __ leave(); + DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); + assert(deopt_blob != NULL, "deoptimization blob must have been created"); + + __ jump(RuntimeAddress(deopt_blob->unpack_with_reexecution())); + } + break; + default: { StubFrame f(sasm, "unimplemented entry", dont_gc_arguments); __ movptr(rax, (int)id); diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/cppInterpreter_x86.cpp --- a/src/cpu/x86/vm/cppInterpreter_x86.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/cppInterpreter_x86.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -1299,25 +1299,8 @@ __ push(rdx); #endif // _LP64 - // Either restore the MXCSR register after returning from the JNI Call - // or verify that it wasn't changed. - if (VM_Version::supports_sse()) { - if (RestoreMXCSROnJNICalls) { - __ ldmxcsr(ExternalAddress(StubRoutines::addr_mxcsr_std())); - } - else if (CheckJNICalls ) { - __ call(RuntimeAddress(StubRoutines::x86::verify_mxcsr_entry())); - } - } - -#ifndef _LP64 - // Either restore the x87 floating pointer control word after returning - // from the JNI call or verify that it wasn't changed. - if (CheckJNICalls) { - __ call(RuntimeAddress(StubRoutines::x86::verify_fpu_cntrl_wrd_entry())); - } -#endif // _LP64 - + // Verify or restore cpu control state after JNI call + __ restore_cpu_control_state_after_jni(); // change thread state __ movl(Address(thread, JavaThread::thread_state_offset()), _thread_in_native_trans); diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/frame_x86.inline.hpp --- a/src/cpu/x86/vm/frame_x86.inline.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/frame_x86.inline.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -295,14 +295,18 @@ return true; } - +inline oop frame::saved_oop_result(RegisterMap* map) const { + oop* result_adr = (oop *)map->location(rax->as_VMReg()); + guarantee(result_adr != NULL, "bad register save location"); -inline oop frame::saved_oop_result(RegisterMap* map) const { - return *((oop*) map->location(rax->as_VMReg())); + return (*result_adr); } inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) { - *((oop*) map->location(rax->as_VMReg())) = obj; + oop* result_adr = (oop *)map->location(rax->as_VMReg()); + guarantee(result_adr != NULL, "bad register save location"); + + *result_adr = obj; } #endif // CPU_X86_VM_FRAME_X86_INLINE_HPP diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/macroAssembler_x86.cpp --- a/src/cpu/x86/vm/macroAssembler_x86.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/macroAssembler_x86.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -4262,8 +4262,13 @@ 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 @@ { 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 @@ // 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 @@ -4751,6 +4765,31 @@ pop_CPU_state(); } +void MacroAssembler::restore_cpu_control_state_after_jni() { + // Either restore the MXCSR register after returning from the JNI Call + // or verify that it wasn't changed (with -Xcheck:jni flag). + if (VM_Version::supports_sse()) { + if (RestoreMXCSROnJNICalls) { + ldmxcsr(ExternalAddress(StubRoutines::addr_mxcsr_std())); + } else if (CheckJNICalls) { + call(RuntimeAddress(StubRoutines::x86::verify_mxcsr_entry())); + } + } + if (VM_Version::supports_avx()) { + // Clear upper bits of YMM registers to avoid SSE <-> AVX transition penalty. + vzeroupper(); + } + +#ifndef _LP64 + // Either restore the x87 floating pointer control word after returning + // from the JNI call or verify that it wasn't changed. + if (CheckJNICalls) { + call(RuntimeAddress(StubRoutines::x86::verify_fpu_cntrl_wrd_entry())); + } +#endif // _LP64 +} + + void MacroAssembler::load_klass(Register dst, Register src) { #ifdef _LP64 if (UseCompressedKlassPointers) { @@ -5745,6 +5784,8 @@ addptr(result, stride2); subl(cnt2, stride2); jccb(Assembler::notZero, COMPARE_WIDE_VECTORS_LOOP); + // clean upper bits of YMM registers + vzeroupper(); // compare wide vectors tail bind(COMPARE_WIDE_TAIL); @@ -5758,6 +5799,8 @@ // Identifies the mismatching (higher or lower)16-bytes in the 32-byte vectors. bind(VECTOR_NOT_EQUAL); + // clean upper bits of YMM registers + vzeroupper(); lea(str1, Address(str1, result, scale)); lea(str2, Address(str2, result, scale)); jmp(COMPARE_16_CHARS); @@ -6014,6 +6057,10 @@ // That's it bind(DONE); + if (UseAVX >= 2) { + // clean upper bits of YMM registers + vzeroupper(); + } } void MacroAssembler::generate_fill(BasicType t, bool aligned, @@ -6143,6 +6190,10 @@ vmovdqu(Address(to, 0), xtmp); addptr(to, 32); subl(count, 8 << shift); + + BIND(L_check_fill_8_bytes); + // clean upper bits of YMM registers + vzeroupper(); } else { // Fill 32-byte chunks pshufd(xtmp, xtmp, 0); @@ -6166,8 +6217,9 @@ addptr(to, 32); subl(count, 8 << shift); jcc(Assembler::greaterEqual, L_fill_32_bytes_loop); + + BIND(L_check_fill_8_bytes); } - BIND(L_check_fill_8_bytes); addl(count, 8 << shift); jccb(Assembler::zero, L_exit); jmpb(L_fill_8_bytes); @@ -6302,6 +6354,10 @@ jccb(Assembler::lessEqual, L_copy_16_chars); bind(L_copy_16_chars_exit); + if (UseAVX >= 2) { + // clean upper bits of YMM registers + vzeroupper(); + } subptr(len, 8); jccb(Assembler::greater, L_copy_8_chars_exit); diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/macroAssembler_x86.hpp --- a/src/cpu/x86/vm/macroAssembler_x86.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/macroAssembler_x86.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -582,6 +582,9 @@ // only if +VerifyFPU void verify_FPU(int stack_depth, const char* s = "illegal FPU state"); + // Verify or restore cpu control state after JNI call + void restore_cpu_control_state_after_jni(); + // prints msg, dumps registers and stops execution void stop(const char* msg); diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/methodHandles_x86.cpp --- a/src/cpu/x86/vm/methodHandles_x86.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/methodHandles_x86.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -41,11 +41,6 @@ #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") -// Workaround for C++ overloading nastiness on '0' for RegisterOrConstant. -static RegisterOrConstant constant(int value) { - return RegisterOrConstant(value); -} - void MethodHandles::load_klass_from_Class(MacroAssembler* _masm, Register klass_reg) { if (VerifyMethodHandles) verify_klass(_masm, klass_reg, SystemDictionary::WK_KLASS_ENUM_NAME(java_lang_Class), diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/relocInfo_x86.cpp --- a/src/cpu/x86/vm/relocInfo_x86.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/relocInfo_x86.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -145,12 +145,9 @@ assert(which == Assembler::disp32_operand || which == Assembler::call32_operand || which == Assembler::imm_operand, "format unpacks ok"); - if (which != Assembler::imm_operand) { - // The "address" in the code is a displacement can't return it as - // and address* since it is really a jint* - ShouldNotReachHere(); - return NULL; - } + // The "address" in the code is a displacement can't return it as + // and address* since it is really a jint* + guarantee(which == Assembler::imm_operand, "must be immediate operand"); #else assert(which == Assembler::disp32_operand || which == Assembler::imm_operand, "format unpacks ok"); #endif // AMD64 diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/sharedRuntime_x86_32.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -2065,6 +2065,9 @@ __ call(RuntimeAddress(native_func)); + // Verify or restore cpu control state after JNI call + __ restore_cpu_control_state_after_jni(); + // WARNING - on Windows Java Natives use pascal calling convention and pop the // arguments off of the stack. We could just re-adjust the stack pointer here // and continue to do SP relative addressing but we instead switch to FP diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -2315,16 +2315,8 @@ __ call(RuntimeAddress(native_func)); - // Either restore the MXCSR register after returning from the JNI Call - // or verify that it wasn't changed. - if (RestoreMXCSROnJNICalls) { - __ ldmxcsr(ExternalAddress(StubRoutines::x86::mxcsr_std())); - - } - else if (CheckJNICalls ) { - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::x86::verify_mxcsr_entry()))); - } - + // Verify or restore cpu control state after JNI call + __ restore_cpu_control_state_after_jni(); // Unpack native results. switch (ret_type) { diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/stubGenerator_x86_32.cpp --- a/src/cpu/x86/vm/stubGenerator_x86_32.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/stubGenerator_x86_32.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -835,6 +835,11 @@ __ BIND(L_copy_64_bytes); __ subl(qword_count, 8); __ jcc(Assembler::greaterEqual, L_copy_64_bytes_loop); + + if (UseUnalignedLoadStores && (UseAVX >= 2)) { + // clean upper bits of YMM registers + __ vzeroupper(); + } __ addl(qword_count, 8); __ jccb(Assembler::zero, L_exit); // diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/stubGenerator_x86_64.cpp --- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -1331,6 +1331,10 @@ } __ addptr(qword_count, 4); __ BIND(L_end); + if (UseAVX >= 2) { + // clean upper bits of YMM registers + __ vzeroupper(); + } } else { // Copy 32-bytes per iteration __ BIND(L_loop); @@ -1404,6 +1408,10 @@ } __ subptr(qword_count, 4); __ BIND(L_end); + if (UseAVX >= 2) { + // clean upper bits of YMM registers + __ vzeroupper(); + } } else { // Copy 32-bytes per iteration __ BIND(L_loop); diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/templateInterpreter_x86_32.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -1080,22 +1080,8 @@ // result potentially in rdx:rax or ST0 - // Either restore the MXCSR register after returning from the JNI Call - // or verify that it wasn't changed. - if (VM_Version::supports_sse()) { - if (RestoreMXCSROnJNICalls) { - __ ldmxcsr(ExternalAddress(StubRoutines::addr_mxcsr_std())); - } - else if (CheckJNICalls ) { - __ call(RuntimeAddress(StubRoutines::x86::verify_mxcsr_entry())); - } - } - - // Either restore the x87 floating pointer control word after returning - // from the JNI call or verify that it wasn't changed. - if (CheckJNICalls) { - __ call(RuntimeAddress(StubRoutines::x86::verify_fpu_cntrl_wrd_entry())); - } + // Verify or restore cpu control state after JNI call + __ restore_cpu_control_state_after_jni(); // save potential result in ST(0) & rdx:rax // (if result handler is the T_FLOAT or T_DOUBLE handler, result must be in ST0 - diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/templateInterpreter_x86_64.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -1079,15 +1079,8 @@ __ call(rax); // result potentially in rax or xmm0 - // Depending on runtime options, either restore the MXCSR - // register after returning from the JNI Call or verify that - // it wasn't changed during -Xcheck:jni. - if (RestoreMXCSROnJNICalls) { - __ ldmxcsr(ExternalAddress(StubRoutines::x86::mxcsr_std())); - } - else if (CheckJNICalls) { - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::x86::verify_mxcsr_entry()))); - } + // Verify or restore cpu control state after JNI call + __ restore_cpu_control_state_after_jni(); // NOTE: The order of these pushes is known to frame::interpreter_frame_result // in order to extract the result of a method call. If the order of these diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/x86_32.ad --- a/src/cpu/x86/vm/x86_32.ad Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/x86_32.ad Fri Apr 12 10:14:42 2013 +0100 @@ -228,10 +228,16 @@ static jlong *double_signflip_pool = double_quadword(&fp_signmask_pool[4*2], CONST64(0x8000000000000000), CONST64(0x8000000000000000)); // Offset hacking within calls. -static int pre_call_FPU_size() { - if (Compile::current()->in_24_bit_fp_mode()) - return 6; // fldcw - return 0; +static int pre_call_resets_size() { + int size = 0; + Compile* C = Compile::current(); + if (C->in_24_bit_fp_mode()) { + size += 6; // fldcw + } + if (C->max_vector_size() > 16) { + size += 3; // vzeroupper + } + return size; } static int preserve_SP_size() { @@ -242,21 +248,21 @@ // from the start of the call to the point where the return address // will point. int MachCallStaticJavaNode::ret_addr_offset() { - int offset = 5 + pre_call_FPU_size(); // 5 bytes from start of call to where return address points + int offset = 5 + pre_call_resets_size(); // 5 bytes from start of call to where return address points if (_method_handle_invoke) offset += preserve_SP_size(); return offset; } int MachCallDynamicJavaNode::ret_addr_offset() { - return 10 + pre_call_FPU_size(); // 10 bytes from start of call to where return address points + return 10 + pre_call_resets_size(); // 10 bytes from start of call to where return address points } static int sizeof_FFree_Float_Stack_All = -1; int MachCallRuntimeNode::ret_addr_offset() { assert(sizeof_FFree_Float_Stack_All != -1, "must have been emitted already"); - return sizeof_FFree_Float_Stack_All + 5 + pre_call_FPU_size(); + return sizeof_FFree_Float_Stack_All + 5 + pre_call_resets_size(); } // Indicate if the safepoint node needs the polling page as an input. @@ -272,7 +278,7 @@ // The address of the call instruction needs to be 4-byte aligned to // ensure that it does not span a cache line so that it can be patched. int CallStaticJavaDirectNode::compute_padding(int current_offset) const { - current_offset += pre_call_FPU_size(); // skip fldcw, if any + current_offset += pre_call_resets_size(); // skip fldcw, if any current_offset += 1; // skip call opcode byte return round_to(current_offset, alignment_required()) - current_offset; } @@ -280,7 +286,7 @@ // The address of the call instruction needs to be 4-byte aligned to // ensure that it does not span a cache line so that it can be patched. int CallStaticJavaHandleNode::compute_padding(int current_offset) const { - current_offset += pre_call_FPU_size(); // skip fldcw, if any + current_offset += pre_call_resets_size(); // skip fldcw, if any current_offset += preserve_SP_size(); // skip mov rbp, rsp current_offset += 1; // skip call opcode byte return round_to(current_offset, alignment_required()) - current_offset; @@ -289,7 +295,7 @@ // The address of the call instruction needs to be 4-byte aligned to // ensure that it does not span a cache line so that it can be patched. int CallDynamicJavaDirectNode::compute_padding(int current_offset) const { - current_offset += pre_call_FPU_size(); // skip fldcw, if any + current_offset += pre_call_resets_size(); // skip fldcw, if any current_offset += 5; // skip MOV instruction current_offset += 1; // skip call opcode byte return round_to(current_offset, alignment_required()) - current_offset; @@ -583,16 +589,20 @@ // Remove two words for return addr and rbp, framesize -= 2*wordSize; - if( C->in_24_bit_fp_mode() ) { + if (C->max_vector_size() > 16) { + st->print("VZEROUPPER"); + st->cr(); st->print("\t"); + } + if (C->in_24_bit_fp_mode()) { st->print("FLDCW standard control word"); st->cr(); st->print("\t"); } - if( framesize ) { + if (framesize) { st->print("ADD ESP,%d\t# Destroy frame",framesize); st->cr(); st->print("\t"); } st->print_cr("POPL EBP"); st->print("\t"); - if( do_polling() && C->is_method_compilation() ) { + if (do_polling() && C->is_method_compilation()) { st->print("TEST PollPage,EAX\t! Poll Safepoint"); st->cr(); st->print("\t"); } @@ -602,8 +612,14 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { Compile *C = ra_->C; + if (C->max_vector_size() > 16) { + // Clear upper bits of YMM registers when current compiled code uses + // wide vectors to avoid AVX <-> SSE transition penalty during call. + MacroAssembler masm(&cbuf); + masm.vzeroupper(); + } // If method set FPU control word, restore to standard control word - if( C->in_24_bit_fp_mode() ) { + if (C->in_24_bit_fp_mode()) { MacroAssembler masm(&cbuf); masm.fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std())); } @@ -615,12 +631,11 @@ // Note that VerifyStackAtCalls' Majik cookie does not change the frame size popped here - if( framesize >= 128 ) { + if (framesize >= 128) { emit_opcode(cbuf, 0x81); // add SP, #framesize emit_rm(cbuf, 0x3, 0x00, ESP_enc); emit_d32(cbuf, framesize); - } - else if( framesize ) { + } else if (framesize) { emit_opcode(cbuf, 0x83); // add SP, #framesize emit_rm(cbuf, 0x3, 0x00, ESP_enc); emit_d8(cbuf, framesize); @@ -628,7 +643,7 @@ emit_opcode(cbuf, 0x58 | EBP_enc); - if( do_polling() && C->is_method_compilation() ) { + if (do_polling() && C->is_method_compilation()) { cbuf.relocate(cbuf.insts_end(), relocInfo::poll_return_type, 0); emit_opcode(cbuf,0x85); emit_rm(cbuf, 0x0, EAX_enc, 0x5); // EAX @@ -640,7 +655,8 @@ Compile *C = ra_->C; // If method set FPU control word, restore to standard control word int size = C->in_24_bit_fp_mode() ? 6 : 0; - if( do_polling() && C->is_method_compilation() ) size += 6; + if (C->max_vector_size() > 16) size += 3; // vzeroupper + if (do_polling() && C->is_method_compilation()) size += 6; int framesize = C->frame_slots() << LogBytesPerInt; assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned"); @@ -649,7 +665,7 @@ size++; // popl rbp, - if( framesize >= 128 ) { + if (framesize >= 128) { size += 6; } else { size += framesize ? 3 : 0; @@ -1853,20 +1869,26 @@ %} - enc_class pre_call_FPU %{ + enc_class pre_call_resets %{ // If method sets FPU control word restore it here debug_only(int off0 = cbuf.insts_size()); - if( Compile::current()->in_24_bit_fp_mode() ) { - MacroAssembler masm(&cbuf); - masm.fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std())); + if (ra_->C->in_24_bit_fp_mode()) { + MacroAssembler _masm(&cbuf); + __ fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std())); + } + if (ra_->C->max_vector_size() > 16) { + // Clear upper bits of YMM registers when current compiled code uses + // wide vectors to avoid AVX <-> SSE transition penalty during call. + MacroAssembler _masm(&cbuf); + __ vzeroupper(); } debug_only(int off1 = cbuf.insts_size()); - assert(off1 - off0 == pre_call_FPU_size(), "correct size prediction"); + assert(off1 - off0 == pre_call_resets_size(), "correct size prediction"); %} enc_class post_call_FPU %{ // If method sets FPU control word do it here also - if( Compile::current()->in_24_bit_fp_mode() ) { + if (Compile::current()->in_24_bit_fp_mode()) { MacroAssembler masm(&cbuf); masm.fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_24())); } @@ -1877,17 +1899,17 @@ // who we intended to call. cbuf.set_insts_mark(); $$$emit8$primary; - if ( !_method ) { + if (!_method) { emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4), runtime_call_Relocation::spec(), RELOC_IMM32 ); - } else if(_optimized_virtual) { + } else if (_optimized_virtual) { emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4), opt_virtual_call_Relocation::spec(), RELOC_IMM32 ); } else { emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4), static_call_Relocation::spec(), RELOC_IMM32 ); } - if( _method ) { // Emit stub for static call + if (_method) { // Emit stub for static call emit_java_to_interp(cbuf); } %} @@ -12828,7 +12850,7 @@ ins_cost(300); format %{ "CALL,static " %} opcode(0xE8); /* E8 cd */ - ins_encode( pre_call_FPU, + ins_encode( pre_call_resets, Java_Static_Call( meth ), call_epilog, post_call_FPU ); @@ -12849,7 +12871,7 @@ ins_cost(300); format %{ "CALL,static/MethodHandle " %} opcode(0xE8); /* E8 cd */ - ins_encode( pre_call_FPU, + ins_encode( pre_call_resets, preserve_SP, Java_Static_Call( meth ), restore_SP, @@ -12870,7 +12892,7 @@ format %{ "MOV EAX,(oop)-1\n\t" "CALL,dynamic" %} opcode(0xE8); /* E8 cd */ - ins_encode( pre_call_FPU, + ins_encode( pre_call_resets, Java_Dynamic_Call( meth ), call_epilog, post_call_FPU ); @@ -12887,7 +12909,7 @@ format %{ "CALL,runtime " %} opcode(0xE8); /* E8 cd */ // Use FFREEs to clear entries in float stack - ins_encode( pre_call_FPU, + ins_encode( pre_call_resets, FFree_Float_Stack_All, Java_To_Runtime( meth ), post_call_FPU ); @@ -12902,7 +12924,7 @@ ins_cost(300); format %{ "CALL_LEAF,runtime " %} opcode(0xE8); /* E8 cd */ - ins_encode( pre_call_FPU, + ins_encode( pre_call_resets, FFree_Float_Stack_All, Java_To_Runtime( meth ), Verify_FPU_For_Leaf, post_call_FPU ); diff -r 3d641132f83b -r 124ca22437b1 src/cpu/x86/vm/x86_64.ad --- a/src/cpu/x86/vm/x86_64.ad Tue Feb 26 16:16:54 2013 -0800 +++ b/src/cpu/x86/vm/x86_64.ad Fri Apr 12 10:14:42 2013 +0100 @@ -399,6 +399,9 @@ static int preserve_SP_size() { return 3; // rex.w, op, rm(reg/reg) } +static int clear_avx_size() { + return (Compile::current()->max_vector_size() > 16) ? 3 : 0; // vzeroupper +} // !!!!! Special hack to get all types of calls to specify the byte offset // from the start of the call to the point where the return address @@ -406,6 +409,7 @@ int MachCallStaticJavaNode::ret_addr_offset() { int offset = 5; // 5 bytes from start of call to where return address points + offset += clear_avx_size(); if (_method_handle_invoke) offset += preserve_SP_size(); return offset; @@ -413,11 +417,16 @@ int MachCallDynamicJavaNode::ret_addr_offset() { - return 15; // 15 bytes from start of call to where return address points + int offset = 15; // 15 bytes from start of call to where return address points + offset += clear_avx_size(); + return offset; } -// In os_cpu .ad file -// int MachCallRuntimeNode::ret_addr_offset() +int MachCallRuntimeNode::ret_addr_offset() { + int offset = 13; // movq r10,#addr; callq (r10) + offset += clear_avx_size(); + return offset; +} // Indicate if the safepoint node needs the polling page as an input, // it does if the polling page is more than disp32 away. @@ -434,6 +443,7 @@ // ensure that it does not span a cache line so that it can be patched. int CallStaticJavaDirectNode::compute_padding(int current_offset) const { + current_offset += clear_avx_size(); // skip vzeroupper current_offset += 1; // skip call opcode byte return round_to(current_offset, alignment_required()) - current_offset; } @@ -443,6 +453,7 @@ int CallStaticJavaHandleNode::compute_padding(int current_offset) const { current_offset += preserve_SP_size(); // skip mov rbp, rsp + current_offset += clear_avx_size(); // skip vzeroupper current_offset += 1; // skip call opcode byte return round_to(current_offset, alignment_required()) - current_offset; } @@ -451,6 +462,7 @@ // ensure that it does not span a cache line so that it can be patched. int CallDynamicJavaDirectNode::compute_padding(int current_offset) const { + current_offset += clear_avx_size(); // skip vzeroupper current_offset += 11; // skip movq instruction + call opcode byte return round_to(current_offset, alignment_required()) - current_offset; } @@ -764,6 +776,11 @@ void MachEpilogNode::format(PhaseRegAlloc* ra_, outputStream* st) const { Compile* C = ra_->C; + if (C->max_vector_size() > 16) { + st->print("vzeroupper"); + st->cr(); st->print("\t"); + } + int framesize = C->frame_slots() << LogBytesPerInt; assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned"); // Remove word for return adr already pushed @@ -793,6 +810,13 @@ void MachEpilogNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const { Compile* C = ra_->C; + if (C->max_vector_size() > 16) { + // Clear upper bits of YMM registers when current compiled code uses + // wide vectors to avoid AVX <-> SSE transition penalty during call. + MacroAssembler _masm(&cbuf); + __ vzeroupper(); + } + int framesize = C->frame_slots() << LogBytesPerInt; assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned"); // Remove word for return adr already pushed @@ -1669,17 +1693,6 @@ return PTR_RBP_REG_mask(); } -static Address build_address(int b, int i, int s, int d) { - Register index = as_Register(i); - Address::ScaleFactor scale = (Address::ScaleFactor)s; - if (index == rsp) { - index = noreg; - scale = Address::no_scale; - } - Address addr(as_Register(b), index, scale, d); - return addr; -} - %} //----------ENCODING BLOCK----------------------------------------------------- @@ -2008,6 +2021,25 @@ __ bind(miss); %} + enc_class clear_avx %{ + debug_only(int off0 = cbuf.insts_size()); + if (ra_->C->max_vector_size() > 16) { + // Clear upper bits of YMM registers when current compiled code uses + // wide vectors to avoid AVX <-> SSE transition penalty during call. + MacroAssembler _masm(&cbuf); + __ vzeroupper(); + } + debug_only(int off1 = cbuf.insts_size()); + assert(off1 - off0 == clear_avx_size(), "correct size prediction"); + %} + + enc_class Java_To_Runtime(method meth) %{ + // No relocation needed + MacroAssembler _masm(&cbuf); + __ mov64(r10, (int64_t) $meth$$method); + __ call(r10); + %} + enc_class Java_To_Interpreter(method meth) %{ // CALL Java_To_Interpreter @@ -11366,7 +11398,7 @@ ins_cost(300); format %{ "call,static " %} opcode(0xE8); /* E8 cd */ - ins_encode(Java_Static_Call(meth), call_epilog); + ins_encode(clear_avx, Java_Static_Call(meth), call_epilog); ins_pipe(pipe_slow); ins_alignment(4); %} @@ -11384,7 +11416,7 @@ ins_cost(300); format %{ "call,static/MethodHandle " %} opcode(0xE8); /* E8 cd */ - ins_encode(preserve_SP, + ins_encode(clear_avx, preserve_SP, Java_Static_Call(meth), restore_SP, call_epilog); @@ -11403,7 +11435,7 @@ ins_cost(300); format %{ "movq rax, #Universe::non_oop_word()\n\t" "call,dynamic " %} - ins_encode(Java_Dynamic_Call(meth), call_epilog); + ins_encode(clear_avx, Java_Dynamic_Call(meth), call_epilog); ins_pipe(pipe_slow); ins_alignment(4); %} @@ -11416,8 +11448,7 @@ ins_cost(300); format %{ "call,runtime " %} - opcode(0xE8); /* E8 cd */ - ins_encode(Java_To_Runtime(meth)); + ins_encode(clear_avx, Java_To_Runtime(meth)); ins_pipe(pipe_slow); %} @@ -11429,8 +11460,7 @@ ins_cost(300); format %{ "call_leaf,runtime " %} - opcode(0xE8); /* E8 cd */ - ins_encode(Java_To_Runtime(meth)); + ins_encode(clear_avx, Java_To_Runtime(meth)); ins_pipe(pipe_slow); %} @@ -11442,7 +11472,6 @@ ins_cost(300); format %{ "call_leaf_nofp,runtime " %} - opcode(0xE8); /* E8 cd */ ins_encode(Java_To_Runtime(meth)); ins_pipe(pipe_slow); %} diff -r 3d641132f83b -r 124ca22437b1 src/os/bsd/vm/os_bsd.cpp --- a/src/os/bsd/vm/os_bsd.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os/bsd/vm/os_bsd.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -152,7 +152,6 @@ // utility functions static int SR_initialize(); -static int SR_finalize(); julong os::available_memory() { return Bsd::available_memory(); @@ -167,20 +166,6 @@ return Bsd::physical_memory(); } -julong os::allocatable_physical_memory(julong size) { -#ifdef _LP64 - return size; -#else - julong result = MIN2(size, (julong)3800*M); - if (!is_allocatable(result)) { - // See comments under solaris for alignment considerations - julong reasonable_size = (julong)2*G - 2 * os::vm_page_size(); - result = MIN2(size, reasonable_size); - } - return result; -#endif // _LP64 -} - //////////////////////////////////////////////////////////////////////////////// // environment support @@ -1214,6 +1199,9 @@ } else if (strchr(pname, *os::path_separator()) != NULL) { int n; char** pelements = split_path(pname, &n); + if (pelements == NULL) { + return false; + } for (int i = 0 ; i < n ; i++) { // Really shouldn't be NULL, but check can't hurt if (pelements[i] == NULL || strlen(pelements[i]) == 0) { @@ -2780,10 +2768,6 @@ return 0; } -static int SR_finalize() { - return 0; -} - // returns true on success and false on error - really an error is fatal // but this seems the normal response to library errors @@ -3592,16 +3576,6 @@ //////////////////////////////////////////////////////////////////////////////// // debug support -static address same_page(address x, address y) { - int page_bits = -os::vm_page_size(); - if ((intptr_t(x) & page_bits) == (intptr_t(y) & page_bits)) - return x; - else if (x > y) - return (address)(intptr_t(y) | ~page_bits) + 1; - else - return (address)(intptr_t(y) & page_bits); -} - bool os::find(address addr, outputStream* st) { Dl_info dlinfo; memset(&dlinfo, 0, sizeof(dlinfo)); @@ -3625,8 +3599,8 @@ if (Verbose) { // decode some bytes around the PC - address begin = same_page(addr-40, addr); - address end = same_page(addr+40, addr); + address begin = clamp_address_in_page(addr-40, addr, os::vm_page_size()); + address end = clamp_address_in_page(addr+40, addr, os::vm_page_size()); address lowest = (address) dlinfo.dli_sname; if (!lowest) lowest = (address) dlinfo.dli_fbase; if (begin < lowest) begin = lowest; diff -r 3d641132f83b -r 124ca22437b1 src/os/bsd/vm/perfMemory_bsd.cpp --- a/src/os/bsd/vm/perfMemory_bsd.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os/bsd/vm/perfMemory_bsd.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -672,15 +672,15 @@ RESTARTABLE(::open(filename, oflags), result); if (result == OS_ERR) { if (errno == ENOENT) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - "Process not found"); + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "Process not found", OS_ERR); } else if (errno == EACCES) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - "Permission denied"); + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "Permission denied", OS_ERR); } else { - THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno)); + THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); } } @@ -828,7 +828,7 @@ char* mapAddress; int result; int fd; - size_t size; + size_t size = 0; const char* luser = NULL; int mmap_prot; @@ -899,9 +899,12 @@ if (*sizep == 0) { size = sharedmem_filesize(fd, CHECK); - assert(size != 0, "unexpected size"); + } else { + size = *sizep; } + assert(size > 0, "unexpected size <= 0"); + mapAddress = (char*)::mmap((char*)0, size, mmap_prot, MAP_SHARED, fd, 0); // attempt to close the file - restart if it gets interrupted, diff -r 3d641132f83b -r 124ca22437b1 src/os/linux/vm/os_linux.cpp --- a/src/os/linux/vm/os_linux.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os/linux/vm/os_linux.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -176,7 +176,6 @@ // utility functions static int SR_initialize(); -static int SR_finalize(); julong os::available_memory() { return Linux::available_memory(); @@ -194,20 +193,6 @@ return Linux::physical_memory(); } -julong os::allocatable_physical_memory(julong size) { -#ifdef _LP64 - return size; -#else - julong result = MIN2(size, (julong)3800*M); - if (!is_allocatable(result)) { - // See comments under solaris for alignment considerations - julong reasonable_size = (julong)2*G - 2 * os::vm_page_size(); - result = MIN2(size, reasonable_size); - } - return result; -#endif // _LP64 -} - //////////////////////////////////////////////////////////////////////////////// // environment support @@ -1647,6 +1632,9 @@ } else if (strchr(pname, *os::path_separator()) != NULL) { int n; char** pelements = split_path(pname, &n); + if (pelements == NULL) { + return false; + } for (int i = 0 ; i < n ; i++) { // Really shouldn't be NULL, but check can't hurt if (pelements[i] == NULL || strlen(pelements[i]) == 0) { @@ -1811,13 +1799,15 @@ class VM_LinuxDllLoad: public VM_Operation { private: const char *_filename; + char *_ebuf; + int _ebuflen; void *_lib; public: - VM_LinuxDllLoad(const char *fn) : - _filename(fn), _lib(NULL) {} + VM_LinuxDllLoad(const char *fn, char *ebuf, int ebuflen) : + _filename(fn), _ebuf(ebuf), _ebuflen(ebuflen), _lib(NULL) {} VMOp_Type type() const { return VMOp_LinuxDllLoad; } void doit() { - _lib = os::Linux::dll_load_inner(_filename); + _lib = os::Linux::dll_load_in_vmthread(_filename, _ebuf, _ebuflen); os::Linux::_stack_is_executable = true; } void* loaded_library() { return _lib; } @@ -1865,13 +1855,13 @@ // This is for the case where the DLL has an static // constructor function that executes JNI code. We cannot // load such DLLs in the VMThread. - result = ::dlopen(filename, RTLD_LAZY); + result = os::Linux::dlopen_helper(filename, ebuf, ebuflen); } ThreadInVMfromNative tiv(jt); debug_only(VMNativeEntryWrapper vew;) - VM_LinuxDllLoad op(filename); + VM_LinuxDllLoad op(filename, ebuf, ebuflen); VMThread::execute(&op); if (LoadExecStackDllInVMThread) { result = op.loaded_library(); @@ -1883,7 +1873,7 @@ } if (!load_attempted) { - result = ::dlopen(filename, RTLD_LAZY); + result = os::Linux::dlopen_helper(filename, ebuf, ebuflen); } if (result != NULL) { @@ -1892,11 +1882,6 @@ } Elf32_Ehdr elf_head; - - // Read system error message into ebuf - // It may or may not be overwritten below - ::strncpy(ebuf, ::dlerror(), ebuflen-1); - ebuf[ebuflen-1]='\0'; int diag_msg_max_length=ebuflen-strlen(ebuf); char* diag_msg_buf=ebuf+strlen(ebuf); @@ -2039,10 +2024,19 @@ return NULL; } -void * os::Linux::dll_load_inner(const char *filename) { +void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) { + void * result = ::dlopen(filename, RTLD_LAZY); + if (result == NULL) { + ::strncpy(ebuf, ::dlerror(), ebuflen - 1); + ebuf[ebuflen-1] = '\0'; + } + return result; +} + +void * os::Linux::dll_load_in_vmthread(const char *filename, char *ebuf, int ebuflen) { void * result = NULL; if (LoadExecStackDllInVMThread) { - result = ::dlopen(filename, RTLD_LAZY); + result = dlopen_helper(filename, ebuf, ebuflen); } // Since 7019808, libjvm.so is linked with -noexecstack. If the VM loads a @@ -3663,10 +3657,6 @@ return 0; } -static int SR_finalize() { - return 0; -} - // returns true on success and false on error - really an error is fatal // but this seems the normal response to library errors @@ -4508,16 +4498,6 @@ //////////////////////////////////////////////////////////////////////////////// // debug support -static address same_page(address x, address y) { - int page_bits = -os::vm_page_size(); - if ((intptr_t(x) & page_bits) == (intptr_t(y) & page_bits)) - return x; - else if (x > y) - return (address)(intptr_t(y) | ~page_bits) + 1; - else - return (address)(intptr_t(y) & page_bits); -} - bool os::find(address addr, outputStream* st) { Dl_info dlinfo; memset(&dlinfo, 0, sizeof(dlinfo)); @@ -4541,8 +4521,8 @@ if (Verbose) { // decode some bytes around the PC - address begin = same_page(addr-40, addr); - address end = same_page(addr+40, addr); + address begin = clamp_address_in_page(addr-40, addr, os::vm_page_size()); + address end = clamp_address_in_page(addr+40, addr, os::vm_page_size()); address lowest = (address) dlinfo.dli_sname; if (!lowest) lowest = (address) dlinfo.dli_fbase; if (begin < lowest) begin = lowest; diff -r 3d641132f83b -r 124ca22437b1 src/os/linux/vm/os_linux.hpp --- a/src/os/linux/vm/os_linux.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os/linux/vm/os_linux.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -95,7 +95,8 @@ public: static bool _stack_is_executable; - static void *dll_load_inner(const char *name); + static void *dlopen_helper(const char *name, char *ebuf, int ebuflen); + static void *dll_load_in_vmthread(const char *name, char *ebuf, int ebuflen); static void init_thread_fpu_state(); static int get_fpu_control_word(); diff -r 3d641132f83b -r 124ca22437b1 src/os/linux/vm/perfMemory_linux.cpp --- a/src/os/linux/vm/perfMemory_linux.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os/linux/vm/perfMemory_linux.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -672,15 +672,15 @@ RESTARTABLE(::open(filename, oflags), result); if (result == OS_ERR) { if (errno == ENOENT) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - "Process not found"); + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "Process not found", OS_ERR); } else if (errno == EACCES) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - "Permission denied"); + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "Permission denied", OS_ERR); } else { - THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno)); + THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); } } @@ -828,7 +828,7 @@ char* mapAddress; int result; int fd; - size_t size; + size_t size = 0; const char* luser = NULL; int mmap_prot; @@ -899,9 +899,12 @@ if (*sizep == 0) { size = sharedmem_filesize(fd, CHECK); - assert(size != 0, "unexpected size"); + } else { + size = *sizep; } + assert(size > 0, "unexpected size <= 0"); + mapAddress = (char*)::mmap((char*)0, size, mmap_prot, MAP_SHARED, fd, 0); // attempt to close the file - restart if it gets interrupted, diff -r 3d641132f83b -r 124ca22437b1 src/os/posix/launcher/launcher.script --- a/src/os/posix/launcher/launcher.script Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os/posix/launcher/launcher.script Fri Apr 12 10:14:42 2013 +0100 @@ -199,7 +199,7 @@ rm -f $GDBSCR ;; dbx) - $DBX -s $MYDIR/.dbxrc $LAUNCHER $JPARAMS + $DBX -s $HOME/.dbxrc $LAUNCHER $JPARMS ;; valgrind) echo Warning: Defaulting to 16Mb heap to make Valgrind run faster, use -Xmx for larger heap diff -r 3d641132f83b -r 124ca22437b1 src/os/posix/vm/os_posix.cpp --- a/src/os/posix/vm/os_posix.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os/posix/vm/os_posix.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -188,4 +188,66 @@ st->cr(); } +bool os::has_allocatable_memory_limit(julong* limit) { + struct rlimit rlim; + int getrlimit_res = getrlimit(RLIMIT_AS, &rlim); + // if there was an error when calling getrlimit, assume that there is no limitation + // on virtual memory. + bool result; + if ((getrlimit_res != 0) || (rlim.rlim_cur == RLIM_INFINITY)) { + result = false; + } else { + *limit = (julong)rlim.rlim_cur; + result = true; + } +#ifdef _LP64 + return result; +#else + // arbitrary virtual space limit for 32 bit Unices found by testing. If + // getrlimit above returned a limit, bound it with this limit. Otherwise + // directly use it. + const julong max_virtual_limit = (julong)3800*M; + if (result) { + *limit = MIN2(*limit, max_virtual_limit); + } else { + *limit = max_virtual_limit; + } + // bound by actually allocatable memory. The algorithm uses two bounds, an + // upper and a lower limit. The upper limit is the current highest amount of + // memory that could not be allocated, the lower limit is the current highest + // amount of memory that could be allocated. + // The algorithm iteratively refines the result by halving the difference + // between these limits, updating either the upper limit (if that value could + // not be allocated) or the lower limit (if the that value could be allocated) + // until the difference between these limits is "small". + + // the minimum amount of memory we care about allocating. + const julong min_allocation_size = M; + + julong upper_limit = *limit; + + // first check a few trivial cases + if (is_allocatable(upper_limit) || (upper_limit <= min_allocation_size)) { + *limit = upper_limit; + } else if (!is_allocatable(min_allocation_size)) { + // we found that not even min_allocation_size is allocatable. Return it + // anyway. There is no point to search for a better value any more. + *limit = min_allocation_size; + } else { + // perform the binary search. + julong lower_limit = min_allocation_size; + while ((upper_limit - lower_limit) > min_allocation_size) { + julong temp_limit = ((upper_limit - lower_limit) / 2) + lower_limit; + temp_limit = align_size_down_(temp_limit, min_allocation_size); + if (is_allocatable(temp_limit)) { + lower_limit = temp_limit; + } else { + upper_limit = temp_limit; + } + } + *limit = lower_limit; + } + return true; +#endif +} diff -r 3d641132f83b -r 124ca22437b1 src/os/solaris/vm/os_solaris.cpp --- a/src/os/solaris/vm/os_solaris.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os/solaris/vm/os_solaris.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -476,24 +476,6 @@ return Solaris::physical_memory(); } -julong os::allocatable_physical_memory(julong size) { -#ifdef _LP64 - return size; -#else - julong result = MIN2(size, (julong)3835*M); - if (!is_allocatable(result)) { - // Memory allocations will be aligned but the alignment - // is not known at this point. Alignments will - // be at most to LargePageSizeInBytes. Protect - // allocations from alignments up to illegal - // values. If at this point 2G is illegal. - julong reasonable_size = (julong)2*G - 2 * LargePageSizeInBytes; - result = MIN2(size, reasonable_size); - } - return result; -#endif -} - static hrtime_t first_hrtime = 0; static const hrtime_t hrtime_hz = 1000*1000*1000; const int LOCK_BUSY = 1; @@ -1903,6 +1885,9 @@ } else if (strchr(pname, *os::path_separator()) != NULL) { int n; char** pelements = split_path(pname, &n); + if (pelements == NULL) { + return false; + } for (int i = 0 ; i < n ; i++) { // really shouldn't be NULL but what the heck, check can't hurt if (pelements[i] == NULL || strlen(pelements[i]) == 0) { @@ -5805,16 +5790,6 @@ //--------------------------------------------------------------------------------- -static address same_page(address x, address y) { - intptr_t page_bits = -os::vm_page_size(); - if ((intptr_t(x) & page_bits) == (intptr_t(y) & page_bits)) - return x; - else if (x > y) - return (address)(intptr_t(y) | ~page_bits) + 1; - else - return (address)(intptr_t(y) & page_bits); -} - bool os::find(address addr, outputStream* st) { Dl_info dlinfo; memset(&dlinfo, 0, sizeof(dlinfo)); @@ -5840,8 +5815,8 @@ if (Verbose) { // decode some bytes around the PC - address begin = same_page(addr-40, addr); - address end = same_page(addr+40, addr); + address begin = clamp_address_in_page(addr-40, addr, os::vm_page_size()); + address end = clamp_address_in_page(addr+40, addr, os::vm_page_size()); address lowest = (address) dlinfo.dli_sname; if (!lowest) lowest = (address) dlinfo.dli_fbase; if (begin < lowest) begin = lowest; diff -r 3d641132f83b -r 124ca22437b1 src/os/solaris/vm/perfMemory_solaris.cpp --- a/src/os/solaris/vm/perfMemory_solaris.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os/solaris/vm/perfMemory_solaris.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -687,15 +687,15 @@ RESTARTABLE(::open(filename, oflags), result); if (result == OS_ERR) { if (errno == ENOENT) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - "Process not found"); + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "Process not found", OS_ERR); } else if (errno == EACCES) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - "Permission denied"); + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "Permission denied", OS_ERR); } else { - THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno)); + THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR); } } @@ -843,7 +843,7 @@ char* mapAddress; int result; int fd; - size_t size; + size_t size = 0; const char* luser = NULL; int mmap_prot; @@ -914,9 +914,12 @@ if (*sizep == 0) { size = sharedmem_filesize(fd, CHECK); - assert(size != 0, "unexpected size"); + } else { + size = *sizep; } + assert(size > 0, "unexpected size <= 0"); + mapAddress = (char*)::mmap((char*)0, size, mmap_prot, MAP_SHARED, fd, 0); // attempt to close the file - restart if it gets interrupted, diff -r 3d641132f83b -r 124ca22437b1 src/os/windows/vm/os_windows.cpp --- a/src/os/windows/vm/os_windows.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os/windows/vm/os_windows.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -686,12 +686,17 @@ return win32::physical_memory(); } -julong os::allocatable_physical_memory(julong size) { +bool os::has_allocatable_memory_limit(julong* limit) { + MEMORYSTATUSEX ms; + ms.dwLength = sizeof(ms); + GlobalMemoryStatusEx(&ms); #ifdef _LP64 - return size; + *limit = (julong)ms.ullAvailVirtual; + return true; #else // Limit to 1400m because of the 2gb address space wall - return MIN2(size, (julong)1400*M); + *limit = MIN2((julong)1400*M, (julong)ms.ullAvailVirtual); + return true; #endif } @@ -1177,6 +1182,9 @@ } else if (strchr(pname, *os::path_separator()) != NULL) { int n; char** pelements = split_path(pname, &n); + if (pelements == NULL) { + return false; + } for (int i = 0 ; i < n ; i++) { char* path = pelements[i]; // Really shouldn't be NULL, but check can't hurt @@ -3768,6 +3776,8 @@ } } +static jint initSock(); + // this is called _after_ the global arguments have been parsed jint os::init_2(void) { // Allocate a single page and mark it as readable for safepoint polling @@ -3898,6 +3908,10 @@ if (!success) UseNUMAInterleaving = false; } + if (initSock() != JNI_OK) { + return JNI_ERR; + } + return JNI_OK; } @@ -4894,42 +4908,24 @@ // We don't build a headless jre for Windows bool os::is_headless_jre() { return false; } - -typedef CRITICAL_SECTION mutex_t; -#define mutexInit(m) InitializeCriticalSection(m) -#define mutexDestroy(m) DeleteCriticalSection(m) -#define mutexLock(m) EnterCriticalSection(m) -#define mutexUnlock(m) LeaveCriticalSection(m) - -static bool sock_initialized = FALSE; -static mutex_t sockFnTableMutex; - -static void initSock() { +static jint initSock() { WSADATA wsadata; if (!os::WinSock2Dll::WinSock2Available()) { - jio_fprintf(stderr, "Could not load Winsock 2 (error: %d)\n", + jio_fprintf(stderr, "Could not load Winsock (error: %d)\n", ::GetLastError()); - return; - } - if (sock_initialized == TRUE) return; - - ::mutexInit(&sockFnTableMutex); - ::mutexLock(&sockFnTableMutex); - if (os::WinSock2Dll::WSAStartup(MAKEWORD(1,1), &wsadata) != 0) { - jio_fprintf(stderr, "Could not initialize Winsock\n"); - } - sock_initialized = TRUE; - ::mutexUnlock(&sockFnTableMutex); + return JNI_ERR; + } + + if (os::WinSock2Dll::WSAStartup(MAKEWORD(2,2), &wsadata) != 0) { + jio_fprintf(stderr, "Could not initialize Winsock (error: %d)\n", + ::GetLastError()); + return JNI_ERR; + } + return JNI_OK; } struct hostent* os::get_host_by_name(char* name) { - if (!sock_initialized) { - initSock(); - } - if (!os::WinSock2Dll::WinSock2Available()) { - return NULL; - } return (struct hostent*)os::WinSock2Dll::gethostbyname(name); } diff -r 3d641132f83b -r 124ca22437b1 src/os/windows/vm/perfMemory_windows.cpp --- a/src/os/windows/vm/perfMemory_windows.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os/windows/vm/perfMemory_windows.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -1581,7 +1581,7 @@ ResourceMark rm; void *mapAddress = 0; - size_t size; + size_t size = 0; HANDLE fmh; DWORD ofm_access; DWORD mv_access; @@ -1652,9 +1652,12 @@ if (*sizep == 0) { size = sharedmem_filesize(rfilename, CHECK); - assert(size != 0, "unexpected size"); + } else { + size = *sizep; } + assert(size > 0, "unexpected size <= 0"); + // Open the file mapping object with the given name fmh = open_sharedmem_object(robjectname, ofm_access, CHECK); diff -r 3d641132f83b -r 124ca22437b1 src/os_cpu/bsd_x86/vm/bsd_x86_64.ad --- a/src/os_cpu/bsd_x86/vm/bsd_x86_64.ad Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os_cpu/bsd_x86/vm/bsd_x86_64.ad Fri Apr 12 10:14:42 2013 +0100 @@ -55,20 +55,6 @@ // adding a syntax that specifies the sizes of fields in an order, // so that the adlc can build the emit functions automagically - enc_class Java_To_Runtime(method meth) %{ - // No relocation needed - - // movq r10, - emit_opcode(cbuf, Assembler::REX_WB); - emit_opcode(cbuf, 0xB8 | (R10_enc - 8)); - emit_d64(cbuf, (int64_t) $meth$$method); - - // call (r10) - emit_opcode(cbuf, Assembler::REX_B); - emit_opcode(cbuf, 0xFF); - emit_opcode(cbuf, 0xD0 | (R10_enc - 8)); - %} - %} @@ -76,8 +62,4 @@ source %{ -int MachCallRuntimeNode::ret_addr_offset() { - return 13; // movq r10,#addr; callq (r10) -} - %} diff -r 3d641132f83b -r 124ca22437b1 src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp --- a/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -46,7 +46,7 @@ define_pd_global(uintx, JVMInvokeMethodSlack, 8192); -// Used on 64 bit platforms for UseCompressedOops base address or CDS +// Used on 64 bit platforms for UseCompressedOops base address define_pd_global(uintx, HeapBaseMinAddress, 2*G); #endif // OS_CPU_BSD_X86_VM_GLOBALS_BSD_X86_HPP diff -r 3d641132f83b -r 124ca22437b1 src/os_cpu/bsd_zero/vm/globals_bsd_zero.hpp --- a/src/os_cpu/bsd_zero/vm/globals_bsd_zero.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os_cpu/bsd_zero/vm/globals_bsd_zero.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -41,7 +41,7 @@ define_pd_global(intx, CompilerThreadStackSize, 0); define_pd_global(uintx, JVMInvokeMethodSlack, 8192); -// Used on 64 bit platforms for UseCompressedOops base address or CDS +// Used on 64 bit platforms for UseCompressedOops base address define_pd_global(uintx, HeapBaseMinAddress, 2*G); #endif // OS_CPU_BSD_ZERO_VM_GLOBALS_BSD_ZERO_HPP diff -r 3d641132f83b -r 124ca22437b1 src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp --- a/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -33,7 +33,7 @@ define_pd_global(uintx, JVMInvokeMethodSlack, 12288); define_pd_global(intx, CompilerThreadStackSize, 0); -// Used on 64 bit platforms for UseCompressedOops base address or CDS +// Used on 64 bit platforms for UseCompressedOops base address define_pd_global(uintx, HeapBaseMinAddress, CONST64(4)*G); #endif // OS_CPU_LINUX_SPARC_VM_GLOBALS_LINUX_SPARC_HPP diff -r 3d641132f83b -r 124ca22437b1 src/os_cpu/linux_x86/vm/globals_linux_x86.hpp --- a/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -44,7 +44,7 @@ define_pd_global(uintx,JVMInvokeMethodSlack, 8192); -// Used on 64 bit platforms for UseCompressedOops base address or CDS +// Used on 64 bit platforms for UseCompressedOops base address define_pd_global(uintx,HeapBaseMinAddress, 2*G); #endif // OS_CPU_LINUX_X86_VM_GLOBALS_LINUX_X86_HPP diff -r 3d641132f83b -r 124ca22437b1 src/os_cpu/linux_x86/vm/linux_x86_64.ad --- a/src/os_cpu/linux_x86/vm/linux_x86_64.ad Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os_cpu/linux_x86/vm/linux_x86_64.ad Fri Apr 12 10:14:42 2013 +0100 @@ -55,20 +55,6 @@ // adding a syntax that specifies the sizes of fields in an order, // so that the adlc can build the emit functions automagically - enc_class Java_To_Runtime(method meth) %{ - // No relocation needed - - // movq r10, - emit_opcode(cbuf, Assembler::REX_WB); - emit_opcode(cbuf, 0xB8 | (R10_enc - 8)); - emit_d64(cbuf, (int64_t) $meth$$method); - - // call (r10) - emit_opcode(cbuf, Assembler::REX_B); - emit_opcode(cbuf, 0xFF); - emit_opcode(cbuf, 0xD0 | (R10_enc - 8)); - %} - %} @@ -76,8 +62,4 @@ source %{ -int MachCallRuntimeNode::ret_addr_offset() { - return 13; // movq r10,#addr; callq (r10) -} - %} diff -r 3d641132f83b -r 124ca22437b1 src/os_cpu/linux_x86/vm/os_linux_x86.cpp --- a/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -340,7 +340,7 @@ // here if the underlying file has been truncated. // Do not crash the VM in such a case. CodeBlob* cb = CodeCache::find_blob_unsafe(pc); - nmethod* nm = cb->is_nmethod() ? (nmethod*)cb : NULL; + nmethod* nm = (cb != NULL && cb->is_nmethod()) ? (nmethod*)cb : NULL; if (nm != NULL && nm->has_unsafe_access()) { stub = StubRoutines::handler_for_unsafe_access(); } diff -r 3d641132f83b -r 124ca22437b1 src/os_cpu/linux_zero/vm/globals_linux_zero.hpp --- a/src/os_cpu/linux_zero/vm/globals_linux_zero.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os_cpu/linux_zero/vm/globals_linux_zero.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -41,7 +41,7 @@ define_pd_global(intx, CompilerThreadStackSize, 0); define_pd_global(uintx, JVMInvokeMethodSlack, 8192); -// Used on 64 bit platforms for UseCompressedOops base address or CDS +// Used on 64 bit platforms for UseCompressedOops base address define_pd_global(uintx, HeapBaseMinAddress, 2*G); #endif // OS_CPU_LINUX_ZERO_VM_GLOBALS_LINUX_ZERO_HPP diff -r 3d641132f83b -r 124ca22437b1 src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp --- a/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -33,7 +33,7 @@ define_pd_global(uintx, JVMInvokeMethodSlack, 12288); define_pd_global(intx, CompilerThreadStackSize, 0); -// Used on 64 bit platforms for UseCompressedOops base address or CDS +// Used on 64 bit platforms for UseCompressedOops base address #ifdef _LP64 define_pd_global(uintx, HeapBaseMinAddress, CONST64(4)*G); #else diff -r 3d641132f83b -r 124ca22437b1 src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp --- a/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -43,7 +43,7 @@ define_pd_global(intx, CompilerThreadStackSize, 0); -// Used on 64 bit platforms for UseCompressedOops base address or CDS +// Used on 64 bit platforms for UseCompressedOops base address define_pd_global(uintx,HeapBaseMinAddress, 256*M); #endif // OS_CPU_SOLARIS_X86_VM_GLOBALS_SOLARIS_X86_HPP diff -r 3d641132f83b -r 124ca22437b1 src/os_cpu/solaris_x86/vm/solaris_x86_64.ad --- a/src/os_cpu/solaris_x86/vm/solaris_x86_64.ad Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os_cpu/solaris_x86/vm/solaris_x86_64.ad Fri Apr 12 10:14:42 2013 +0100 @@ -54,39 +54,10 @@ // main source block for now. In future, we can generalize this by // adding a syntax that specifies the sizes of fields in an order, // so that the adlc can build the emit functions automagically - - enc_class Java_To_Runtime(method meth) %{ - // No relocation needed - - // movq r10, - emit_opcode(cbuf, Assembler::REX_WB); - emit_opcode(cbuf, 0xB8 | (R10_enc - 8)); - emit_d64(cbuf, (int64_t) $meth$$method); - - // call (r10) - emit_opcode(cbuf, Assembler::REX_B); - emit_opcode(cbuf, 0xFF); - emit_opcode(cbuf, 0xD0 | (R10_enc - 8)); - %} - - enc_class post_call_verify_mxcsr %{ - MacroAssembler _masm(&cbuf); - if (RestoreMXCSROnJNICalls) { - __ ldmxcsr(ExternalAddress(StubRoutines::amd64::mxcsr_std())); - } - else if (CheckJNICalls) { - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::amd64::verify_mxcsr_entry()))); - } - %} %} // Platform dependent source source %{ - -int MachCallRuntimeNode::ret_addr_offset() { - return 13; // movq r10,#addr; callq (r10) -} - %} diff -r 3d641132f83b -r 124ca22437b1 src/os_cpu/windows_x86/vm/globals_windows_x86.hpp --- a/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -45,7 +45,7 @@ define_pd_global(uintx, JVMInvokeMethodSlack, 8192); -// Used on 64 bit platforms for UseCompressedOops base address or CDS +// Used on 64 bit platforms for UseCompressedOops base address define_pd_global(uintx, HeapBaseMinAddress, 2*G); #endif // OS_CPU_WINDOWS_X86_VM_GLOBALS_WINDOWS_X86_HPP diff -r 3d641132f83b -r 124ca22437b1 src/os_cpu/windows_x86/vm/windows_x86_64.ad --- a/src/os_cpu/windows_x86/vm/windows_x86_64.ad Tue Feb 26 16:16:54 2013 -0800 +++ b/src/os_cpu/windows_x86/vm/windows_x86_64.ad Fri Apr 12 10:14:42 2013 +0100 @@ -53,30 +53,11 @@ // adding a syntax that specifies the sizes of fields in an order, // so that the adlc can build the emit functions automagically - enc_class Java_To_Runtime (method meth) %{ // CALL Java_To_Runtime - // No relocation needed +%} + - // movq r10, - emit_opcode(cbuf, Assembler::REX_WB); - emit_opcode(cbuf, 0xB8 | (R10_enc - 8)); - emit_d64(cbuf, (int64_t) $meth$$method); +// Platform dependent source - // call (r10) - emit_opcode(cbuf, Assembler::REX_B); - emit_opcode(cbuf, 0xFF); - emit_opcode(cbuf, 0xD0 | (R10_enc - 8)); - %} +source %{ %} - -// -// Platform dependent source -// -source %{ - -int MachCallRuntimeNode::ret_addr_offset() -{ - return 13; // movq r10,#addr; callq (r10) -} - -%} diff -r 3d641132f83b -r 124ca22437b1 src/share/tools/ProjectCreator/BuildConfig.java --- a/src/share/tools/ProjectCreator/BuildConfig.java Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/tools/ProjectCreator/BuildConfig.java Fri Apr 12 10:14:42 2013 +0100 @@ -568,36 +568,6 @@ } } -class KernelDebugConfig extends GenericDebugConfig { - String getOptFlag() { - return getCI().getNoOptFlag(); - } - - KernelDebugConfig() { - initNames("kernel", "debug", "jvm.dll"); - init(getIncludes(), getDefines()); - } -} - - -class KernelFastDebugConfig extends GenericDebugConfig { - String getOptFlag() { - return getCI().getOptFlag(); - } - - KernelFastDebugConfig() { - initNames("kernel", "fastdebug", "jvm.dll"); - init(getIncludes(), getDefines()); - } -} - - -class KernelProductConfig extends ProductConfig { - KernelProductConfig() { - initNames("kernel", "product", "jvm.dll"); - init(getIncludes(), getDefines()); - } -} abstract class CompilerInterface { abstract Vector getBaseCompilerFlags(Vector defines, Vector includes, String outDir); diff -r 3d641132f83b -r 124ca22437b1 src/share/tools/ProjectCreator/WinGammaPlatform.java --- a/src/share/tools/ProjectCreator/WinGammaPlatform.java Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/tools/ProjectCreator/WinGammaPlatform.java Fri Apr 12 10:14:42 2013 +0100 @@ -564,12 +564,6 @@ allConfigs.add(new CoreFastDebugConfig()); allConfigs.add(new CoreProductConfig()); - if (platform.equals("Win32")) { - allConfigs.add(new KernelDebugConfig()); - allConfigs.add(new KernelFastDebugConfig()); - allConfigs.add(new KernelProductConfig()); - } - return allConfigs; } diff -r 3d641132f83b -r 124ca22437b1 src/share/tools/launcher/wildcard.c --- a/src/share/tools/launcher/wildcard.c Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/tools/launcher/wildcard.c Fri Apr 12 10:14:42 2013 +0100 @@ -368,8 +368,10 @@ const char *basename; FileList fl = FileList_new(16); WildcardIterator it = WildcardIterator_for(wildcard); - if (it == NULL) + if (it == NULL) { + FileList_free(fl); return NULL; + } while ((basename = WildcardIterator_next(it)) != NULL) if (isJarFileName(basename)) FileList_add(fl, wildcardConcat(wildcard, basename)); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/adlc/archDesc.cpp --- a/src/share/vm/adlc/archDesc.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/adlc/archDesc.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -832,6 +832,7 @@ int length = (int)strlen(rc_name) + (int)strlen(mask) + 5; char *regMask = new char[length]; sprintf(regMask,"%s%s()", rc_name, mask); + delete[] rc_name; return regMask; } } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/adlc/dfa.cpp --- a/src/share/vm/adlc/dfa.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/adlc/dfa.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -191,12 +191,19 @@ // Macro equivalent to: _kids[0]->valid(FOO) && _kids[1]->valid(BAR) // static void child_test(FILE *fp, MatchList &mList) { - if( mList._lchild ) // If left child, check it - fprintf(fp, "STATE__VALID_CHILD(_kids[0], %s)", ArchDesc::getMachOperEnum(mList._lchild)); - if( mList._lchild && mList._rchild ) // If both, add the "&&" - fprintf(fp, " && " ); - if( mList._rchild ) // If right child, check it - fprintf(fp, "STATE__VALID_CHILD(_kids[1], %s)", ArchDesc::getMachOperEnum(mList._rchild)); + if (mList._lchild) { // If left child, check it + const char* lchild_to_upper = ArchDesc::getMachOperEnum(mList._lchild); + fprintf(fp, "STATE__VALID_CHILD(_kids[0], %s)", lchild_to_upper); + delete[] lchild_to_upper; + } + if (mList._lchild && mList._rchild) { // If both, add the "&&" + fprintf(fp, " && "); + } + if (mList._rchild) { // If right child, check it + const char* rchild_to_upper = ArchDesc::getMachOperEnum(mList._rchild); + fprintf(fp, "STATE__VALID_CHILD(_kids[1], %s)", rchild_to_upper); + delete[] rchild_to_upper; + } } //---------------------------calc_cost----------------------------------------- @@ -206,13 +213,17 @@ Expr *ArchDesc::calc_cost(FILE *fp, const char *spaces, MatchList &mList, ProductionState &status) { fprintf(fp, "%sunsigned int c = ", spaces); Expr *c = new Expr("0"); - if (mList._lchild ) { // If left child, add it in - sprintf(Expr::buffer(), "_kids[0]->_cost[%s]", ArchDesc::getMachOperEnum(mList._lchild)); + if (mList._lchild) { // If left child, add it in + const char* lchild_to_upper = ArchDesc::getMachOperEnum(mList._lchild); + sprintf(Expr::buffer(), "_kids[0]->_cost[%s]", lchild_to_upper); c->add(Expr::buffer()); + delete[] lchild_to_upper; } - if (mList._rchild) { // If right child, add it in - sprintf(Expr::buffer(), "_kids[1]->_cost[%s]", ArchDesc::getMachOperEnum(mList._rchild)); + if (mList._rchild) { // If right child, add it in + const char* rchild_to_upper = ArchDesc::getMachOperEnum(mList._rchild); + sprintf(Expr::buffer(), "_kids[1]->_cost[%s]", rchild_to_upper); c->add(Expr::buffer()); + delete[] rchild_to_upper; } // Add in cost of this rule const char *mList_cost = mList.get_cost(); @@ -232,15 +243,17 @@ fprintf(fp, "%s", spaces4); // Only generate child tests if this is not a leaf node bool has_child_constraints = mList._lchild || mList._rchild; - const char *predicate_test = mList.get_pred(); - if( has_child_constraints || predicate_test ) { + const char *predicate_test = mList.get_pred(); + if (has_child_constraints || predicate_test) { // Open the child-and-predicate-test braces fprintf(fp, "if( "); status.set_constraint(hasConstraint); child_test(fp, mList); // Only generate predicate test if one exists for this match - if( predicate_test ) { - if( has_child_constraints ) { fprintf(fp," &&\n"); } + if (predicate_test) { + if (has_child_constraints) { + fprintf(fp," &&\n"); + } fprintf(fp, "%s %s", spaces6, predicate_test); } // End of outer tests diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/asm/assembler.cpp --- a/src/share/vm/asm/assembler.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/asm/assembler.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -284,15 +284,19 @@ DelayedConstant::update_all(); } - - - void AbstractAssembler::block_comment(const char* comment) { if (sect() == CodeBuffer::SECT_INSTS) { code_section()->outer()->block_comment(offset(), comment); } } +const char* AbstractAssembler::code_string(const char* str) { + if (sect() == CodeBuffer::SECT_INSTS || sect() == CodeBuffer::SECT_STUBS) { + return code_section()->outer()->code_string(str); + } + return NULL; +} + bool MacroAssembler::needs_explicit_null_check(intptr_t offset) { // Exception handler checks the nmethod's implicit null checks table // only when this method returns false. diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/asm/assembler.hpp --- a/src/share/vm/asm/assembler.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/asm/assembler.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -336,6 +336,8 @@ // along with the disassembly when printing nmethods. Currently // only supported in the instruction section of the code buffer. void block_comment(const char* comment); + // Copy str to a buffer that has the same lifetime as the CodeBuffer + const char* code_string(const char* str); // Label functions void bind(Label& L); // binds an unbound label L to the current code position diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/asm/codeBuffer.cpp --- a/src/share/vm/asm/codeBuffer.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/asm/codeBuffer.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -703,8 +703,8 @@ 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 CodeBuffer::block_comment(intptr_t offset, const char * comment) { - _comments.add_comment(offset, comment); + _strings.add_comment(offset, comment); +} + +const char* CodeBuffer::code_string(const char* str) { + return _strings.add_string(str); } -class CodeComment: public CHeapObj { +class CodeString: public CHeapObj { private: - friend class CodeComments; + friend class CodeStrings; + const char * _string; + CodeString* _next; intptr_t _offset; - const char * _comment; - CodeComment* _next; - ~CodeComment() { + ~CodeString() { assert(_next == NULL, "wrong interface for freeing list"); - os::free((void*)_comment, mtCode); - } - - public: - CodeComment(intptr_t offset, const char * comment) { - _offset = offset; - _comment = os::strdup(comment, mtCode); - _next = NULL; + os::free((void*)_string, mtCode); } - intptr_t offset() const { return _offset; } - const char * comment() const { return _comment; } - CodeComment* next() { return _next; } - - void set_next(CodeComment* next) { _next = next; } + bool is_comment() const { return _offset >= 0; } - CodeComment* find(intptr_t offset) { - CodeComment* a = this; - while (a != NULL && a->_offset != offset) { - a = a->_next; - } - return a; + public: + CodeString(const char * string, intptr_t offset = -1) + : _next(NULL), _offset(offset) { + _string = os::strdup(string, mtCode); } - // 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; - } + 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(CodeString* next) { _next = next; } + + CodeString* first_comment() { + if (is_comment()) { + return this; + } else { + return next_comment(); } - return a; + } + CodeString* next_comment() const { + CodeString* s = _next; + while (s != NULL && !s->is_comment()) { + s = s->_next; + } + 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 @@ inspos->set_next(c); } else { // no comments with such offset, yet. Insert before anything else. - c->set_next(_comments); - _comments = c; + c->set_next(_strings); + _strings = c; } } - -void CodeComments::assign(CodeComments& other) { - _comments = other._comments; +void CodeStrings::assign(CodeStrings& other) { + _strings = other._strings; } - -void CodeComments::print_block_comment(outputStream* stream, intptr_t offset) const { - if (_comments != NULL) { - CodeComment* c = _comments->find(offset); +void CodeStrings::print_block_comment(outputStream* stream, intptr_t offset) const { + if (_strings != NULL) { + CodeString* c = find(offset); while (c && c->offset() == offset) { stream->bol(); stream->print(" ;; "); - stream->print_cr(c->comment()); - c = c->next(); + stream->print_cr(c->string()); + c = c->next_comment(); } } } -void CodeComments::free() { - CodeComment* n = _comments; +void CodeStrings::free() { + CodeString* n = _strings; while (n) { // unlink the node from the list saving a pointer to the next - CodeComment* p = n->_next; - n->_next = NULL; + CodeString* p = n->next(); + n->set_next(NULL); delete n; n = p; } - _comments = NULL; + _strings = NULL; } - +const char* CodeStrings::add_string(const char * string) { + CodeString* s = new CodeString(string); + s->set_next(_strings); + _strings = s; + assert(s->string() != NULL, "should have a string"); + return s->string(); +} void CodeBuffer::decode() { ttyLocker ttyl; diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/asm/codeBuffer.hpp --- a/src/share/vm/asm/codeBuffer.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/asm/codeBuffer.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -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 @@ #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 @@ 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 @@ 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 @@ address transform_address(const CodeBuffer &cb, address addr) const; void block_comment(intptr_t offset, const char * comment) PRODUCT_RETURN; + const char* code_string(const char* str) PRODUCT_RETURN_(return NULL;); // Log a little info about section usage in the CodeBuffer void log_section_sizes(const char* name); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_Canonicalizer.cpp --- a/src/share/vm/c1/c1_Canonicalizer.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_Canonicalizer.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -937,4 +937,6 @@ void Canonicalizer::do_ProfileCall(ProfileCall* x) {} void Canonicalizer::do_ProfileInvoke(ProfileInvoke* x) {} void Canonicalizer::do_RuntimeCall(RuntimeCall* x) {} +void Canonicalizer::do_RangeCheckPredicate(RangeCheckPredicate* x) {} +void Canonicalizer::do_Assert(Assert* x) {} void Canonicalizer::do_MemBar(MemBar* x) {} diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_Canonicalizer.hpp --- a/src/share/vm/c1/c1_Canonicalizer.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_Canonicalizer.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -107,6 +107,8 @@ virtual void do_ProfileInvoke (ProfileInvoke* x); virtual void do_RuntimeCall (RuntimeCall* x); virtual void do_MemBar (MemBar* x); + virtual void do_RangeCheckPredicate(RangeCheckPredicate* x); + virtual void do_Assert (Assert* x); }; #endif // SHARE_VM_C1_C1_CANONICALIZER_HPP diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_CodeStubs.hpp --- a/src/share/vm/c1/c1_CodeStubs.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_CodeStubs.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -166,6 +166,22 @@ #endif // PRODUCT }; +// stub used when predicate fails and deoptimization is needed +class PredicateFailedStub: public CodeStub { + private: + CodeEmitInfo* _info; + + public: + PredicateFailedStub(CodeEmitInfo* info); + virtual void emit_code(LIR_Assembler* e); + virtual CodeEmitInfo* info() const { return _info; } + virtual void visit(LIR_OpVisitState* visitor) { + visitor->do_slow_case(_info); + } +#ifndef PRODUCT + virtual void print_name(outputStream* out) const { out->print("PredicateFailedStub"); } +#endif // PRODUCT +}; class DivByZeroStub: public CodeStub { private: diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_Compilation.cpp --- a/src/share/vm/c1/c1_Compilation.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_Compilation.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -33,13 +33,16 @@ #include "c1/c1_ValueStack.hpp" #include "code/debugInfoRec.hpp" #include "compiler/compileLog.hpp" +#include "c1/c1_RangeCheckElimination.hpp" typedef enum { _t_compile, _t_setup, - _t_optimizeIR, _t_buildIR, + _t_optimize_blocks, + _t_optimize_null_checks, + _t_rangeCheckElimination, _t_emit_lir, _t_linearScan, _t_lirGeneration, @@ -52,8 +55,10 @@ static const char * timer_name[] = { "compile", "setup", - "optimizeIR", "buildIR", + "optimize_blocks", + "optimize_null_checks", + "rangeCheckElimination", "emit_lir", "linearScan", "lirGeneration", @@ -159,9 +164,9 @@ if (UseC1Optimizations) { NEEDS_CLEANUP // optimization - PhaseTraceTime timeit(_t_optimizeIR); + PhaseTraceTime timeit(_t_optimize_blocks); - _hir->optimize(); + _hir->optimize_blocks(); } _hir->verify(); @@ -180,13 +185,47 @@ _hir->compute_code(); if (UseGlobalValueNumbering) { - ResourceMark rm; + // No resource mark here! LoopInvariantCodeMotion can allocate ValueStack objects. int instructions = Instruction::number_of_instructions(); GlobalValueNumbering gvn(_hir); assert(instructions == Instruction::number_of_instructions(), "shouldn't have created an instructions"); } + _hir->verify(); + +#ifndef PRODUCT + if (PrintCFGToFile) { + CFGPrinter::print_cfg(_hir, "Before RangeCheckElimination", true, false); + } +#endif + + if (RangeCheckElimination) { + if (_hir->osr_entry() == NULL) { + PhaseTraceTime timeit(_t_rangeCheckElimination); + RangeCheckElimination::eliminate(_hir); + } + } + +#ifndef PRODUCT + if (PrintCFGToFile) { + CFGPrinter::print_cfg(_hir, "After RangeCheckElimination", true, false); + } +#endif + + if (UseC1Optimizations) { + // loop invariant code motion reorders instructions and range + // check elimination adds new instructions so do null check + // elimination after. + NEEDS_CLEANUP + // optimization + PhaseTraceTime timeit(_t_optimize_null_checks); + + _hir->eliminate_null_checks(); + } + + _hir->verify(); + // compute use counts after global value numbering _hir->compute_use_counts(); @@ -502,6 +541,7 @@ , _next_id(0) , _next_block_id(0) , _code(buffer_blob) +, _has_access_indexed(false) , _current_instruction(NULL) #ifndef PRODUCT , _last_instruction_printed(NULL) @@ -567,7 +607,9 @@ tty->print_cr(" Detailed C1 Timings"); tty->print_cr(" Setup time: %6.3f s (%4.1f%%)", timers[_t_setup].seconds(), (timers[_t_setup].seconds() / total) * 100.0); tty->print_cr(" Build IR: %6.3f s (%4.1f%%)", timers[_t_buildIR].seconds(), (timers[_t_buildIR].seconds() / total) * 100.0); - tty->print_cr(" Optimize: %6.3f s (%4.1f%%)", timers[_t_optimizeIR].seconds(), (timers[_t_optimizeIR].seconds() / total) * 100.0); + float t_optimizeIR = timers[_t_optimize_blocks].seconds() + timers[_t_optimize_null_checks].seconds(); + tty->print_cr(" Optimize: %6.3f s (%4.1f%%)", t_optimizeIR, (t_optimizeIR / total) * 100.0); + tty->print_cr(" RCE: %6.3f s (%4.1f%%)", timers[_t_rangeCheckElimination].seconds(), (timers[_t_rangeCheckElimination].seconds() / total) * 100.0); tty->print_cr(" Emit LIR: %6.3f s (%4.1f%%)", timers[_t_emit_lir].seconds(), (timers[_t_emit_lir].seconds() / total) * 100.0); tty->print_cr(" LIR Gen: %6.3f s (%4.1f%%)", timers[_t_lirGeneration].seconds(), (timers[_t_lirGeneration].seconds() / total) * 100.0); tty->print_cr(" Linear Scan: %6.3f s (%4.1f%%)", timers[_t_linearScan].seconds(), (timers[_t_linearScan].seconds() / total) * 100.0); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_Compilation.hpp --- a/src/share/vm/c1/c1_Compilation.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_Compilation.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -26,8 +26,10 @@ #define SHARE_VM_C1_C1_COMPILATION_HPP #include "ci/ciEnv.hpp" +#include "ci/ciMethodData.hpp" #include "code/exceptionHandlerTable.hpp" #include "memory/resourceArea.hpp" +#include "runtime/deoptimization.hpp" class CompilationResourceObj; class XHandlers; @@ -85,6 +87,7 @@ LinearScan* _allocator; CodeOffsets _offsets; CodeBuffer _code; + bool _has_access_indexed; // compilation helpers void initialize(); @@ -140,6 +143,7 @@ C1_MacroAssembler* masm() const { return _masm; } CodeOffsets* offsets() { return &_offsets; } Arena* arena() { return _arena; } + bool has_access_indexed() { return _has_access_indexed; } // Instruction ids int get_next_id() { return _next_id++; } @@ -154,6 +158,7 @@ void set_has_fpu_code(bool f) { _has_fpu_code = f; } void set_has_unsafe_access(bool f) { _has_unsafe_access = f; } void set_would_profile(bool f) { _would_profile = f; } + void set_has_access_indexed(bool f) { _has_access_indexed = f; } // Add a set of exception handlers covering the given PC offset void add_exception_handlers_for_pco(int pco, XHandlers* exception_handlers); // Statistics gathering @@ -233,6 +238,14 @@ return env()->comp_level() == CompLevel_full_profile && C1UpdateMethodData && C1ProfileCheckcasts; } + + // will compilation make optimistic assumptions that might lead to + // deoptimization and that the runtime will account for? + bool is_optimistic() const { + return !TieredCompilation && + (RangeCheckElimination || UseLoopInvariantCodeMotion) && + method()->method_data()->trap_count(Deoptimization::Reason_none) == 0; + } }; diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -947,7 +947,9 @@ void GraphBuilder::load_indexed(BasicType type) { - ValueStack* state_before = copy_state_for_exception(); + // In case of in block code motion in range check elimination + ValueStack* state_before = copy_state_indexed_access(); + compilation()->set_has_access_indexed(true); Value index = ipop(); Value array = apop(); Value length = NULL; @@ -961,7 +963,9 @@ void GraphBuilder::store_indexed(BasicType type) { - ValueStack* state_before = copy_state_for_exception(); + // In case of in block code motion in range check elimination + ValueStack* state_before = copy_state_indexed_access(); + compilation()->set_has_access_indexed(true); Value value = pop(as_ValueType(type)); Value index = ipop(); Value array = apop(); @@ -1179,7 +1183,9 @@ BlockBegin* tsux = block_at(stream()->get_dest()); BlockBegin* fsux = block_at(stream()->next_bci()); bool is_bb = tsux->bci() < stream()->cur_bci() || fsux->bci() < stream()->cur_bci(); - Instruction *i = append(new If(x, cond, false, y, tsux, fsux, is_bb ? state_before : NULL, is_bb)); + // In case of loop invariant code motion or predicate insertion + // before the body of a loop the state is needed + Instruction *i = append(new If(x, cond, false, y, tsux, fsux, (is_bb || compilation()->is_optimistic()) ? state_before : NULL, is_bb)); assert(i->as_Goto() == NULL || (i->as_Goto()->sux_at(0) == tsux && i->as_Goto()->is_safepoint() == tsux->bci() < stream()->cur_bci()) || @@ -1294,7 +1300,9 @@ BlockBegin* tsux = block_at(bci() + sw.dest_offset_at(0)); BlockBegin* fsux = block_at(bci() + sw.default_offset()); bool is_bb = tsux->bci() < bci() || fsux->bci() < bci(); - ValueStack* state_before = is_bb ? copy_state_before() : NULL; + // In case of loop invariant code motion or predicate insertion + // before the body of a loop the state is needed + ValueStack* state_before = copy_state_if_bb(is_bb); append(new If(ipop(), If::eql, true, key, tsux, fsux, state_before, is_bb)); } else { // collect successors @@ -1308,7 +1316,9 @@ // add default successor if (sw.default_offset() < 0) has_bb = true; sux->at_put(i, block_at(bci() + sw.default_offset())); - ValueStack* state_before = has_bb ? copy_state_before() : NULL; + // In case of loop invariant code motion or predicate insertion + // before the body of a loop the state is needed + ValueStack* state_before = copy_state_if_bb(has_bb); Instruction* res = append(new TableSwitch(ipop(), sux, sw.low_key(), state_before, has_bb)); #ifdef ASSERT if (res->as_Goto()) { @@ -1336,7 +1346,9 @@ BlockBegin* tsux = block_at(bci() + pair.offset()); BlockBegin* fsux = block_at(bci() + sw.default_offset()); bool is_bb = tsux->bci() < bci() || fsux->bci() < bci(); - ValueStack* state_before = is_bb ? copy_state_before() : NULL; + // In case of loop invariant code motion or predicate insertion + // before the body of a loop the state is needed + ValueStack* state_before = copy_state_if_bb(is_bb);; append(new If(ipop(), If::eql, true, key, tsux, fsux, state_before, is_bb)); } else { // collect successors & keys @@ -1353,7 +1365,9 @@ // add default successor if (sw.default_offset() < 0) has_bb = true; sux->at_put(i, block_at(bci() + sw.default_offset())); - ValueStack* state_before = has_bb ? copy_state_before() : NULL; + // In case of loop invariant code motion or predicate insertion + // before the body of a loop the state is needed + ValueStack* state_before = copy_state_if_bb(has_bb); Instruction* res = append(new LookupSwitch(ipop(), sux, keys, state_before, has_bb)); #ifdef ASSERT if (res->as_Goto()) { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_GraphBuilder.hpp --- a/src/share/vm/c1/c1_GraphBuilder.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_GraphBuilder.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -301,6 +301,8 @@ ValueStack* copy_state_exhandling(); ValueStack* copy_state_for_exception_with_bci(int bci); ValueStack* copy_state_for_exception(); + ValueStack* copy_state_if_bb(bool is_bb) { return (is_bb || compilation()->is_optimistic()) ? copy_state_before() : NULL; } + ValueStack* copy_state_indexed_access() { return compilation()->is_optimistic() ? copy_state_before() : copy_state_for_exception(); } // // Inlining support diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_IR.cpp --- a/src/share/vm/c1/c1_IR.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_IR.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -182,13 +182,14 @@ // Implementation of CodeEmitInfo // Stack must be NON-null -CodeEmitInfo::CodeEmitInfo(ValueStack* stack, XHandlers* exception_handlers) +CodeEmitInfo::CodeEmitInfo(ValueStack* stack, XHandlers* exception_handlers, bool deoptimize_on_exception) : _scope(stack->scope()) , _scope_debug_info(NULL) , _oop_map(NULL) , _stack(stack) , _exception_handlers(exception_handlers) - , _is_method_handle_invoke(false) { + , _is_method_handle_invoke(false) + , _deoptimize_on_exception(deoptimize_on_exception) { assert(_stack != NULL, "must be non null"); } @@ -199,7 +200,8 @@ , _scope_debug_info(NULL) , _oop_map(NULL) , _stack(stack == NULL ? info->_stack : stack) - , _is_method_handle_invoke(info->_is_method_handle_invoke) { + , _is_method_handle_invoke(info->_is_method_handle_invoke) + , _deoptimize_on_exception(info->_deoptimize_on_exception) { // deep copy of exception handlers if (info->_exception_handlers != NULL) { @@ -239,7 +241,7 @@ } -void IR::optimize() { +void IR::optimize_blocks() { Optimizer opt(this); if (!compilation()->profile_branches()) { if (DoCEE) { @@ -257,6 +259,10 @@ #endif } } +} + +void IR::eliminate_null_checks() { + Optimizer opt(this); if (EliminateNullChecks) { opt.eliminate_null_checks(); #ifndef PRODUCT @@ -429,6 +435,7 @@ BlockList _loop_end_blocks; // list of all loop end blocks collected during count_edges BitMap2D _loop_map; // two-dimensional bit set: a bit is set if a block is contained in a loop BlockList _work_list; // temporary list (used in mark_loops and compute_order) + BlockList _loop_headers; Compilation* _compilation; @@ -594,6 +601,7 @@ TRACE_LINEAR_SCAN(3, tty->print_cr("Block B%d is loop header of loop %d", cur->block_id(), _num_loops)); cur->set_loop_index(_num_loops); + _loop_headers.append(cur); _num_loops++; } @@ -656,6 +664,16 @@ // -> this is not a natural loop, so ignore it TRACE_LINEAR_SCAN(2, tty->print_cr("Loop %d is non-natural, so it is ignored", i)); + BlockBegin *loop_header = _loop_headers.at(i); + assert(loop_header->is_set(BlockBegin::linear_scan_loop_header_flag), "Must be loop header"); + + for (int j = 0; j < loop_header->number_of_preds(); j++) { + BlockBegin *pred = loop_header->pred_at(j); + pred->clear(BlockBegin::linear_scan_loop_end_flag); + } + + loop_header->clear(BlockBegin::linear_scan_loop_header_flag); + for (int block_id = _max_block_id - 1; block_id >= 0; block_id--) { clear_block_in_loop(i, block_id); } @@ -729,9 +747,20 @@ } else if (!(cur->is_set(BlockBegin::linear_scan_loop_header_flag) && parent->is_set(BlockBegin::linear_scan_loop_end_flag))) { TRACE_LINEAR_SCAN(4, tty->print_cr("DOM: computing dominator of B%d: common dominator of B%d and B%d is B%d", cur->block_id(), parent->block_id(), cur->dominator()->block_id(), common_dominator(cur->dominator(), parent)->block_id())); - assert(cur->number_of_preds() > 1, ""); + // Does not hold for exception blocks + assert(cur->number_of_preds() > 1 || cur->is_set(BlockBegin::exception_entry_flag), ""); cur->set_dominator(common_dominator(cur->dominator(), parent)); } + + // Additional edge to xhandler of all our successors + // range check elimination needs that the state at the end of a + // block be valid in every block it dominates so cur must dominate + // the exception handlers of its successors. + int num_cur_xhandler = cur->number_of_exception_handlers(); + for (int j = 0; j < num_cur_xhandler; j++) { + BlockBegin* xhandler = cur->exception_handler_at(j); + compute_dominator(xhandler, parent); + } } @@ -898,7 +927,6 @@ num_sux = cur->number_of_exception_handlers(); for (i = 0; i < num_sux; i++) { BlockBegin* sux = cur->exception_handler_at(i); - compute_dominator(sux, cur); if (ready_for_processing(sux)) { sort_into_work_list(sux); } @@ -918,8 +946,23 @@ BlockBegin* dominator = block->pred_at(0); int num_preds = block->number_of_preds(); - for (int i = 1; i < num_preds; i++) { - dominator = common_dominator(dominator, block->pred_at(i)); + + TRACE_LINEAR_SCAN(4, tty->print_cr("DOM: Processing B%d", block->block_id())); + + for (int j = 0; j < num_preds; j++) { + + BlockBegin *pred = block->pred_at(j); + TRACE_LINEAR_SCAN(4, tty->print_cr(" DOM: Subrocessing B%d", pred->block_id())); + + if (block->is_set(BlockBegin::exception_entry_flag)) { + dominator = common_dominator(dominator, pred); + int num_pred_preds = pred->number_of_preds(); + for (int k = 0; k < num_pred_preds; k++) { + dominator = common_dominator(dominator, pred->pred_at(k)); + } + } else { + dominator = common_dominator(dominator, pred); + } } if (dominator != block->dominator()) { @@ -946,6 +989,21 @@ // check that dominators are correct assert(!compute_dominators_iter(), "fix point not reached"); + + // Add Blocks to dominates-Array + int num_blocks = _linear_scan_order->length(); + for (int i = 0; i < num_blocks; i++) { + BlockBegin* block = _linear_scan_order->at(i); + + BlockBegin *dom = block->dominator(); + if (dom) { + assert(dom->dominator_depth() != -1, "Dominator must have been visited before"); + dom->dominates()->append(block); + block->set_dominator_depth(dom->dominator_depth() + 1); + } else { + block->set_dominator_depth(0); + } + } } @@ -1032,7 +1090,7 @@ BlockBegin* sux = cur->sux_at(j); assert(sux->linear_scan_number() >= 0 && sux->linear_scan_number() == _linear_scan_order->index_of(sux), "incorrect linear_scan_number"); - if (!cur->is_set(BlockBegin::linear_scan_loop_end_flag)) { + if (!sux->is_set(BlockBegin::backward_branch_target_flag)) { assert(cur->linear_scan_number() < sux->linear_scan_number(), "invalid order"); } if (cur->loop_depth() == sux->loop_depth()) { @@ -1044,7 +1102,7 @@ BlockBegin* pred = cur->pred_at(j); assert(pred->linear_scan_number() >= 0 && pred->linear_scan_number() == _linear_scan_order->index_of(pred), "incorrect linear_scan_number"); - if (!cur->is_set(BlockBegin::linear_scan_loop_header_flag)) { + if (!cur->is_set(BlockBegin::backward_branch_target_flag)) { assert(cur->linear_scan_number() > pred->linear_scan_number(), "invalid order"); } if (cur->loop_depth() == pred->loop_depth()) { @@ -1060,7 +1118,8 @@ } else { assert(cur->dominator() != NULL, "all but first block must have dominator"); } - assert(cur->number_of_preds() != 1 || cur->dominator() == cur->pred_at(0), "Single predecessor must also be dominator"); + // Assertion does not hold for exception handlers + assert(cur->number_of_preds() != 1 || cur->dominator() == cur->pred_at(0) || cur->is_set(BlockBegin::exception_entry_flag), "Single predecessor must also be dominator"); } // check that all loops are continuous @@ -1249,9 +1308,22 @@ } }; +class VerifyBlockBeginField : public BlockClosure { + +public: + + virtual void block_do(BlockBegin *block) { + for ( Instruction *cur = block; cur != NULL; cur = cur->next()) { + assert(cur->block() == block, "Block begin is not correct"); + } + } +}; + void IR::verify() { #ifdef ASSERT PredecessorValidator pv(this); + VerifyBlockBeginField verifier; + this->iterate_postorder(&verifier); #endif } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_IR.hpp --- a/src/share/vm/c1/c1_IR.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_IR.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -254,6 +254,7 @@ OopMap* _oop_map; ValueStack* _stack; // used by deoptimization (contains also monitors bool _is_method_handle_invoke; // true if the associated call site is a MethodHandle call site. + bool _deoptimize_on_exception; FrameMap* frame_map() const { return scope()->compilation()->frame_map(); } Compilation* compilation() const { return scope()->compilation(); } @@ -261,7 +262,7 @@ public: // use scope from ValueStack - CodeEmitInfo(ValueStack* stack, XHandlers* exception_handlers); + CodeEmitInfo(ValueStack* stack, XHandlers* exception_handlers, bool deoptimize_on_exception = false); // make a copy CodeEmitInfo(CodeEmitInfo* info, ValueStack* stack = NULL); @@ -272,6 +273,7 @@ IRScope* scope() const { return _scope; } XHandlers* exception_handlers() const { return _exception_handlers; } ValueStack* stack() const { return _stack; } + bool deoptimize_on_exception() const { return _deoptimize_on_exception; } void add_register_oop(LIR_Opr opr); void record_debug_info(DebugInformationRecorder* recorder, int pc_offset); @@ -309,7 +311,8 @@ int max_stack() const { return top_scope()->max_stack(); } // expensive // ir manipulation - void optimize(); + void optimize_blocks(); + void eliminate_null_checks(); void compute_predecessors(); void split_critical_edges(); void compute_code(); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_Instruction.cpp --- a/src/share/vm/c1/c1_Instruction.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_Instruction.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -34,6 +34,15 @@ // Implementation of Instruction +int Instruction::dominator_depth() { + int result = -1; + if (block()) { + result = block()->dominator_depth(); + } + assert(result != -1 || this->as_Local(), "Only locals have dominator depth -1"); + return result; +} + Instruction::Condition Instruction::mirror(Condition cond) { switch (cond) { case eql: return eql; @@ -42,6 +51,8 @@ case leq: return geq; case gtr: return lss; case geq: return leq; + case aeq: return beq; + case beq: return aeq; } ShouldNotReachHere(); return eql; @@ -56,6 +67,8 @@ case leq: return gtr; case gtr: return leq; case geq: return lss; + case aeq: assert(false, "Above equal cannot be negated"); + case beq: assert(false, "Below equal cannot be negated"); } ShouldNotReachHere(); return eql; @@ -70,10 +83,10 @@ } } - -Instruction* Instruction::prev(BlockBegin* block) { +// Prev without need to have BlockBegin +Instruction* Instruction::prev() { Instruction* p = NULL; - Instruction* q = block; + Instruction* q = block(); while (q != this) { assert(q != NULL, "this is not in the block's instruction list"); p = q; q = q->next(); @@ -122,15 +135,24 @@ // perform constant and interval tests on index value bool AccessIndexed::compute_needs_range_check() { - Constant* clength = length()->as_Constant(); - Constant* cindex = index()->as_Constant(); - if (clength && cindex) { - IntConstant* l = clength->type()->as_IntConstant(); - IntConstant* i = cindex->type()->as_IntConstant(); - if (l && i && i->value() < l->value() && i->value() >= 0) { - return false; + + if (length()) { + + Constant* clength = length()->as_Constant(); + Constant* cindex = index()->as_Constant(); + if (clength && cindex) { + IntConstant* l = clength->type()->as_IntConstant(); + IntConstant* i = cindex->type()->as_IntConstant(); + if (l && i && i->value() < l->value() && i->value() >= 0) { + return false; + } } } + + if (!this->check_flag(NeedsRangeCheckFlag)) { + return false; + } + return true; } @@ -631,19 +653,25 @@ // of the inserted block, without recomputing the values of the other blocks // in the CFG. Therefore the value of "depth_first_number" in BlockBegin becomes meaningless. BlockBegin* BlockBegin::insert_block_between(BlockBegin* sux) { - BlockBegin* new_sux = new BlockBegin(end()->state()->bci()); + int bci = sux->bci(); + // critical edge splitting may introduce a goto after a if and array + // bound check elimination may insert a predicate between the if and + // goto. The bci of the goto can't be the one of the if otherwise + // the state and bci are inconsistent and a deoptimization triggered + // by the predicate would lead to incorrect execution/a crash. + BlockBegin* new_sux = new BlockBegin(bci); // mark this block (special treatment when block order is computed) new_sux->set(critical_edge_split_flag); // This goto is not a safepoint. Goto* e = new Goto(sux, false); - new_sux->set_next(e, end()->state()->bci()); + new_sux->set_next(e, bci); new_sux->set_end(e); // setup states ValueStack* s = end()->state(); - new_sux->set_state(s->copy()); - e->set_state(s->copy()); + new_sux->set_state(s->copy(s->kind(), bci)); + e->set_state(s->copy(s->kind(), bci)); assert(new_sux->state()->locals_size() == s->locals_size(), "local size mismatch!"); assert(new_sux->state()->stack_size() == s->stack_size(), "stack size mismatch!"); assert(new_sux->state()->locks_size() == s->locks_size(), "locks size mismatch!"); @@ -960,15 +988,14 @@ BlockList* sux = NULL; if (begin != NULL) { sux = begin->successors(); - } else if (_begin != NULL) { + } else if (this->begin() != NULL) { // copy our sux list - BlockList* sux = new BlockList(_begin->number_of_sux()); - for (int i = 0; i < _begin->number_of_sux(); i++) { - sux->append(_begin->sux_at(i)); + BlockList* sux = new BlockList(this->begin()->number_of_sux()); + for (int i = 0; i < this->begin()->number_of_sux(); i++) { + sux->append(this->begin()->sux_at(i)); } } _sux = sux; - _begin = begin; } @@ -1008,7 +1035,38 @@ } } +#ifdef ASSERT +// Constructor of Assert +Assert::Assert(Value x, Condition cond, bool unordered_is_true, Value y) : Instruction(illegalType) + , _x(x) + , _cond(cond) + , _y(y) +{ + set_flag(UnorderedIsTrueFlag, unordered_is_true); + assert(x->type()->tag() == y->type()->tag(), "types must match"); + pin(); + stringStream strStream; + Compilation::current()->method()->print_name(&strStream); + + stringStream strStream1; + InstructionPrinter ip1(1, &strStream1); + ip1.print_instr(x); + + stringStream strStream2; + InstructionPrinter ip2(1, &strStream2); + ip2.print_instr(y); + + stringStream ss; + ss.print("Assertion %s %s %s in method %s", strStream1.as_string(), ip2.cond_name(cond), strStream2.as_string(), strStream.as_string()); + + _message = ss.as_string(); +} +#endif + +void RangeCheckPredicate::check_state() { + assert(state()->kind() != ValueStack::EmptyExceptionState && state()->kind() != ValueStack::ExceptionState, "will deopt with empty state"); +} void ProfileInvoke::state_values_do(ValueVisitor* f) { if (state() != NULL) state()->values_do(f); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_Instruction.hpp --- a/src/share/vm/c1/c1_Instruction.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_Instruction.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -110,6 +110,8 @@ class ProfileInvoke; class RuntimeCall; class MemBar; +class RangeCheckPredicate; +class Assert; // A Value is a reference to the instruction creating the value typedef Instruction* Value; @@ -210,6 +212,10 @@ virtual void do_ProfileInvoke (ProfileInvoke* x) = 0; virtual void do_RuntimeCall (RuntimeCall* x) = 0; virtual void do_MemBar (MemBar* x) = 0; + virtual void do_RangeCheckPredicate(RangeCheckPredicate* x) = 0; +#ifdef ASSERT + virtual void do_Assert (Assert* x) = 0; +#endif }; @@ -306,8 +312,9 @@ void update_exception_state(ValueStack* state); - //protected: - public: + protected: + BlockBegin* _block; // Block that contains this instruction + void set_type(ValueType* type) { assert(type != NULL, "type must exist"); _type = type; @@ -342,6 +349,9 @@ ThrowIncompatibleClassChangeErrorFlag, ProfileMDOFlag, IsLinkedInBlockFlag, + NeedsRangeCheckFlag, + InWorkListFlag, + DeoptimizeOnException, InstructionLastFlag }; @@ -351,7 +361,7 @@ // 'globally' used condition values enum Condition { - eql, neq, lss, leq, gtr, geq + eql, neq, lss, leq, gtr, geq, aeq, beq }; // Instructions may be pinned for many reasons and under certain conditions @@ -381,6 +391,7 @@ , _pin_state(0) , _type(type) , _next(NULL) + , _block(NULL) , _subst(NULL) , _flags(0) , _operand(LIR_OprFact::illegalOpr) @@ -399,11 +410,13 @@ int printable_bci() const { assert(has_printable_bci(), "_printable_bci should have been set"); return _printable_bci; } void set_printable_bci(int bci) { _printable_bci = bci; } #endif + int dominator_depth(); int use_count() const { return _use_count; } int pin_state() const { return _pin_state; } bool is_pinned() const { return _pin_state != 0 || PinAllInstructions; } ValueType* type() const { return _type; } - Instruction* prev(BlockBegin* block); // use carefully, expensive operation + BlockBegin *block() const { return _block; } + Instruction* prev(); // use carefully, expensive operation Instruction* next() const { return _next; } bool has_subst() const { return _subst != NULL; } Instruction* subst() { return _subst == NULL ? this : _subst->subst(); } @@ -432,6 +445,9 @@ assert(as_BlockEnd() == NULL, "BlockEnd instructions must have no next"); assert(next->can_be_linked(), "shouldn't link these instructions into list"); + BlockBegin *block = this->block(); + next->_block = block; + next->set_flag(Instruction::IsLinkedInBlockFlag, true); _next = next; return next; @@ -444,6 +460,29 @@ return set_next(next); } + // when blocks are merged + void fixup_block_pointers() { + Instruction *cur = next()->next(); // next()'s block is set in set_next + while (cur && cur->_block != block()) { + cur->_block = block(); + cur = cur->next(); + } + } + + Instruction *insert_after(Instruction *i) { + Instruction* n = _next; + set_next(i); + i->set_next(n); + return _next; + } + + Instruction *insert_after_same_bci(Instruction *i) { +#ifndef PRODUCT + i->set_printable_bci(printable_bci()); +#endif + return insert_after(i); + } + void set_subst(Instruction* subst) { assert(subst == NULL || type()->base() == subst->type()->base() || @@ -452,6 +491,7 @@ } void set_exception_handlers(XHandlers *xhandlers) { _exception_handlers = xhandlers; } void set_exception_state(ValueStack* s) { check_state(s); _exception_state = s; } + void set_state_before(ValueStack* s) { check_state(s); _state_before = s; } // machine-specifics void set_operand(LIR_Opr operand) { assert(operand != LIR_OprFact::illegalOpr, "operand must exist"); _operand = operand; } @@ -509,6 +549,11 @@ virtual ExceptionObject* as_ExceptionObject() { return NULL; } virtual UnsafeOp* as_UnsafeOp() { return NULL; } virtual ProfileInvoke* as_ProfileInvoke() { return NULL; } + virtual RangeCheckPredicate* as_RangeCheckPredicate() { return NULL; } + +#ifdef ASSERT + virtual Assert* as_Assert() { return NULL; } +#endif virtual void visit(InstructionVisitor* v) = 0; @@ -570,7 +615,6 @@ LEAF(Phi, Instruction) private: - BlockBegin* _block; // the block to which the phi function belongs int _pf_flags; // the flags of the phi function int _index; // to value on operand stack (index < 0) or to local public: @@ -578,9 +622,9 @@ Phi(ValueType* type, BlockBegin* b, int index) : Instruction(type->base()) , _pf_flags(0) - , _block(b) , _index(index) { + _block = b; NOT_PRODUCT(set_printable_bci(Value(b)->printable_bci())); if (type->is_illegal()) { make_illegal(); @@ -603,8 +647,6 @@ Value operand_at(int i) const; int operand_count() const; - BlockBegin* block() const { return _block; } - void set(Flag f) { _pf_flags |= f; } void clear(Flag f) { _pf_flags &= ~f; } bool is_set(Flag f) const { return (_pf_flags & f) != 0; } @@ -670,6 +712,7 @@ pin(); } + // generic virtual bool can_trap() const { return state_before() != NULL; } virtual void input_values_do(ValueVisitor* f) { /* no values */ } @@ -852,6 +895,7 @@ , _length(length) , _elt_type(elt_type) { + set_flag(Instruction::NeedsRangeCheckFlag, true); ASSERT_VALUES } @@ -860,6 +904,7 @@ Value length() const { return _length; } BasicType elt_type() const { return _elt_type; } + void clear_length() { _length = NULL; } // perform elimination of range checks involving constants bool compute_needs_range_check(); @@ -1524,6 +1569,7 @@ int _bci; // start-bci of block int _depth_first_number; // number of this block in a depth-first ordering int _linear_scan_number; // number of this block in linear-scan ordering + int _dominator_depth; int _loop_depth; // the loop nesting level of this block int _loop_index; // number of the innermost loop of this block int _flags; // the flags associated with this block @@ -1535,6 +1581,7 @@ // SSA specific fields: (factor out later) BlockList _successors; // the successors of this block BlockList _predecessors; // the predecessors of this block + BlockList _dominates; // list of blocks that are dominated by this block BlockBegin* _dominator; // the dominator of this block // SSA specific ends BlockEnd* _end; // the last instruction of this block @@ -1583,10 +1630,12 @@ , _linear_scan_number(-1) , _loop_depth(0) , _flags(0) + , _dominator_depth(-1) , _dominator(NULL) , _end(NULL) , _predecessors(2) , _successors(2) + , _dominates(2) , _exception_handlers(1) , _exception_states(NULL) , _exception_handler_pco(-1) @@ -1603,6 +1652,7 @@ , _total_preds(0) , _stores_to_locals() { + _block = this; #ifndef PRODUCT set_printable_bci(bci); #endif @@ -1612,8 +1662,10 @@ int block_id() const { return _block_id; } int bci() const { return _bci; } BlockList* successors() { return &_successors; } + BlockList* dominates() { return &_dominates; } BlockBegin* dominator() const { return _dominator; } int loop_depth() const { return _loop_depth; } + int dominator_depth() const { return _dominator_depth; } int depth_first_number() const { return _depth_first_number; } int linear_scan_number() const { return _linear_scan_number; } BlockEnd* end() const { return _end; } @@ -1634,6 +1686,7 @@ // manipulation void set_dominator(BlockBegin* dom) { _dominator = dom; } void set_loop_depth(int d) { _loop_depth = d; } + void set_dominator_depth(int d) { _dominator_depth = d; } void set_depth_first_number(int dfn) { _depth_first_number = dfn; } void set_linear_scan_number(int lsn) { _linear_scan_number = lsn; } void set_end(BlockEnd* end); @@ -1695,7 +1748,8 @@ parser_loop_header_flag = 1 << 7, // set by parser to identify blocks where phi functions can not be created on demand critical_edge_split_flag = 1 << 8, // set for all blocks that are introduced when critical edges are split linear_scan_loop_header_flag = 1 << 9, // set during loop-detection for LinearScan - linear_scan_loop_end_flag = 1 << 10 // set during loop-detection for LinearScan + linear_scan_loop_end_flag = 1 << 10, // set during loop-detection for LinearScan + donot_eliminate_range_checks = 1 << 11 // Should be try to eliminate range checks in this block }; void set(Flag f) { _flags |= f; } @@ -1728,7 +1782,6 @@ BASE(BlockEnd, StateSplit) private: - BlockBegin* _begin; BlockList* _sux; protected: @@ -1746,7 +1799,6 @@ // creation BlockEnd(ValueType* type, ValueStack* state_before, bool is_safepoint) : StateSplit(type, state_before) - , _begin(NULL) , _sux(NULL) { set_flag(IsSafepointFlag, is_safepoint); @@ -1754,7 +1806,8 @@ // accessors bool is_safepoint() const { return check_flag(IsSafepointFlag); } - BlockBegin* begin() const { return _begin; } + // For compatibility with old code, for new code use block() + BlockBegin* begin() const { return _block; } // manipulation void set_begin(BlockBegin* begin); @@ -1811,6 +1864,74 @@ void set_direction(Direction d) { _direction = d; } }; +#ifdef ASSERT +LEAF(Assert, Instruction) + private: + Value _x; + Condition _cond; + Value _y; + char *_message; + + public: + // creation + // unordered_is_true is valid for float/double compares only + Assert(Value x, Condition cond, bool unordered_is_true, Value y); + + // accessors + Value x() const { return _x; } + Condition cond() const { return _cond; } + bool unordered_is_true() const { return check_flag(UnorderedIsTrueFlag); } + Value y() const { return _y; } + const char *message() const { return _message; } + + // generic + virtual void input_values_do(ValueVisitor* f) { f->visit(&_x); f->visit(&_y); } +}; +#endif + +LEAF(RangeCheckPredicate, StateSplit) + private: + Value _x; + Condition _cond; + Value _y; + + void check_state(); + + public: + // creation + // unordered_is_true is valid for float/double compares only + RangeCheckPredicate(Value x, Condition cond, bool unordered_is_true, Value y, ValueStack* state) : StateSplit(illegalType) + , _x(x) + , _cond(cond) + , _y(y) + { + ASSERT_VALUES + set_flag(UnorderedIsTrueFlag, unordered_is_true); + assert(x->type()->tag() == y->type()->tag(), "types must match"); + this->set_state(state); + check_state(); + } + + // Always deoptimize + RangeCheckPredicate(ValueStack* state) : StateSplit(illegalType) + { + this->set_state(state); + _x = _y = NULL; + check_state(); + } + + // accessors + Value x() const { return _x; } + Condition cond() const { return _cond; } + bool unordered_is_true() const { return check_flag(UnorderedIsTrueFlag); } + Value y() const { return _y; } + + void always_fail() { _x = _y = NULL; } + + // generic + virtual void input_values_do(ValueVisitor* f) { StateSplit::input_values_do(f); f->visit(&_x); f->visit(&_y); } + HASHING3(RangeCheckPredicate, true, x()->subst(), y()->subst(), cond()) +}; LEAF(If, BlockEnd) private: diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_InstructionPrinter.cpp --- a/src/share/vm/c1/c1_InstructionPrinter.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_InstructionPrinter.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -57,6 +57,8 @@ case If::leq: return "<="; case If::gtr: return ">"; case If::geq: return ">="; + case If::aeq: return "|>=|"; + case If::beq: return "|<=|"; } ShouldNotReachHere(); return NULL; @@ -181,6 +183,11 @@ output()->put('['); print_value(indexed->index()); output()->put(']'); + if (indexed->length() != NULL) { + output()->put('('); + print_value(indexed->length()); + output()->put(')'); + } } @@ -373,6 +380,7 @@ void InstructionPrinter::do_LoadField(LoadField* x) { print_field(x); output()->print(" (%c)", type2char(x->field()->type()->basic_type())); + output()->print(" %s", x->field()->name()->as_utf8()); } @@ -381,6 +389,7 @@ output()->print(" := "); print_value(x->value()); output()->print(" (%c)", type2char(x->field()->type()->basic_type())); + output()->print(" %s", x->field()->name()->as_utf8()); } @@ -393,6 +402,9 @@ void InstructionPrinter::do_LoadIndexed(LoadIndexed* x) { print_indexed(x); output()->print(" (%c)", type2char(x->elt_type())); + if (x->check_flag(Instruction::NeedsRangeCheckFlag)) { + output()->print(" [rc]"); + } } @@ -401,6 +413,9 @@ output()->print(" := "); print_value(x->value()); output()->print(" (%c)", type2char(x->elt_type())); + if (x->check_flag(Instruction::NeedsRangeCheckFlag)) { + output()->print(" [rc]"); + } } void InstructionPrinter::do_NegateOp(NegateOp* x) { @@ -843,6 +858,25 @@ output()->put(')'); } +void InstructionPrinter::do_RangeCheckPredicate(RangeCheckPredicate* x) { + + if (x->x() != NULL && x->y() != NULL) { + output()->print("if "); + print_value(x->x()); + output()->print(" %s ", cond_name(x->cond())); + print_value(x->y()); + output()->print(" then deoptimize!"); + } else { + output()->print("always deoptimize!"); + } +} + +void InstructionPrinter::do_Assert(Assert* x) { + output()->print("assert "); + print_value(x->x()); + output()->print(" %s ", cond_name(x->cond())); + print_value(x->y()); +} void InstructionPrinter::do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { print_unsafe_object_op(x, "UnsafePrefetchWrite"); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_InstructionPrinter.hpp --- a/src/share/vm/c1/c1_InstructionPrinter.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_InstructionPrinter.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -135,6 +135,8 @@ virtual void do_ProfileInvoke (ProfileInvoke* x); virtual void do_RuntimeCall (RuntimeCall* x); virtual void do_MemBar (MemBar* x); + virtual void do_RangeCheckPredicate(RangeCheckPredicate* x); + virtual void do_Assert (Assert* x); }; #endif // PRODUCT diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_LIR.cpp --- a/src/share/vm/c1/c1_LIR.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_LIR.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -633,6 +633,7 @@ case lir_ushr: case lir_xadd: case lir_xchg: + case lir_assert: { assert(op->as_Op2() != NULL, "must be"); LIR_Op2* op2 = (LIR_Op2*)op; @@ -1112,6 +1113,11 @@ } } +#ifdef ASSERT +void LIR_OpAssert::emit_code(LIR_Assembler* masm) { + masm->emit_assert(this); +} +#endif void LIR_OpDelay::emit_code(LIR_Assembler* masm) { masm->emit_delay(this); @@ -1771,6 +1777,8 @@ case lir_cas_int: s = "cas_int"; break; // LIR_OpProfileCall case lir_profile_call: s = "profile_call"; break; + // LIR_OpAssert + case lir_assert: s = "assert"; break; case lir_none: ShouldNotReachHere();break; default: s = "illegal_op"; break; } @@ -2017,6 +2025,13 @@ out->print("[lbl:0x%x]", stub()->entry()); } +void LIR_OpAssert::print_instr(outputStream* out) const { + print_condition(out, condition()); out->print(" "); + in_opr1()->print(out); out->print(" "); + in_opr2()->print(out); out->print(", \""); + out->print(msg()); out->print("\""); +} + void LIR_OpDelay::print_instr(outputStream* out) const { _op->print_on(out); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_LIR.hpp --- a/src/share/vm/c1/c1_LIR.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_LIR.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -881,6 +881,7 @@ class LIR_OpTypeCheck; class LIR_OpCompareAndSwap; class LIR_OpProfileCall; +class LIR_OpAssert; // LIR operation codes @@ -1000,6 +1001,9 @@ , begin_opMDOProfile , lir_profile_call , end_opMDOProfile + , begin_opAssert + , lir_assert + , end_opAssert }; @@ -1135,6 +1139,7 @@ virtual LIR_OpTypeCheck* as_OpTypeCheck() { return NULL; } virtual LIR_OpCompareAndSwap* as_OpCompareAndSwap() { return NULL; } virtual LIR_OpProfileCall* as_OpProfileCall() { return NULL; } + virtual LIR_OpAssert* as_OpAssert() { return NULL; } virtual void verify() const {} }; @@ -1623,7 +1628,7 @@ , _tmp3(LIR_OprFact::illegalOpr) , _tmp4(LIR_OprFact::illegalOpr) , _tmp5(LIR_OprFact::illegalOpr) { - assert(code == lir_cmp, "code check"); + assert(code == lir_cmp || code == lir_assert, "code check"); } LIR_Op2(LIR_Code code, LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) @@ -1683,7 +1688,7 @@ LIR_Opr tmp4_opr() const { return _tmp4; } LIR_Opr tmp5_opr() const { return _tmp5; } LIR_Condition condition() const { - assert(code() == lir_cmp || code() == lir_cmove, "only valid for cmp and cmove"); return _condition; + assert(code() == lir_cmp || code() == lir_cmove || code() == lir_assert, "only valid for cmp and cmove and assert"); return _condition; } void set_condition(LIR_Condition condition) { assert(code() == lir_cmp || code() == lir_cmove, "only valid for cmp and cmove"); _condition = condition; @@ -1823,6 +1828,30 @@ CodeEmitInfo* call_info() const { return info(); } }; +#ifdef ASSERT +// LIR_OpAssert +class LIR_OpAssert : public LIR_Op2 { + friend class LIR_OpVisitState; + + private: + const char* _msg; + bool _halt; + + public: + LIR_OpAssert(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, const char* msg, bool halt) + : LIR_Op2(lir_assert, condition, opr1, opr2) + , _halt(halt) + , _msg(msg) { + } + + const char* msg() const { return _msg; } + bool halt() const { return _halt; } + + virtual void emit_code(LIR_Assembler* masm); + virtual LIR_OpAssert* as_OpAssert() { return this; } + virtual void print_instr(outputStream* out) const PRODUCT_RETURN; +}; +#endif // LIR_OpCompareAndSwap class LIR_OpCompareAndSwap : public LIR_Op { @@ -2196,6 +2225,9 @@ void xadd(LIR_Opr src, LIR_Opr add, LIR_Opr res, LIR_Opr tmp) { append(new LIR_Op2(lir_xadd, src, add, res, tmp)); } void xchg(LIR_Opr src, LIR_Opr set, LIR_Opr res, LIR_Opr tmp) { append(new LIR_Op2(lir_xchg, src, set, res, tmp)); } +#ifdef ASSERT + void lir_assert(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, const char* msg, bool halt) { append(new LIR_OpAssert(condition, opr1, opr2, msg, halt)); } +#endif }; void print_LIR(BlockList* blocks); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_LIRAssembler.hpp --- a/src/share/vm/c1/c1_LIRAssembler.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_LIRAssembler.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -210,6 +210,9 @@ void arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest, CodeEmitInfo* info, bool pop_fpu_stack); void arithmetic_idiv(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr temp, LIR_Opr result, CodeEmitInfo* info); void intrinsic_op(LIR_Code code, LIR_Opr value, LIR_Opr unused, LIR_Opr dest, LIR_Op* op); +#ifdef ASSERT + void emit_assert(LIR_OpAssert* op); +#endif void logic_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_LIRGenerator.cpp --- a/src/share/vm/c1/c1_LIRGenerator.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -403,6 +403,10 @@ CodeEmitInfo* LIRGenerator::state_for(Instruction* x, ValueStack* state, bool ignore_xhandler) { assert(state != NULL, "state must be defined"); +#ifndef PRODUCT + state->verify(); +#endif + ValueStack* s = state; for_each_state(s) { if (s->kind() == ValueStack::EmptyExceptionState) { @@ -453,7 +457,7 @@ } } - return new CodeEmitInfo(state, ignore_xhandler ? NULL : x->exception_handlers()); + return new CodeEmitInfo(state, ignore_xhandler ? NULL : x->exception_handlers(), x->check_flag(Instruction::DeoptimizeOnException)); } @@ -707,25 +711,6 @@ } } -static Value maxvalue(IfOp* ifop) { - switch (ifop->cond()) { - case If::eql: return NULL; - case If::neq: return NULL; - case If::lss: // x < y ? x : y - case If::leq: // x <= y ? x : y - if (ifop->x() == ifop->tval() && - ifop->y() == ifop->fval()) return ifop->y(); - return NULL; - - case If::gtr: // x > y ? y : x - case If::geq: // x >= y ? y : x - if (ifop->x() == ifop->tval() && - ifop->y() == ifop->fval()) return ifop->y(); - return NULL; - - } -} - static ciType* phi_declared_type(Phi* phi) { ciType* t = phi->operand_at(0)->declared_type(); if (t == NULL) { @@ -1792,11 +1777,18 @@ } #endif + bool stress_deopt = StressLoopInvariantCodeMotion && info && info->deoptimize_on_exception(); if (x->needs_null_check() && (needs_patching || - MacroAssembler::needs_explicit_null_check(x->offset()))) { + MacroAssembler::needs_explicit_null_check(x->offset()) || + stress_deopt)) { + LIR_Opr obj = object.result(); + if (stress_deopt) { + obj = new_register(T_OBJECT); + __ move(LIR_OprFact::oopConst(NULL), obj); + } // emit an explicit null check because the offset is too large - __ null_check(object.result(), new CodeEmitInfo(info)); + __ null_check(obj, new CodeEmitInfo(info)); } LIR_Opr reg = rlock_result(x, field_type); @@ -1873,6 +1865,11 @@ } else { info = state_for(nc); } + if (StressLoopInvariantCodeMotion && info->deoptimize_on_exception()) { + LIR_Opr obj = new_register(T_OBJECT); + __ move(LIR_OprFact::oopConst(NULL), obj); + __ null_check(obj, new CodeEmitInfo(info)); + } } __ load(new LIR_Address(array.result(), arrayOopDesc::length_offset_in_bytes(), T_INT), reg, info, lir_patch_none); } @@ -1883,14 +1880,11 @@ LIRItem array(x->array(), this); LIRItem index(x->index(), this); LIRItem length(this); - bool needs_range_check = true; - - if (use_length) { - needs_range_check = x->compute_needs_range_check(); - if (needs_range_check) { - length.set_instruction(x->length()); - length.load_item(); - } + bool needs_range_check = x->compute_needs_range_check(); + + if (use_length && needs_range_check) { + length.set_instruction(x->length()); + length.load_item(); } array.load_item(); @@ -1910,13 +1904,20 @@ } else { null_check_info = range_check_info; } + if (StressLoopInvariantCodeMotion && null_check_info->deoptimize_on_exception()) { + LIR_Opr obj = new_register(T_OBJECT); + __ move(LIR_OprFact::oopConst(NULL), obj); + __ null_check(obj, new CodeEmitInfo(null_check_info)); + } } // emit array address setup early so it schedules better LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), false); if (GenerateRangeChecks && needs_range_check) { - if (use_length) { + if (StressLoopInvariantCodeMotion && range_check_info->deoptimize_on_exception()) { + __ branch(lir_cond_always, T_ILLEGAL, new RangeCheckStub(range_check_info, index.result())); + } else if (use_length) { // TODO: use a (modified) version of array_range_check that does not require a // constant length to be loaded to a register __ cmp(lir_cond_belowEqual, length.result(), index.result()); @@ -2634,7 +2635,7 @@ LIR_Opr lock = new_register(T_INT); __ load_stack_address_monitor(0, lock); - CodeEmitInfo* info = new CodeEmitInfo(scope()->start()->state()->copy(ValueStack::StateBefore, SynchronizationEntryBCI), NULL); + CodeEmitInfo* info = new CodeEmitInfo(scope()->start()->state()->copy(ValueStack::StateBefore, SynchronizationEntryBCI), NULL, x->check_flag(Instruction::DeoptimizeOnException)); CodeStub* slow_path = new MonitorEnterStub(obj, lock, info); // receiver is guaranteed non-NULL so don't need CodeEmitInfo @@ -2644,7 +2645,7 @@ // increment invocation counters if needed if (!method()->is_accessor()) { // Accessors do not have MDOs, so no counting. - CodeEmitInfo* info = new CodeEmitInfo(scope()->start()->state()->copy(ValueStack::StateBefore, SynchronizationEntryBCI), NULL); + CodeEmitInfo* info = new CodeEmitInfo(scope()->start()->state()->copy(ValueStack::StateBefore, SynchronizationEntryBCI), NULL, false); increment_invocation_counter(info); } @@ -3102,6 +3103,95 @@ } } +void LIRGenerator::do_Assert(Assert *x) { +#ifdef ASSERT + ValueTag tag = x->x()->type()->tag(); + If::Condition cond = x->cond(); + + LIRItem xitem(x->x(), this); + LIRItem yitem(x->y(), this); + LIRItem* xin = &xitem; + LIRItem* yin = &yitem; + + assert(tag == intTag, "Only integer assertions are valid!"); + + xin->load_item(); + yin->dont_load_item(); + + set_no_result(x); + + LIR_Opr left = xin->result(); + LIR_Opr right = yin->result(); + + __ lir_assert(lir_cond(x->cond()), left, right, x->message(), true); +#endif +} + + +void LIRGenerator::do_RangeCheckPredicate(RangeCheckPredicate *x) { + + + Instruction *a = x->x(); + Instruction *b = x->y(); + if (!a || StressRangeCheckElimination) { + assert(!b || StressRangeCheckElimination, "B must also be null"); + + CodeEmitInfo *info = state_for(x, x->state()); + CodeStub* stub = new PredicateFailedStub(info); + + __ jump(stub); + } else if (a->type()->as_IntConstant() && b->type()->as_IntConstant()) { + int a_int = a->type()->as_IntConstant()->value(); + int b_int = b->type()->as_IntConstant()->value(); + + bool ok = false; + + switch(x->cond()) { + case Instruction::eql: ok = (a_int == b_int); break; + case Instruction::neq: ok = (a_int != b_int); break; + case Instruction::lss: ok = (a_int < b_int); break; + case Instruction::leq: ok = (a_int <= b_int); break; + case Instruction::gtr: ok = (a_int > b_int); break; + case Instruction::geq: ok = (a_int >= b_int); break; + case Instruction::aeq: ok = ((unsigned int)a_int >= (unsigned int)b_int); break; + case Instruction::beq: ok = ((unsigned int)a_int <= (unsigned int)b_int); break; + default: ShouldNotReachHere(); + } + + if (ok) { + + CodeEmitInfo *info = state_for(x, x->state()); + CodeStub* stub = new PredicateFailedStub(info); + + __ jump(stub); + } + } else { + + ValueTag tag = x->x()->type()->tag(); + If::Condition cond = x->cond(); + LIRItem xitem(x->x(), this); + LIRItem yitem(x->y(), this); + LIRItem* xin = &xitem; + LIRItem* yin = &yitem; + + assert(tag == intTag, "Only integer deoptimizations are valid!"); + + xin->load_item(); + yin->dont_load_item(); + set_no_result(x); + + LIR_Opr left = xin->result(); + LIR_Opr right = yin->result(); + + CodeEmitInfo *info = state_for(x, x->state()); + CodeStub* stub = new PredicateFailedStub(info); + + __ cmp(lir_cond(cond), left, right); + __ branch(lir_cond(cond), right->type(), stub); + } +} + + LIR_Opr LIRGenerator::call_runtime(Value arg1, address entry, ValueType* result_type, CodeEmitInfo* info) { LIRItemList args(1); LIRItem value(arg1, this); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_LIRGenerator.hpp --- a/src/share/vm/c1/c1_LIRGenerator.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_LIRGenerator.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -412,6 +412,8 @@ case If::leq: l = lir_cond_lessEqual; break; case If::geq: l = lir_cond_greaterEqual; break; case If::gtr: l = lir_cond_greater; break; + case If::aeq: l = lir_cond_aboveEqual; break; + case If::beq: l = lir_cond_belowEqual; break; }; return l; } @@ -534,6 +536,8 @@ virtual void do_ProfileInvoke (ProfileInvoke* x); virtual void do_RuntimeCall (RuntimeCall* x); virtual void do_MemBar (MemBar* x); + virtual void do_RangeCheckPredicate(RangeCheckPredicate* x); + virtual void do_Assert (Assert* x); }; diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_LinearScan.cpp --- a/src/share/vm/c1/c1_LinearScan.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_LinearScan.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -6231,26 +6231,29 @@ assert(prev_op->as_OpBranch() != NULL, "branch must be of type LIR_OpBranch"); LIR_OpBranch* prev_branch = (LIR_OpBranch*)prev_op; - LIR_Op2* prev_cmp = NULL; - - for(int j = instructions->length() - 3; j >= 0 && prev_cmp == NULL; j--) { - prev_op = instructions->at(j); - if(prev_op->code() == lir_cmp) { - assert(prev_op->as_Op2() != NULL, "branch must be of type LIR_Op2"); - prev_cmp = (LIR_Op2*)prev_op; - assert(prev_branch->cond() == prev_cmp->condition(), "should be the same"); + if (prev_branch->stub() == NULL) { + + LIR_Op2* prev_cmp = NULL; + + for(int j = instructions->length() - 3; j >= 0 && prev_cmp == NULL; j--) { + prev_op = instructions->at(j); + if (prev_op->code() == lir_cmp) { + assert(prev_op->as_Op2() != NULL, "branch must be of type LIR_Op2"); + prev_cmp = (LIR_Op2*)prev_op; + assert(prev_branch->cond() == prev_cmp->condition(), "should be the same"); + } } - } - assert(prev_cmp != NULL, "should have found comp instruction for branch"); - if (prev_branch->block() == code->at(i + 1) && prev_branch->info() == NULL) { - - TRACE_LINEAR_SCAN(3, tty->print_cr("Negating conditional branch and deleting unconditional branch at end of block B%d", block->block_id())); - - // eliminate a conditional branch to the immediate successor - prev_branch->change_block(last_branch->block()); - prev_branch->negate_cond(); - prev_cmp->set_condition(prev_branch->cond()); - instructions->truncate(instructions->length() - 1); + assert(prev_cmp != NULL, "should have found comp instruction for branch"); + if (prev_branch->block() == code->at(i + 1) && prev_branch->info() == NULL) { + + TRACE_LINEAR_SCAN(3, tty->print_cr("Negating conditional branch and deleting unconditional branch at end of block B%d", block->block_id())); + + // eliminate a conditional branch to the immediate successor + prev_branch->change_block(last_branch->block()); + prev_branch->negate_cond(); + prev_cmp->set_condition(prev_branch->cond()); + instructions->truncate(instructions->length() - 1); + } } } } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_Optimizer.cpp --- a/src/share/vm/c1/c1_Optimizer.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_Optimizer.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -178,7 +178,7 @@ // 2) substitute conditional expression // with an IfOp followed by a Goto // cut if_ away and get node before - Instruction* cur_end = if_->prev(block); + Instruction* cur_end = if_->prev(); // append constants of true- and false-block if necessary // clone constants because original block must not be destroyed @@ -202,7 +202,7 @@ } // append Goto to successor - ValueStack* state_before = if_->is_safepoint() ? if_->state_before() : NULL; + ValueStack* state_before = if_->state_before(); Goto* goto_ = new Goto(sux, state_before, if_->is_safepoint() || t_goto->is_safepoint() || f_goto->is_safepoint()); // prepare state for Goto @@ -367,10 +367,11 @@ #endif // find instruction before end & append first instruction of sux block - Instruction* prev = end->prev(block); + Instruction* prev = end->prev(); Instruction* next = sux->next(); assert(prev->as_BlockEnd() == NULL, "must not be a BlockEnd"); prev->set_next(next); + prev->fixup_block_pointers(); sux->disconnect_from_graph(); block->set_end(sux->end()); // add exception handlers of deleted block, if any @@ -533,6 +534,8 @@ void do_ProfileInvoke (ProfileInvoke* x); void do_RuntimeCall (RuntimeCall* x); void do_MemBar (MemBar* x); + void do_RangeCheckPredicate(RangeCheckPredicate* x); + void do_Assert (Assert* x); }; @@ -714,6 +717,8 @@ void NullCheckVisitor::do_ProfileInvoke (ProfileInvoke* x) {} void NullCheckVisitor::do_RuntimeCall (RuntimeCall* x) {} void NullCheckVisitor::do_MemBar (MemBar* x) {} +void NullCheckVisitor::do_RangeCheckPredicate(RangeCheckPredicate* x) {} +void NullCheckVisitor::do_Assert (Assert* x) {} void NullCheckEliminator::visit(Value* p) { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_RangeCheckElimination.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/c1/c1_RangeCheckElimination.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -0,0 +1,1517 @@ +/* + * Copyright (c) 2012, 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. + * + */ + +#include "precompiled.hpp" +#include "c1/c1_ValueStack.hpp" +#include "c1/c1_RangeCheckElimination.hpp" +#include "c1/c1_IR.hpp" +#include "c1/c1_Canonicalizer.hpp" +#include "c1/c1_ValueMap.hpp" +#include "ci/ciMethodData.hpp" +#include "runtime/deoptimization.hpp" + +// Macros for the Trace and the Assertion flag +#ifdef ASSERT +#define TRACE_RANGE_CHECK_ELIMINATION(code) if (TraceRangeCheckElimination) { code; } +#define ASSERT_RANGE_CHECK_ELIMINATION(code) if (AssertRangeCheckElimination) { code; } +#define TRACE_OR_ASSERT_RANGE_CHECK_ELIMINATION(code) if (TraceRangeCheckElimination || AssertRangeCheckElimination) { code; } +#else +#define TRACE_RANGE_CHECK_ELIMINATION(code) +#define ASSERT_RANGE_CHECK_ELIMINATION(code) +#define TRACE_OR_ASSERT_RANGE_CHECK_ELIMINATION(code) +#endif + +// Entry point for the optimization +void RangeCheckElimination::eliminate(IR *ir) { + bool do_elimination = ir->compilation()->has_access_indexed(); + ASSERT_RANGE_CHECK_ELIMINATION(do_elimination = true); + if (do_elimination) { + RangeCheckEliminator rce(ir); + } +} + +// Constructor +RangeCheckEliminator::RangeCheckEliminator(IR *ir) : + _bounds(Instruction::number_of_instructions(), NULL), + _access_indexed_info(Instruction::number_of_instructions(), NULL) +{ + _visitor.set_range_check_eliminator(this); + _ir = ir; + _number_of_instructions = Instruction::number_of_instructions(); + _optimistic = ir->compilation()->is_optimistic(); + + TRACE_RANGE_CHECK_ELIMINATION( + tty->print_cr(""); + tty->print_cr("Range check elimination"); + ir->method()->print_name(tty); + tty->print_cr(""); + ); + + TRACE_RANGE_CHECK_ELIMINATION( + tty->print_cr("optimistic=%d", (int)_optimistic); + ); + +#ifdef ASSERT + // Verifies several conditions that must be true on the IR-input. Only used for debugging purposes. + TRACE_RANGE_CHECK_ELIMINATION( + tty->print_cr("Verification of IR . . ."); + ); + Verification verification(ir); +#endif + + // Set process block flags + // Optimization so a blocks is only processed if it contains an access indexed instruction or if + // one of its children in the dominator tree contains an access indexed instruction. + set_process_block_flags(ir->start()); + + // Pass over instructions in the dominator tree + TRACE_RANGE_CHECK_ELIMINATION( + tty->print_cr("Starting pass over dominator tree . . .") + ); + calc_bounds(ir->start(), NULL); + + TRACE_RANGE_CHECK_ELIMINATION( + tty->print_cr("Finished!") + ); +} + +// Instruction specific work for some instructions +// Constant +void RangeCheckEliminator::Visitor::do_Constant(Constant *c) { + IntConstant *ic = c->type()->as_IntConstant(); + if (ic != NULL) { + int value = ic->value(); + _bound = new Bound(value, NULL, value, NULL); + } +} + +// LogicOp +void RangeCheckEliminator::Visitor::do_LogicOp(LogicOp *lo) { + if (lo->type()->as_IntType() && lo->op() == Bytecodes::_iand && (lo->x()->as_Constant() || lo->y()->as_Constant())) { + int constant = 0; + Constant *c = lo->x()->as_Constant(); + if (c != NULL) { + constant = c->type()->as_IntConstant()->value(); + } else { + constant = lo->y()->as_Constant()->type()->as_IntConstant()->value(); + } + if (constant >= 0) { + _bound = new Bound(0, NULL, constant, NULL); + } + } +} + +// Phi +void RangeCheckEliminator::Visitor::do_Phi(Phi *phi) { + if (!phi->type()->as_IntType() && !phi->type()->as_ObjectType()) return; + + BlockBegin *block = phi->block(); + int op_count = phi->operand_count(); + bool has_upper = true; + bool has_lower = true; + assert(phi, "Phi must not be null"); + Bound *bound = NULL; + + // TODO: support more difficult phis + for (int i=0; ioperand_at(i); + + if (v == phi) continue; + + // Check if instruction is connected with phi itself + Op2 *op2 = v->as_Op2(); + if (op2 != NULL) { + Value x = op2->x(); + Value y = op2->y(); + if ((x == phi || y == phi)) { + Value other = x; + if (other == phi) { + other = y; + } + ArithmeticOp *ao = v->as_ArithmeticOp(); + if (ao != NULL && ao->op() == Bytecodes::_iadd) { + assert(ao->op() == Bytecodes::_iadd, "Has to be add!"); + if (ao->type()->as_IntType()) { + Constant *c = other->as_Constant(); + if (c != NULL) { + assert(c->type()->as_IntConstant(), "Constant has to be of type integer"); + int value = c->type()->as_IntConstant()->value(); + if (value == 1) { + has_upper = false; + } else if (value > 1) { + // Overflow not guaranteed + has_upper = false; + has_lower = false; + } else if (value < 0) { + has_lower = false; + } + continue; + } + } + } + } + } + + // No connection -> new bound + Bound *v_bound = _rce->get_bound(v); + Bound *cur_bound; + int cur_constant = 0; + Value cur_value = v; + + if (v->type()->as_IntConstant()) { + cur_constant = v->type()->as_IntConstant()->value(); + cur_value = NULL; + } + if (!v_bound->has_upper() || !v_bound->has_lower()) { + cur_bound = new Bound(cur_constant, cur_value, cur_constant, cur_value); + } else { + cur_bound = v_bound; + } + if (cur_bound) { + if (!bound) { + bound = cur_bound->copy(); + } else { + bound->or_op(cur_bound); + } + } else { + // No bound! + bound = NULL; + break; + } + } + + if (bound) { + if (!has_upper) { + bound->remove_upper(); + } + if (!has_lower) { + bound->remove_lower(); + } + _bound = bound; + } else { + _bound = new Bound(); + } +} + + +// ArithmeticOp +void RangeCheckEliminator::Visitor::do_ArithmeticOp(ArithmeticOp *ao) { + Value x = ao->x(); + Value y = ao->y(); + + if (ao->op() == Bytecodes::_irem) { + Bound* x_bound = _rce->get_bound(x); + Bound* y_bound = _rce->get_bound(y); + if (x_bound->lower() >= 0 && x_bound->lower_instr() == NULL && y->as_ArrayLength() != NULL) { + _bound = new Bound(0, NULL, -1, y); + } else { + _bound = new Bound(); + } + } else if (!x->as_Constant() || !y->as_Constant()) { + assert(!x->as_Constant() || !y->as_Constant(), "One of the operands must be non-constant!"); + if (((x->as_Constant() || y->as_Constant()) && (ao->op() == Bytecodes::_iadd)) || (y->as_Constant() && ao->op() == Bytecodes::_isub)) { + assert(ao->op() == Bytecodes::_iadd || ao->op() == Bytecodes::_isub, "Operand must be iadd or isub"); + + if (y->as_Constant()) { + Value tmp = x; + x = y; + y = tmp; + } + assert(x->as_Constant()->type()->as_IntConstant(), "Constant must be int constant!"); + + // Constant now in x + int const_value = x->as_Constant()->type()->as_IntConstant()->value(); + if (ao->op() == Bytecodes::_iadd || const_value != min_jint) { + if (ao->op() == Bytecodes::_isub) { + const_value = -const_value; + } + + Bound * bound = _rce->get_bound(y); + if (bound->has_upper() && bound->has_lower()) { + int new_lower = bound->lower() + const_value; + jlong new_lowerl = ((jlong)bound->lower()) + const_value; + int new_upper = bound->upper() + const_value; + jlong new_upperl = ((jlong)bound->upper()) + const_value; + + if (((jlong)new_lower) == new_lowerl && ((jlong)new_upper == new_upperl)) { + Bound *newBound = new Bound(new_lower, bound->lower_instr(), new_upper, bound->upper_instr()); + _bound = newBound; + } else { + // overflow + _bound = new Bound(); + } + } else { + _bound = new Bound(); + } + } else { + _bound = new Bound(); + } + } else { + Bound *bound = _rce->get_bound(x); + if (ao->op() == Bytecodes::_isub) { + if (bound->lower_instr() == y) { + _bound = new Bound(Instruction::geq, NULL, bound->lower()); + } else { + _bound = new Bound(); + } + } else { + _bound = new Bound(); + } + } + } +} + +// IfOp +void RangeCheckEliminator::Visitor::do_IfOp(IfOp *ifOp) +{ + if (ifOp->tval()->type()->as_IntConstant() && ifOp->fval()->type()->as_IntConstant()) { + int min = ifOp->tval()->type()->as_IntConstant()->value(); + int max = ifOp->fval()->type()->as_IntConstant()->value(); + if (min > max) { + // min ^= max ^= min ^= max; + int tmp = min; + min = max; + max = tmp; + } + _bound = new Bound(min, NULL, max, NULL); + } +} + +// Get bound. Returns the current bound on Value v. Normally this is the topmost element on the bound stack. +RangeCheckEliminator::Bound *RangeCheckEliminator::get_bound(Value v) { + // Wrong type or NULL -> No bound + if (!v || (!v->type()->as_IntType() && !v->type()->as_ObjectType())) return NULL; + + if (!_bounds[v->id()]) { + // First (default) bound is calculated + // Create BoundStack + _bounds[v->id()] = new BoundStack(); + _visitor.clear_bound(); + Value visit_value = v; + visit_value->visit(&_visitor); + Bound *bound = _visitor.bound(); + if (bound) { + _bounds[v->id()]->push(bound); + } + if (_bounds[v->id()]->length() == 0) { + assert(!(v->as_Constant() && v->type()->as_IntConstant()), "constants not handled here"); + _bounds[v->id()]->push(new Bound()); + } + } else if (_bounds[v->id()]->length() == 0) { + // To avoid endless loops, bound is currently in calculation -> nothing known about it + return new Bound(); + } + + // Return bound + return _bounds[v->id()]->top(); +} + +// Update bound +void RangeCheckEliminator::update_bound(IntegerStack &pushed, Value v, Instruction::Condition cond, Value value, int constant) { + if (cond == Instruction::gtr) { + cond = Instruction::geq; + constant++; + } else if (cond == Instruction::lss) { + cond = Instruction::leq; + constant--; + } + Bound *bound = new Bound(cond, value, constant); + update_bound(pushed, v, bound); +} + +// Checks for loop invariance. Returns true if the instruction is outside of the loop which is identified by loop_header. +bool RangeCheckEliminator::loop_invariant(BlockBegin *loop_header, Instruction *instruction) { + assert(loop_header, "Loop header must not be null!"); + if (!instruction) return true; + return instruction->dominator_depth() < loop_header->dominator_depth(); +} + +// Update bound. Pushes a new bound onto the stack. Tries to do a conjunction with the current bound. +void RangeCheckEliminator::update_bound(IntegerStack &pushed, Value v, Bound *bound) { + if (v->as_Constant()) { + // No bound update for constants + return; + } + if (!_bounds[v->id()]) { + get_bound(v); + assert(_bounds[v->id()], "Now Stack must exist"); + } + Bound *top = NULL; + if (_bounds[v->id()]->length() > 0) { + top = _bounds[v->id()]->top(); + } + if (top) { + bound->and_op(top); + } + _bounds[v->id()]->push(bound); + pushed.append(v->id()); +} + +// Add instruction + idx for in block motion +void RangeCheckEliminator::add_access_indexed_info(InstructionList &indices, int idx, Value instruction, AccessIndexed *ai) { + int id = instruction->id(); + AccessIndexedInfo *aii = _access_indexed_info[id]; + if (aii == NULL) { + aii = new AccessIndexedInfo(); + _access_indexed_info[id] = aii; + indices.append(instruction); + aii->_min = idx; + aii->_max = idx; + aii->_list = new AccessIndexedList(); + } else if (idx >= aii->_min && idx <= aii->_max) { + remove_range_check(ai); + return; + } + aii->_min = MIN2(aii->_min, idx); + aii->_max = MAX2(aii->_max, idx); + aii->_list->append(ai); +} + +// In block motion. Tries to reorder checks in order to reduce some of them. +// Example: +// a[i] = 0; +// a[i+2] = 0; +// a[i+1] = 0; +// In this example the check for a[i+1] would be considered as unnecessary during the first iteration. +// After this i is only checked once for i >= 0 and i+2 < a.length before the first array access. If this +// check fails, deoptimization is called. +void RangeCheckEliminator::in_block_motion(BlockBegin *block, AccessIndexedList &accessIndexed, InstructionList &arrays) { + InstructionList indices; + + // Now iterate over all arrays + for (int i=0; iarray() != array || !ai->check_flag(Instruction::NeedsRangeCheckFlag)) continue; + + Value index = ai->index(); + Constant *c = index->as_Constant(); + if (c != NULL) { + int constant_value = c->type()->as_IntConstant()->value(); + if (constant_value >= 0) { + if (constant_value <= max_constant) { + // No range check needed for this + remove_range_check(ai); + } else { + max_constant = constant_value; + list_constant.append(ai); + } + } + } else { + int last_integer = 0; + Instruction *last_instruction = index; + int base = 0; + ArithmeticOp *ao = index->as_ArithmeticOp(); + + while (ao != NULL && (ao->x()->as_Constant() || ao->y()->as_Constant()) && (ao->op() == Bytecodes::_iadd || ao->op() == Bytecodes::_isub)) { + c = ao->y()->as_Constant(); + Instruction *other = ao->x(); + if (!c && ao->op() == Bytecodes::_iadd) { + c = ao->x()->as_Constant(); + other = ao->y(); + } + + if (c) { + int value = c->type()->as_IntConstant()->value(); + if (value != min_jint) { + if (ao->op() == Bytecodes::_isub) { + value = -value; + } + base += value; + last_integer = base; + last_instruction = other; + } + index = other; + } else { + break; + } + ao = index->as_ArithmeticOp(); + } + add_access_indexed_info(indices, last_integer, last_instruction, ai); + } + } + + // Iterate over all different indices + if (_optimistic) { + for (int i=0; iid()]; + assert(info != NULL, "Info must not be null"); + + // if idx < 0, max > 0, max + idx may fall between 0 and + // length-1 and if min < 0, min + idx may overflow and be >= + // 0. The predicate wouldn't trigger but some accesses could + // be with a negative index. This test guarantees that for the + // min and max value that are kept the predicate can't let + // some incorrect accesses happen. + bool range_cond = (info->_max < 0 || info->_max + min_jint <= info->_min); + + // Generate code only if more than 2 range checks can be eliminated because of that. + // 2 because at least 2 comparisons are done + if (info->_list->length() > 2 && range_cond) { + AccessIndexed *first = info->_list->at(0); + Instruction *insert_position = first->prev(); + assert(insert_position->next() == first, "prev was calculated"); + ValueStack *state = first->state_before(); + + // Load min Constant + Constant *min_constant = NULL; + if (info->_min != 0) { + min_constant = new Constant(new IntConstant(info->_min)); + NOT_PRODUCT(min_constant->set_printable_bci(first->printable_bci())); + insert_position = insert_position->insert_after(min_constant); + } + + // Load max Constant + Constant *max_constant = NULL; + if (info->_max != 0) { + max_constant = new Constant(new IntConstant(info->_max)); + NOT_PRODUCT(max_constant->set_printable_bci(first->printable_bci())); + insert_position = insert_position->insert_after(max_constant); + } + + // Load array length + Value length_instr = first->length(); + if (!length_instr) { + ArrayLength *length = new ArrayLength(array, first->state_before()->copy()); + length->set_exception_state(length->state_before()); + length->set_flag(Instruction::DeoptimizeOnException, true); + insert_position = insert_position->insert_after_same_bci(length); + length_instr = length; + } + + // Calculate lower bound + Instruction *lower_compare = index_instruction; + if (min_constant) { + ArithmeticOp *ao = new ArithmeticOp(Bytecodes::_iadd, min_constant, lower_compare, false, NULL); + insert_position = insert_position->insert_after_same_bci(ao); + lower_compare = ao; + } + + // Calculate upper bound + Instruction *upper_compare = index_instruction; + if (max_constant) { + ArithmeticOp *ao = new ArithmeticOp(Bytecodes::_iadd, max_constant, upper_compare, false, NULL); + insert_position = insert_position->insert_after_same_bci(ao); + upper_compare = ao; + } + + // Trick with unsigned compare is done + int bci = NOT_PRODUCT(first->printable_bci()) PRODUCT_ONLY(-1); + insert_position = predicate(upper_compare, Instruction::aeq, length_instr, state, insert_position, bci); + insert_position = predicate_cmp_with_const(lower_compare, Instruction::leq, -1, state, insert_position); + for (int j = 0; j_list->length(); j++) { + AccessIndexed *ai = info->_list->at(j); + remove_range_check(ai); + } + } + _access_indexed_info[index_instruction->id()] = NULL; + } + indices.clear(); + + if (list_constant.length() > 1) { + AccessIndexed *first = list_constant.at(0); + Instruction *insert_position = first->prev(); + ValueStack *state = first->state_before(); + // Load max Constant + Constant *constant = new Constant(new IntConstant(max_constant)); + NOT_PRODUCT(constant->set_printable_bci(first->printable_bci())); + insert_position = insert_position->insert_after(constant); + Instruction *compare_instr = constant; + Value length_instr = first->length(); + if (!length_instr) { + ArrayLength *length = new ArrayLength(array, state->copy()); + length->set_exception_state(length->state_before()); + length->set_flag(Instruction::DeoptimizeOnException, true); + insert_position = insert_position->insert_after_same_bci(length); + length_instr = length; + } + // Compare for greater or equal to array length + insert_position = predicate(compare_instr, Instruction::geq, length_instr, state, insert_position); + for (int j = 0; jas_AccessIndexed() != NULL); + cur = cur->next(); + } + + BlockList *dominates = block->dominates(); + for (int i=0; ilength(); i++) { + BlockBegin *next = dominates->at(i); + process |= set_process_block_flags(next); + } + + if (!process) { + block->set(BlockBegin::donot_eliminate_range_checks); + } + return process; +} + +bool RangeCheckEliminator::is_ok_for_deoptimization(Instruction *insert_position, Instruction *array_instr, Instruction *length_instr, Instruction *lower_instr, int lower, Instruction *upper_instr, int upper) { + bool upper_check = true; + assert(lower_instr || lower >= 0, "If no lower_instr present, lower must be greater 0"); + assert(!lower_instr || lower_instr->dominator_depth() <= insert_position->dominator_depth(), "Dominator depth must be smaller"); + assert(!upper_instr || upper_instr->dominator_depth() <= insert_position->dominator_depth(), "Dominator depth must be smaller"); + assert(array_instr, "Array instruction must exist"); + assert(array_instr->dominator_depth() <= insert_position->dominator_depth(), "Dominator depth must be smaller"); + assert(!length_instr || length_instr->dominator_depth() <= insert_position->dominator_depth(), "Dominator depth must be smaller"); + + if (upper_instr && upper_instr->as_ArrayLength() && upper_instr->as_ArrayLength()->array() == array_instr) { + // static check + if (upper >= 0) return false; // would always trigger a deopt: + // array_length + x >= array_length, x >= 0 is always true + upper_check = false; + } + if (lower_instr && lower_instr->as_ArrayLength() && lower_instr->as_ArrayLength()->array() == array_instr) { + if (lower > 0) return false; + } + // No upper check required -> skip + if (upper_check && upper_instr && upper_instr->type()->as_ObjectType() && upper_instr == array_instr) { + // upper_instr is object means that the upper bound is the length + // of the upper_instr. + return false; + } + return true; +} + +Instruction* RangeCheckEliminator::insert_after(Instruction* insert_position, Instruction* instr, int bci) { + if (bci != -1) { + NOT_PRODUCT(instr->set_printable_bci(bci)); + return insert_position->insert_after(instr); + } else { + return insert_position->insert_after_same_bci(instr); + } +} + +Instruction* RangeCheckEliminator::predicate(Instruction* left, Instruction::Condition cond, Instruction* right, ValueStack* state, Instruction *insert_position, int bci) { + RangeCheckPredicate *deoptimize = new RangeCheckPredicate(left, cond, true, right, state->copy()); + return insert_after(insert_position, deoptimize, bci); +} + +Instruction* RangeCheckEliminator::predicate_cmp_with_const(Instruction* instr, Instruction::Condition cond, int constant, ValueStack* state, Instruction *insert_position, int bci) { + Constant *const_instr = new Constant(new IntConstant(constant)); + insert_position = insert_after(insert_position, const_instr, bci); + return predicate(instr, cond, const_instr, state, insert_position); +} + +Instruction* RangeCheckEliminator::predicate_add(Instruction* left, int left_const, Instruction::Condition cond, Instruction* right, ValueStack* state, Instruction *insert_position, int bci) { + Constant *constant = new Constant(new IntConstant(left_const)); + insert_position = insert_after(insert_position, constant, bci); + ArithmeticOp *ao = new ArithmeticOp(Bytecodes::_iadd, constant, left, false, NULL); + insert_position = insert_position->insert_after_same_bci(ao); + return predicate(ao, cond, right, state, insert_position); +} + +Instruction* RangeCheckEliminator::predicate_add_cmp_with_const(Instruction* left, int left_const, Instruction::Condition cond, int constant, ValueStack* state, Instruction *insert_position, int bci) { + Constant *const_instr = new Constant(new IntConstant(constant)); + insert_position = insert_after(insert_position, const_instr, bci); + return predicate_add(left, left_const, cond, const_instr, state, insert_position); +} + +// Insert deoptimization +void RangeCheckEliminator::insert_deoptimization(ValueStack *state, Instruction *insert_position, Instruction *array_instr, Instruction *length_instr, Instruction *lower_instr, int lower, Instruction *upper_instr, int upper, AccessIndexed *ai) { + assert(is_ok_for_deoptimization(insert_position, array_instr, length_instr, lower_instr, lower, upper_instr, upper), "should have been tested before"); + bool upper_check = !(upper_instr && upper_instr->as_ArrayLength() && upper_instr->as_ArrayLength()->array() == array_instr); + + int bci = NOT_PRODUCT(ai->printable_bci()) PRODUCT_ONLY(-1); + if (lower_instr) { + assert(!lower_instr->type()->as_ObjectType(), "Must not be object type"); + if (lower == 0) { + // Compare for less than 0 + insert_position = predicate_cmp_with_const(lower_instr, Instruction::lss, 0, state, insert_position, bci); + } else if (lower > 0) { + // Compare for smaller 0 + insert_position = predicate_add_cmp_with_const(lower_instr, lower, Instruction::lss, 0, state, insert_position, bci); + } else { + assert(lower < 0, ""); + // Add 1 + lower++; + lower = -lower; + // Compare for smaller or equal 0 + insert_position = predicate_cmp_with_const(lower_instr, Instruction::leq, lower, state, insert_position, bci); + } + } + + // No upper check required -> skip + if (!upper_check) return; + + // We need to know length of array + if (!length_instr) { + // Load length if necessary + ArrayLength *length = new ArrayLength(array_instr, state->copy()); + NOT_PRODUCT(length->set_printable_bci(ai->printable_bci())); + length->set_exception_state(length->state_before()); + length->set_flag(Instruction::DeoptimizeOnException, true); + insert_position = insert_position->insert_after(length); + length_instr = length; + } + + if (!upper_instr) { + // Compare for geq array.length + insert_position = predicate_cmp_with_const(length_instr, Instruction::leq, upper, state, insert_position, bci); + } else { + if (upper_instr->type()->as_ObjectType()) { + assert(state, "must not be null"); + assert(upper_instr != array_instr, "should be"); + ArrayLength *length = new ArrayLength(upper_instr, state->copy()); + NOT_PRODUCT(length->set_printable_bci(ai->printable_bci())); + length->set_flag(Instruction::DeoptimizeOnException, true); + length->set_exception_state(length->state_before()); + insert_position = insert_position->insert_after(length); + upper_instr = length; + } + assert(upper_instr->type()->as_IntType(), "Must not be object type!"); + + if (upper == 0) { + // Compare for geq array.length + insert_position = predicate(upper_instr, Instruction::geq, length_instr, state, insert_position, bci); + } else if (upper < 0) { + // Compare for geq array.length + insert_position = predicate_add(upper_instr, upper, Instruction::geq, length_instr, state, insert_position, bci); + } else { + assert(upper > 0, ""); + upper = -upper; + // Compare for geq array.length + insert_position = predicate_add(length_instr, upper, Instruction::leq, upper_instr, state, insert_position, bci); + } + } +} + +// Add if condition +void RangeCheckEliminator::add_if_condition(IntegerStack &pushed, Value x, Value y, Instruction::Condition condition) { + if (y->as_Constant()) return; + + int const_value = 0; + Value instr_value = x; + Constant *c = x->as_Constant(); + ArithmeticOp *ao = x->as_ArithmeticOp(); + + if (c != NULL) { + const_value = c->type()->as_IntConstant()->value(); + instr_value = NULL; + } else if (ao != NULL && (!ao->x()->as_Constant() || !ao->y()->as_Constant()) && ((ao->op() == Bytecodes::_isub && ao->y()->as_Constant()) || ao->op() == Bytecodes::_iadd)) { + assert(!ao->x()->as_Constant() || !ao->y()->as_Constant(), "At least one operator must be non-constant!"); + assert(ao->op() == Bytecodes::_isub || ao->op() == Bytecodes::_iadd, "Operation has to be add or sub!"); + c = ao->x()->as_Constant(); + if (c != NULL) { + const_value = c->type()->as_IntConstant()->value(); + instr_value = ao->y(); + } else { + c = ao->y()->as_Constant(); + if (c != NULL) { + const_value = c->type()->as_IntConstant()->value(); + instr_value = ao->x(); + } + } + if (ao->op() == Bytecodes::_isub) { + assert(ao->y()->as_Constant(), "1 - x not supported, only x - 1 is valid!"); + if (const_value > min_jint) { + const_value = -const_value; + } else { + const_value = 0; + instr_value = x; + } + } + } + + update_bound(pushed, y, condition, instr_value, const_value); +} + +// Process If +void RangeCheckEliminator::process_if(IntegerStack &pushed, BlockBegin *block, If *cond) { + // Only if we are direct true / false successor and NOT both ! (even this may occur) + if ((cond->tsux() == block || cond->fsux() == block) && cond->tsux() != cond->fsux()) { + Instruction::Condition condition = cond->cond(); + if (cond->fsux() == block) { + condition = Instruction::negate(condition); + } + Value x = cond->x(); + Value y = cond->y(); + if (x->type()->as_IntType() && y->type()->as_IntType()) { + add_if_condition(pushed, y, x, condition); + add_if_condition(pushed, x, y, Instruction::mirror(condition)); + } + } +} + +// Process access indexed +void RangeCheckEliminator::process_access_indexed(BlockBegin *loop_header, BlockBegin *block, AccessIndexed *ai) { + TRACE_RANGE_CHECK_ELIMINATION( + tty->fill_to(block->dominator_depth()*2) + ); + TRACE_RANGE_CHECK_ELIMINATION( + tty->print_cr("Access indexed: index=%d length=%d", ai->index()->id(), (ai->length() != NULL ? ai->length()->id() :-1 )) + ); + + if (ai->check_flag(Instruction::NeedsRangeCheckFlag)) { + Bound *index_bound = get_bound(ai->index()); + if (!index_bound->has_lower() || !index_bound->has_upper()) { + TRACE_RANGE_CHECK_ELIMINATION( + tty->fill_to(block->dominator_depth()*2); + tty->print_cr("Index instruction %d has no lower and/or no upper bound!", ai->index()->id()) + ); + return; + } + + Bound *array_bound; + if (ai->length()) { + array_bound = get_bound(ai->length()); + } else { + array_bound = get_bound(ai->array()); + } + + if (in_array_bound(index_bound, ai->array()) || + (index_bound && array_bound && index_bound->is_smaller(array_bound) && !index_bound->lower_instr() && index_bound->lower() >= 0)) { + TRACE_RANGE_CHECK_ELIMINATION( + tty->fill_to(block->dominator_depth()*2); + tty->print_cr("Bounds check for instruction %d in block B%d can be fully eliminated!", ai->id(), ai->block()->block_id()) + ); + + remove_range_check(ai); + } else if (_optimistic && loop_header) { + assert(ai->array(), "Array must not be null!"); + assert(ai->index(), "Index must not be null!"); + + // Array instruction + Instruction *array_instr = ai->array(); + if (!loop_invariant(loop_header, array_instr)) { + TRACE_RANGE_CHECK_ELIMINATION( + tty->fill_to(block->dominator_depth()*2); + tty->print_cr("Array %d is not loop invariant to header B%d", ai->array()->id(), loop_header->block_id()) + ); + return; + } + + // Lower instruction + Value index_instr = ai->index(); + Value lower_instr = index_bound->lower_instr(); + if (!loop_invariant(loop_header, lower_instr)) { + TRACE_RANGE_CHECK_ELIMINATION( + tty->fill_to(block->dominator_depth()*2); + tty->print_cr("Lower instruction %d not loop invariant!", lower_instr->id()) + ); + return; + } + if (!lower_instr && index_bound->lower() < 0) { + TRACE_RANGE_CHECK_ELIMINATION( + tty->fill_to(block->dominator_depth()*2); + tty->print_cr("Lower bound smaller than 0 (%d)!", index_bound->lower()) + ); + return; + } + + // Upper instruction + Value upper_instr = index_bound->upper_instr(); + if (!loop_invariant(loop_header, upper_instr)) { + TRACE_RANGE_CHECK_ELIMINATION( + tty->fill_to(block->dominator_depth()*2); + tty->print_cr("Upper instruction %d not loop invariant!", upper_instr->id()) + ); + return; + } + + // Length instruction + Value length_instr = ai->length(); + if (!loop_invariant(loop_header, length_instr)) { + // Generate length instruction yourself! + length_instr = NULL; + } + + TRACE_RANGE_CHECK_ELIMINATION( + tty->fill_to(block->dominator_depth()*2); + tty->print_cr("LOOP INVARIANT access indexed %d found in block B%d!", ai->id(), ai->block()->block_id()) + ); + + BlockBegin *pred_block = loop_header->dominator(); + assert(pred_block != NULL, "Every loop header has a dominator!"); + BlockEnd *pred_block_end = pred_block->end(); + Instruction *insert_position = pred_block_end->prev(); + ValueStack *state = pred_block_end->state_before(); + if (pred_block_end->as_Goto() && state == NULL) state = pred_block_end->state(); + assert(state, "State must not be null"); + + // Add deoptimization to dominator of loop header + TRACE_RANGE_CHECK_ELIMINATION( + tty->fill_to(block->dominator_depth()*2); + tty->print_cr("Inserting deopt at bci %d in block B%d!", state->bci(), insert_position->block()->block_id()) + ); + + if (!is_ok_for_deoptimization(insert_position, array_instr, length_instr, lower_instr, index_bound->lower(), upper_instr, index_bound->upper())) { + TRACE_RANGE_CHECK_ELIMINATION( + tty->fill_to(block->dominator_depth()*2); + tty->print_cr("Could not eliminate because of static analysis!") + ); + return; + } + + insert_deoptimization(state, insert_position, array_instr, length_instr, lower_instr, index_bound->lower(), upper_instr, index_bound->upper(), ai); + + // Finally remove the range check! + remove_range_check(ai); + } + } +} + +void RangeCheckEliminator::remove_range_check(AccessIndexed *ai) { + ai->set_flag(Instruction::NeedsRangeCheckFlag, false); + // no range check, no need for the length instruction anymore + ai->clear_length(); + + TRACE_RANGE_CHECK_ELIMINATION( + tty->fill_to(ai->dominator_depth()*2); + tty->print_cr("Range check for instruction %d eliminated!", ai->id()); + ); + + ASSERT_RANGE_CHECK_ELIMINATION( + Value array_length = ai->length(); + if (!array_length) { + array_length = ai->array(); + assert(array_length->type()->as_ObjectType(), "Has to be object type!"); + } + int cur_constant = -1; + Value cur_value = array_length; + if (cur_value->type()->as_IntConstant()) { + cur_constant += cur_value->type()->as_IntConstant()->value(); + cur_value = NULL; + } + Bound *new_index_bound = new Bound(0, NULL, cur_constant, cur_value); + add_assertions(new_index_bound, ai->index(), ai); + ); +} + +// Calculate bounds for instruction in this block and children blocks in the dominator tree +void RangeCheckEliminator::calc_bounds(BlockBegin *block, BlockBegin *loop_header) { + // Ensures a valid loop_header + assert(!loop_header || loop_header->is_set(BlockBegin::linear_scan_loop_header_flag), "Loop header has to be real !"); + + // Tracing output + TRACE_RANGE_CHECK_ELIMINATION( + tty->fill_to(block->dominator_depth()*2); + tty->print_cr("Block B%d", block->block_id()); + ); + + // Pushed stack for conditions + IntegerStack pushed; + // Process If + BlockBegin *parent = block->dominator(); + if (parent != NULL) { + If *cond = parent->end()->as_If(); + if (cond != NULL) { + process_if(pushed, block, cond); + } + } + + // Interate over current block + InstructionList arrays; + AccessIndexedList accessIndexed; + Instruction *cur = block; + + while (cur) { + // Ensure cur wasn't inserted during the elimination + if (cur->id() < this->_bounds.length()) { + // Process only if it is an access indexed instruction + AccessIndexed *ai = cur->as_AccessIndexed(); + if (ai != NULL) { + process_access_indexed(loop_header, block, ai); + accessIndexed.append(ai); + if (!arrays.contains(ai->array())) { + arrays.append(ai->array()); + } + Bound *b = get_bound(ai->index()); + if (!b->lower_instr()) { + // Lower bound is constant + update_bound(pushed, ai->index(), Instruction::geq, NULL, 0); + } + if (!b->has_upper()) { + if (ai->length() && ai->length()->type()->as_IntConstant()) { + int value = ai->length()->type()->as_IntConstant()->value(); + update_bound(pushed, ai->index(), Instruction::lss, NULL, value); + } else { + // Has no upper bound + Instruction *instr = ai->length(); + if (instr != NULL) instr = ai->array(); + update_bound(pushed, ai->index(), Instruction::lss, instr, 0); + } + } + } + } + cur = cur->next(); + } + + // Output current condition stack + TRACE_RANGE_CHECK_ELIMINATION(dump_condition_stack(block)); + + // Do in block motion of range checks + in_block_motion(block, accessIndexed, arrays); + + // Call all dominated blocks + for (int i=0; idominates()->length(); i++) { + BlockBegin *next = block->dominates()->at(i); + if (!next->is_set(BlockBegin::donot_eliminate_range_checks)) { + // if current block is a loop header and: + // - next block belongs to the same loop + // or + // - next block belongs to an inner loop + // then current block is the loop header for next block + if (block->is_set(BlockBegin::linear_scan_loop_header_flag) && (block->loop_index() == next->loop_index() || next->loop_depth() > block->loop_depth())) { + calc_bounds(next, block); + } else { + calc_bounds(next, loop_header); + } + } + } + + // Reset stack + for (int i=0; ipop(); + } +} + +#ifndef PRODUCT +// Dump condition stack +void RangeCheckEliminator::dump_condition_stack(BlockBegin *block) { + for (int i=0; i<_ir->linear_scan_order()->length(); i++) { + BlockBegin *cur_block = _ir->linear_scan_order()->at(i); + Instruction *instr = cur_block; + for_each_phi_fun(cur_block, phi, + BoundStack *bound_stack = _bounds.at(phi->id()); + if (bound_stack && bound_stack->length() > 0) { + Bound *bound = bound_stack->top(); + if ((bound->has_lower() || bound->has_upper()) && (bound->lower_instr() != phi || bound->upper_instr() != phi || bound->lower() != 0 || bound->upper() != 0)) { + TRACE_RANGE_CHECK_ELIMINATION(tty->fill_to(2*block->dominator_depth()); + tty->print("i%d", phi->id()); + tty->print(": "); + bound->print(); + tty->print_cr(""); + ); + } + }); + + while (!instr->as_BlockEnd()) { + if (instr->id() < _bounds.length()) { + BoundStack *bound_stack = _bounds.at(instr->id()); + if (bound_stack && bound_stack->length() > 0) { + Bound *bound = bound_stack->top(); + if ((bound->has_lower() || bound->has_upper()) && (bound->lower_instr() != instr || bound->upper_instr() != instr || bound->lower() != 0 || bound->upper() != 0)) { + TRACE_RANGE_CHECK_ELIMINATION(tty->fill_to(2*block->dominator_depth()); + tty->print("i%d", instr->id()); + tty->print(": "); + bound->print(); + tty->print_cr(""); + ); + } + } + } + instr = instr->next(); + } + } +} +#endif + +// Verification or the IR +RangeCheckEliminator::Verification::Verification(IR *ir) : _used(BlockBegin::number_of_blocks(), false) { + this->_ir = ir; + ir->iterate_linear_scan_order(this); +} + +// Verify this block +void RangeCheckEliminator::Verification::block_do(BlockBegin *block) { + If *cond = block->end()->as_If(); + // Watch out: tsux and fsux can be the same! + if (block->number_of_sux() > 1) { + for (int i=0; inumber_of_sux(); i++) { + BlockBegin *sux = block->sux_at(i); + BlockBegin *pred = NULL; + for (int j=0; jnumber_of_preds(); j++) { + BlockBegin *cur = sux->pred_at(j); + assert(cur != NULL, "Predecessor must not be null"); + if (!pred) { + pred = cur; + } + assert(cur == pred, "Block must not have more than one predecessor if its predecessor has more than one successor"); + } + assert(sux->number_of_preds() >= 1, "Block must have at least one predecessor"); + assert(sux->pred_at(0) == block, "Wrong successor"); + } + } + + BlockBegin *dominator = block->dominator(); + if (dominator) { + assert(block != _ir->start(), "Start block must not have a dominator!"); + assert(can_reach(dominator, block), "Dominator can't reach his block !"); + assert(can_reach(_ir->start(), dominator), "Dominator is unreachable !"); + assert(!can_reach(_ir->start(), block, dominator), "Wrong dominator ! Block can be reached anyway !"); + BlockList *all_blocks = _ir->linear_scan_order(); + for (int i=0; ilength(); i++) { + BlockBegin *cur = all_blocks->at(i); + if (cur != dominator && cur != block) { + assert(can_reach(dominator, block, cur), "There has to be another dominator!"); + } + } + } else { + assert(block == _ir->start(), "Only start block must not have a dominator"); + } + + if (block->is_set(BlockBegin::linear_scan_loop_header_flag)) { + int loop_index = block->loop_index(); + BlockList *all_blocks = _ir->linear_scan_order(); + assert(block->number_of_preds() >= 1, "Block must have at least one predecessor"); + assert(!block->is_set(BlockBegin::exception_entry_flag), "Loop header must not be exception handler!"); + // Sometimes, the backbranch comes from an exception handler. In + // this case, loop indexes/loop depths may not appear correct. + bool loop_through_xhandler = false; + for (int i = 0; i < block->number_of_exception_handlers(); i++) { + BlockBegin *xhandler = block->exception_handler_at(i); + for (int j = 0; j < block->number_of_preds(); j++) { + if (dominates(xhandler, block->pred_at(j)) || xhandler == block->pred_at(j)) { + loop_through_xhandler = true; + } + } + } + + for (int i=0; inumber_of_sux(); i++) { + BlockBegin *sux = block->sux_at(i); + assert(sux->loop_depth() != block->loop_depth() || sux->loop_index() == block->loop_index() || loop_through_xhandler, "Loop index has to be same"); + assert(sux->loop_depth() == block->loop_depth() || sux->loop_index() != block->loop_index(), "Loop index has to be different"); + } + + for (int i=0; ilength(); i++) { + BlockBegin *cur = all_blocks->at(i); + if (cur->loop_index() == loop_index && cur != block) { + assert(dominates(block->dominator(), cur), "Dominator of loop header must dominate all loop blocks"); + } + } + } + + Instruction *cur = block; + while (cur) { + assert(cur->block() == block, "Block begin has to be set correctly!"); + cur = cur->next(); + } +} + +// Loop header must dominate all loop blocks +bool RangeCheckEliminator::Verification::dominates(BlockBegin *dominator, BlockBegin *block) { + BlockBegin *cur = block->dominator(); + while (cur && cur != dominator) { + cur = cur->dominator(); + } + return cur == dominator; +} + +// Try to reach Block end beginning in Block start and not using Block dont_use +bool RangeCheckEliminator::Verification::can_reach(BlockBegin *start, BlockBegin *end, BlockBegin *dont_use /* = NULL */) { + if (start == end) return start != dont_use; + // Simple BSF from start to end + // BlockBeginList _current; + for (int i=0; i<_used.length(); i++) { + _used[i] = false; + } + _current.truncate(0); + _successors.truncate(0); + if (start != dont_use) { + _current.push(start); + _used[start->block_id()] = true; + } + + // BlockBeginList _successors; + while (_current.length() > 0) { + BlockBegin *cur = _current.pop(); + // Add exception handlers to list + for (int i=0; inumber_of_exception_handlers(); i++) { + BlockBegin *xhandler = cur->exception_handler_at(i); + _successors.push(xhandler); + // Add exception handlers of _successors to list + for (int j=0; jnumber_of_exception_handlers(); j++) { + BlockBegin *sux_xhandler = xhandler->exception_handler_at(j); + _successors.push(sux_xhandler); + } + } + // Add normal _successors to list + for (int i=0; inumber_of_sux(); i++) { + BlockBegin *sux = cur->sux_at(i); + _successors.push(sux); + // Add exception handlers of _successors to list + for (int j=0; jnumber_of_exception_handlers(); j++) { + BlockBegin *xhandler = sux->exception_handler_at(j); + _successors.push(xhandler); + } + } + for (int i=0; i<_successors.length(); i++) { + BlockBegin *sux = _successors[i]; + assert(sux != NULL, "Successor must not be NULL!"); + if (sux == end) { + return true; + } + if (sux != dont_use && !_used[sux->block_id()]) { + _used[sux->block_id()] = true; + _current.push(sux); + } + } + _successors.truncate(0); + } + + return false; +} + +// Bound +RangeCheckEliminator::Bound::~Bound() { +} + +// Bound constructor +RangeCheckEliminator::Bound::Bound() { + init(); + this->_lower = min_jint; + this->_upper = max_jint; + this->_lower_instr = NULL; + this->_upper_instr = NULL; +} + +// Bound constructor +RangeCheckEliminator::Bound::Bound(int lower, Value lower_instr, int upper, Value upper_instr) { + init(); + assert(!lower_instr || !lower_instr->as_Constant() || !lower_instr->type()->as_IntConstant(), "Must not be constant!"); + assert(!upper_instr || !upper_instr->as_Constant() || !upper_instr->type()->as_IntConstant(), "Must not be constant!"); + this->_lower = lower; + this->_upper = upper; + this->_lower_instr = lower_instr; + this->_upper_instr = upper_instr; +} + +// Bound constructor +RangeCheckEliminator::Bound::Bound(Instruction::Condition cond, Value v, int constant) { + assert(!v || (v->type() && (v->type()->as_IntType() || v->type()->as_ObjectType())), "Type must be array or integer!"); + assert(!v || !v->as_Constant() || !v->type()->as_IntConstant(), "Must not be constant!"); + + init(); + if (cond == Instruction::eql) { + _lower = constant; + _lower_instr = v; + _upper = constant; + _upper_instr = v; + } else if (cond == Instruction::neq) { + _lower = min_jint; + _upper = max_jint; + _lower_instr = NULL; + _upper_instr = NULL; + if (v == NULL) { + if (constant == min_jint) { + _lower++; + } + if (constant == max_jint) { + _upper--; + } + } + } else if (cond == Instruction::geq) { + _lower = constant; + _lower_instr = v; + _upper = max_jint; + _upper_instr = NULL; + } else if (cond == Instruction::leq) { + _lower = min_jint; + _lower_instr = NULL; + _upper = constant; + _upper_instr = v; + } else { + ShouldNotReachHere(); + } +} + +// Set lower +void RangeCheckEliminator::Bound::set_lower(int value, Value v) { + assert(!v || !v->as_Constant() || !v->type()->as_IntConstant(), "Must not be constant!"); + this->_lower = value; + this->_lower_instr = v; +} + +// Set upper +void RangeCheckEliminator::Bound::set_upper(int value, Value v) { + assert(!v || !v->as_Constant() || !v->type()->as_IntConstant(), "Must not be constant!"); + this->_upper = value; + this->_upper_instr = v; +} + +// Add constant -> no overflow may occur +void RangeCheckEliminator::Bound::add_constant(int value) { + this->_lower += value; + this->_upper += value; +} + +// Init +void RangeCheckEliminator::Bound::init() { +} + +// or +void RangeCheckEliminator::Bound::or_op(Bound *b) { + // Watch out, bound is not guaranteed not to overflow! + // Update lower bound + if (_lower_instr != b->_lower_instr || (_lower_instr && _lower != b->_lower)) { + _lower_instr = NULL; + _lower = min_jint; + } else { + _lower = MIN2(_lower, b->_lower); + } + // Update upper bound + if (_upper_instr != b->_upper_instr || (_upper_instr && _upper != b->_upper)) { + _upper_instr = NULL; + _upper = max_jint; + } else { + _upper = MAX2(_upper, b->_upper); + } +} + +// and +void RangeCheckEliminator::Bound::and_op(Bound *b) { + // Update lower bound + if (_lower_instr == b->_lower_instr) { + _lower = MAX2(_lower, b->_lower); + } + if (b->has_lower()) { + bool set = true; + if (_lower_instr != NULL && b->_lower_instr != NULL) { + set = (_lower_instr->dominator_depth() > b->_lower_instr->dominator_depth()); + } + if (set) { + _lower = b->_lower; + _lower_instr = b->_lower_instr; + } + } + // Update upper bound + if (_upper_instr == b->_upper_instr) { + _upper = MIN2(_upper, b->_upper); + } + if (b->has_upper()) { + bool set = true; + if (_upper_instr != NULL && b->_upper_instr != NULL) { + set = (_upper_instr->dominator_depth() > b->_upper_instr->dominator_depth()); + } + if (set) { + _upper = b->_upper; + _upper_instr = b->_upper_instr; + } + } +} + +// has_upper +bool RangeCheckEliminator::Bound::has_upper() { + return _upper_instr != NULL || _upper < max_jint; +} + +// is_smaller +bool RangeCheckEliminator::Bound::is_smaller(Bound *b) { + if (b->_lower_instr != _upper_instr) { + return false; + } + return _upper < b->_lower; +} + +// has_lower +bool RangeCheckEliminator::Bound::has_lower() { + return _lower_instr != NULL || _lower > min_jint; +} + +// in_array_bound +bool RangeCheckEliminator::in_array_bound(Bound *bound, Value array){ + if (!bound) return false; + assert(array != NULL, "Must not be null!"); + assert(bound != NULL, "Must not be null!"); + if (bound->lower() >=0 && bound->lower_instr() == NULL && bound->upper() < 0 && bound->upper_instr() != NULL) { + ArrayLength *len = bound->upper_instr()->as_ArrayLength(); + if (bound->upper_instr() == array || (len != NULL && len->array() == array)) { + return true; + } + } + return false; +} + +// remove_lower +void RangeCheckEliminator::Bound::remove_lower() { + _lower = min_jint; + _lower_instr = NULL; +} + +// remove_upper +void RangeCheckEliminator::Bound::remove_upper() { + _upper = max_jint; + _upper_instr = NULL; +} + +// upper +int RangeCheckEliminator::Bound::upper() { + return _upper; +} + +// lower +int RangeCheckEliminator::Bound::lower() { + return _lower; +} + +// upper_instr +Value RangeCheckEliminator::Bound::upper_instr() { + return _upper_instr; +} + +// lower_instr +Value RangeCheckEliminator::Bound::lower_instr() { + return _lower_instr; +} + +// print +void RangeCheckEliminator::Bound::print() { + tty->print(""); + if (this->_lower_instr || this->_lower != min_jint) { + if (this->_lower_instr) { + tty->print("i%d", this->_lower_instr->id()); + if (this->_lower > 0) { + tty->print("+%d", _lower); + } + if (this->_lower < 0) { + tty->print("%d", _lower); + } + } else { + tty->print("%d", _lower); + } + tty->print(" <= "); + } + tty->print("x"); + if (this->_upper_instr || this->_upper != max_jint) { + tty->print(" <= "); + if (this->_upper_instr) { + tty->print("i%d", this->_upper_instr->id()); + if (this->_upper > 0) { + tty->print("+%d", _upper); + } + if (this->_upper < 0) { + tty->print("%d", _upper); + } + } else { + tty->print("%d", _upper); + } + } +} + +// Copy +RangeCheckEliminator::Bound *RangeCheckEliminator::Bound::copy() { + Bound *b = new Bound(); + b->_lower = _lower; + b->_lower_instr = _lower_instr; + b->_upper = _upper; + b->_upper_instr = _upper_instr; + return b; +} + +#ifdef ASSERT +// Add assertion +void RangeCheckEliminator::Bound::add_assertion(Instruction *instruction, Instruction *position, int i, Value instr, Instruction::Condition cond) { + Instruction *result = position; + Instruction *compare_with = NULL; + ValueStack *state = position->state_before(); + if (position->as_BlockEnd() && !position->as_Goto()) { + state = position->as_BlockEnd()->state_before(); + } + Instruction *instruction_before = position->prev(); + if (position->as_Return() && Compilation::current()->method()->is_synchronized() && instruction_before->as_MonitorExit()) { + instruction_before = instruction_before->prev(); + } + result = instruction_before; + // Load constant only if needed + Constant *constant = NULL; + if (i != 0 || !instr) { + constant = new Constant(new IntConstant(i)); + NOT_PRODUCT(constant->set_printable_bci(position->printable_bci())); + result = result->insert_after(constant); + compare_with = constant; + } + + if (instr) { + assert(instr->type()->as_ObjectType() || instr->type()->as_IntType(), "Type must be array or integer!"); + compare_with = instr; + // Load array length if necessary + Instruction *op = instr; + if (instr->type()->as_ObjectType()) { + assert(state, "must not be null"); + ArrayLength *length = new ArrayLength(instr, state->copy()); + NOT_PRODUCT(length->set_printable_bci(position->printable_bci())); + length->set_exception_state(length->state_before()); + result = result->insert_after(length); + op = length; + compare_with = length; + } + // Add operation only if necessary + if (constant) { + ArithmeticOp *ao = new ArithmeticOp(Bytecodes::_iadd, constant, op, false, NULL); + NOT_PRODUCT(ao->set_printable_bci(position->printable_bci())); + result = result->insert_after(ao); + compare_with = ao; + // TODO: Check that add operation does not overflow! + } + } + assert(compare_with != NULL, "You have to compare with something!"); + assert(instruction != NULL, "Instruction must not be null!"); + + if (instruction->type()->as_ObjectType()) { + // Load array length if necessary + Instruction *op = instruction; + assert(state, "must not be null"); + ArrayLength *length = new ArrayLength(instruction, state->copy()); + length->set_exception_state(length->state_before()); + NOT_PRODUCT(length->set_printable_bci(position->printable_bci())); + result = result->insert_after(length); + instruction = length; + } + + Assert *assert = new Assert(instruction, cond, false, compare_with); + NOT_PRODUCT(assert->set_printable_bci(position->printable_bci())); + result->insert_after(assert); +} + +// Add assertions +void RangeCheckEliminator::add_assertions(Bound *bound, Instruction *instruction, Instruction *position) { + // Add lower bound assertion + if (bound->has_lower()) { + bound->add_assertion(instruction, position, bound->lower(), bound->lower_instr(), Instruction::geq); + } + // Add upper bound assertion + if (bound->has_upper()) { + bound->add_assertion(instruction, position, bound->upper(), bound->upper_instr(), Instruction::leq); + } +} +#endif + diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_RangeCheckElimination.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/c1/c1_RangeCheckElimination.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2012, 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. + * + */ + +#ifndef SHARE_VM_C1_C1_RANGECHECKELIMINATION_HPP +#define SHARE_VM_C1_C1_RANGECHECKELIMINATION_HPP + +#include "c1/c1_Instruction.hpp" + +// Base class for range check elimination +class RangeCheckElimination : AllStatic { +public: + static void eliminate(IR *ir); +}; + +// Implementation +class RangeCheckEliminator VALUE_OBJ_CLASS_SPEC { +private: + int _number_of_instructions; + bool _optimistic; // Insert predicates and deoptimize when they fail + IR *_ir; + + define_array(BlockBeginArray, BlockBegin*) + define_stack(BlockBeginList, BlockBeginArray) + define_stack(IntegerStack, intArray) + define_array(IntegerMap, IntegerStack*) + + class Verification : public _ValueObj /*VALUE_OBJ_CLASS_SPEC*/, public BlockClosure { + private: + IR *_ir; + boolArray _used; + BlockBeginList _current; + BlockBeginList _successors; + + public: + Verification(IR *ir); + virtual void block_do(BlockBegin *block); + bool can_reach(BlockBegin *start, BlockBegin *end, BlockBegin *dont_use = NULL); + bool dominates(BlockBegin *dominator, BlockBegin *block); + }; + +public: + // Bounds for an instruction in the form x + c which c integer + // constant and x another instruction + class Bound : public CompilationResourceObj { + private: + int _upper; + Value _upper_instr; + int _lower; + Value _lower_instr; + + public: + Bound(); + Bound(Value v); + Bound(Instruction::Condition cond, Value v, int constant = 0); + Bound(int lower, Value lower_instr, int upper, Value upper_instr); + ~Bound(); + +#ifdef ASSERT + void add_assertion(Instruction *instruction, Instruction *position, int i, Value instr, Instruction::Condition cond); +#endif + int upper(); + Value upper_instr(); + int lower(); + Value lower_instr(); + void print(); + bool check_no_overflow(int const_value); + void or_op(Bound *b); + void and_op(Bound *b); + bool has_upper(); + bool has_lower(); + void set_upper(int upper, Value upper_instr); + void set_lower(int lower, Value lower_instr); + bool is_smaller(Bound *b); + void remove_upper(); + void remove_lower(); + void add_constant(int value); + Bound *copy(); + + private: + void init(); + }; + + + class Visitor : public InstructionVisitor { + private: + Bound *_bound; + RangeCheckEliminator *_rce; + + public: + void set_range_check_eliminator(RangeCheckEliminator *rce) { _rce = rce; } + Bound *bound() const { return _bound; } + void clear_bound() { _bound = NULL; } + + protected: + // visitor functions + void do_Constant (Constant* x); + void do_IfOp (IfOp* x); + void do_LogicOp (LogicOp* x); + void do_ArithmeticOp (ArithmeticOp* x); + void do_Phi (Phi* x); + + void do_StoreField (StoreField* x) { /* nothing to do */ }; + void do_StoreIndexed (StoreIndexed* x) { /* nothing to do */ }; + void do_MonitorEnter (MonitorEnter* x) { /* nothing to do */ }; + void do_MonitorExit (MonitorExit* x) { /* nothing to do */ }; + void do_Invoke (Invoke* x) { /* nothing to do */ }; + void do_UnsafePutRaw (UnsafePutRaw* x) { /* nothing to do */ }; + void do_UnsafePutObject(UnsafePutObject* x) { /* nothing to do */ }; + void do_Intrinsic (Intrinsic* x) { /* nothing to do */ }; + void do_Local (Local* x) { /* nothing to do */ }; + void do_LoadField (LoadField* x) { /* nothing to do */ }; + void do_ArrayLength (ArrayLength* x) { /* nothing to do */ }; + void do_LoadIndexed (LoadIndexed* x) { /* nothing to do */ }; + void do_NegateOp (NegateOp* x) { /* nothing to do */ }; + void do_ShiftOp (ShiftOp* x) { /* nothing to do */ }; + void do_CompareOp (CompareOp* x) { /* nothing to do */ }; + void do_Convert (Convert* x) { /* nothing to do */ }; + void do_NullCheck (NullCheck* x) { /* nothing to do */ }; + void do_TypeCast (TypeCast* x) { /* nothing to do */ }; + void do_NewInstance (NewInstance* x) { /* nothing to do */ }; + void do_NewTypeArray (NewTypeArray* x) { /* nothing to do */ }; + void do_NewObjectArray (NewObjectArray* x) { /* nothing to do */ }; + void do_NewMultiArray (NewMultiArray* x) { /* nothing to do */ }; + void do_CheckCast (CheckCast* x) { /* nothing to do */ }; + void do_InstanceOf (InstanceOf* x) { /* nothing to do */ }; + void do_BlockBegin (BlockBegin* x) { /* nothing to do */ }; + void do_Goto (Goto* x) { /* nothing to do */ }; + void do_If (If* x) { /* nothing to do */ }; + void do_IfInstanceOf (IfInstanceOf* x) { /* nothing to do */ }; + void do_TableSwitch (TableSwitch* x) { /* nothing to do */ }; + void do_LookupSwitch (LookupSwitch* x) { /* nothing to do */ }; + void do_Return (Return* x) { /* nothing to do */ }; + void do_Throw (Throw* x) { /* nothing to do */ }; + void do_Base (Base* x) { /* nothing to do */ }; + void do_OsrEntry (OsrEntry* x) { /* nothing to do */ }; + void do_ExceptionObject(ExceptionObject* x) { /* nothing to do */ }; + void do_RoundFP (RoundFP* x) { /* nothing to do */ }; + void do_UnsafeGetRaw (UnsafeGetRaw* x) { /* nothing to do */ }; + void do_UnsafeGetObject(UnsafeGetObject* x) { /* nothing to do */ }; + void do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) { /* nothing to do */ }; + void do_UnsafePrefetchRead (UnsafePrefetchRead* x) { /* nothing to do */ }; + void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ }; + void do_ProfileCall (ProfileCall* x) { /* nothing to do */ }; + void do_ProfileInvoke (ProfileInvoke* x) { /* nothing to do */ }; + void do_RuntimeCall (RuntimeCall* x) { /* nothing to do */ }; + void do_MemBar (MemBar* x) { /* nothing to do */ }; + void do_RangeCheckPredicate(RangeCheckPredicate* x) { /* nothing to do */ }; + void do_Assert (Assert* x) { /* nothing to do */ }; + }; + +#ifdef ASSERT + void add_assertions(Bound *bound, Instruction *instruction, Instruction *position); +#endif + + define_array(BoundArray, Bound *) + define_stack(BoundStack, BoundArray) + define_array(BoundMap, BoundStack *) + define_array(AccessIndexedArray, AccessIndexed *) + define_stack(AccessIndexedList, AccessIndexedArray) + define_array(InstructionArray, Instruction *) + define_stack(InstructionList, InstructionArray) + + class AccessIndexedInfo : public CompilationResourceObj { + public: + AccessIndexedList *_list; + int _min; + int _max; + }; + + define_array(AccessIndexedInfoArray, AccessIndexedInfo *) + BoundMap _bounds; // Mapping from Instruction's id to current bound + AccessIndexedInfoArray _access_indexed_info; // Mapping from Instruction's id to AccessIndexedInfo for in block motion + Visitor _visitor; + +public: + RangeCheckEliminator(IR *ir); + + IR *ir() const { return _ir; } + + // Pass over the dominator tree to identify blocks where there's an oppportunity for optimization + bool set_process_block_flags(BlockBegin *block); + // The core of the optimization work: pass over the dominator tree + // to propagate bound information, insert predicate out of loops, + // eliminate bound checks when possible and perform in block motion + void calc_bounds(BlockBegin *block, BlockBegin *loop_header); + // reorder bound checks within a block in order to eliminate some of them + void in_block_motion(BlockBegin *block, AccessIndexedList &accessIndexed, InstructionList &arrays); + + // update/access current bound + void update_bound(IntegerStack &pushed, Value v, Instruction::Condition cond, Value value, int constant); + void update_bound(IntegerStack &pushed, Value v, Bound *bound); + Bound *get_bound(Value v); + + bool loop_invariant(BlockBegin *loop_header, Instruction *instruction); // check for loop invariance + void add_access_indexed_info(InstructionList &indices, int i, Value instruction, AccessIndexed *ai); // record indexed access for in block motion + void remove_range_check(AccessIndexed *ai); // Mark this instructions as not needing a range check + void add_if_condition(IntegerStack &pushed, Value x, Value y, Instruction::Condition condition); // Update bound for an If + bool in_array_bound(Bound *bound, Value array); // Check whether bound is known to fall within array + + // helper functions to work with predicates + Instruction* insert_after(Instruction* insert_position, Instruction* instr, int bci); + Instruction* predicate(Instruction* left, Instruction::Condition cond, Instruction* right, ValueStack* state, Instruction *insert_position, int bci=-1); + Instruction* predicate_cmp_with_const(Instruction* instr, Instruction::Condition cond, int constant, ValueStack* state, Instruction *insert_position, int bci=1); + Instruction* predicate_add(Instruction* left, int left_const, Instruction::Condition cond, Instruction* right, ValueStack* state, Instruction *insert_position, int bci=-1); + Instruction* predicate_add_cmp_with_const(Instruction* left, int left_const, Instruction::Condition cond, int constant, ValueStack* state, Instruction *insert_position, int bci=-1); + + void insert_deoptimization(ValueStack *state, Instruction *insert_position, Instruction *array_instr, // Add predicate + Instruction *length_instruction, Instruction *lower_instr, int lower, + Instruction *upper_instr, int upper, AccessIndexed *ai); + bool is_ok_for_deoptimization(Instruction *insert_position, Instruction *array_instr, // Can we safely add a predicate? + Instruction *length_instr, Instruction *lower_instr, + int lower, Instruction *upper_instr, int upper); + void process_if(IntegerStack &pushed, BlockBegin *block, If *cond); // process If Instruction + void process_access_indexed(BlockBegin *loop_header, BlockBegin *block, AccessIndexed *ai); // process indexed access + + void dump_condition_stack(BlockBegin *cur_block); + static void print_statistics(); +}; + +#endif // SHARE_VM_C1_C1_RANGECHECKELIMINATION_HPP diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_Runtime1.cpp --- a/src/share/vm/c1/c1_Runtime1.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_Runtime1.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -1330,6 +1330,50 @@ return (k != NULL && obj != NULL && obj->is_a(k)) ? 1 : 0; JRT_END +JRT_ENTRY(void, Runtime1::predicate_failed_trap(JavaThread* thread)) + ResourceMark rm; + + assert(!TieredCompilation, "incompatible with tiered compilation"); + + RegisterMap reg_map(thread, false); + frame runtime_frame = thread->last_frame(); + frame caller_frame = runtime_frame.sender(®_map); + + nmethod* nm = CodeCache::find_nmethod(caller_frame.pc()); + assert (nm != NULL, "no more nmethod?"); + nm->make_not_entrant(); + + methodHandle m(nm->method()); + MethodData* mdo = m->method_data(); + + if (mdo == NULL && !HAS_PENDING_EXCEPTION) { + // Build an MDO. Ignore errors like OutOfMemory; + // that simply means we won't have an MDO to update. + Method::build_interpreter_method_data(m, THREAD); + if (HAS_PENDING_EXCEPTION) { + assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOM error here"); + CLEAR_PENDING_EXCEPTION; + } + mdo = m->method_data(); + } + + if (mdo != NULL) { + mdo->inc_trap_count(Deoptimization::Reason_none); + } + + if (TracePredicateFailedTraps) { + stringStream ss1, ss2; + vframeStream vfst(thread); + methodHandle inlinee = methodHandle(vfst.method()); + inlinee->print_short_name(&ss1); + m->print_short_name(&ss2); + tty->print_cr("Predicate failed trap in method %s at bci %d inlined in %s at pc %x", ss1.as_string(), vfst.bci(), ss2.as_string(), caller_frame.pc()); + } + + + Deoptimization::deoptimize_frame(thread, caller_frame.id()); + +JRT_END #ifndef PRODUCT void Runtime1::print_statistics() { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_Runtime1.hpp --- a/src/share/vm/c1/c1_Runtime1.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_Runtime1.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -71,6 +71,7 @@ stub(g1_post_barrier_slow) \ stub(fpu2long_stub) \ stub(counter_overflow) \ + stub(predicate_failed_trap) \ last_entry(number_of_ids) #define DECLARE_STUB_ID(x) x ## _id , @@ -190,6 +191,8 @@ static void oop_arraycopy(HeapWord* src, HeapWord* dst, int length); static int is_instance_of(oopDesc* mirror, oopDesc* obj); + static void predicate_failed_trap(JavaThread* thread); + static void print_statistics() PRODUCT_RETURN; }; diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_ValueMap.cpp --- a/src/share/vm/c1/c1_ValueMap.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_ValueMap.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -26,9 +26,9 @@ #include "c1/c1_Canonicalizer.hpp" #include "c1/c1_IR.hpp" #include "c1/c1_ValueMap.hpp" +#include "c1/c1_ValueStack.hpp" #include "utilities/bitMap.inline.hpp" - #ifndef PRODUCT int ValueMap::_number_of_finds = 0; @@ -192,10 +192,6 @@ && lf->field()->holder() == field->holder() \ && (all_offsets || lf->field()->offset() == field->offset()); -#define MUST_KILL_EXCEPTION(must_kill, entry, value) \ - assert(entry->nesting() < nesting(), "must not find bigger nesting than current"); \ - bool must_kill = (entry->nesting() == nesting() - 1); - void ValueMap::kill_memory() { GENERIC_KILL_VALUE(MUST_KILL_MEMORY); @@ -209,11 +205,6 @@ GENERIC_KILL_VALUE(MUST_KILL_FIELD); } -void ValueMap::kill_exception() { - GENERIC_KILL_VALUE(MUST_KILL_EXCEPTION); -} - - void ValueMap::kill_map(ValueMap* map) { assert(is_global_value_numbering(), "only for global value numbering"); _killed_values.set_union(&map->_killed_values); @@ -274,6 +265,8 @@ GlobalValueNumbering* _gvn; BlockList _loop_blocks; bool _too_complicated_loop; + bool _has_field_store[T_ARRAY + 1]; + bool _has_indexed_store[T_ARRAY + 1]; // simplified access to methods of GlobalValueNumbering ValueMap* current_map() { return _gvn->current_map(); } @@ -281,8 +274,16 @@ // implementation for abstract methods of ValueNumberingVisitor void kill_memory() { _too_complicated_loop = true; } - void kill_field(ciField* field, bool all_offsets) { current_map()->kill_field(field, all_offsets); }; - void kill_array(ValueType* type) { current_map()->kill_array(type); }; + void kill_field(ciField* field, bool all_offsets) { + current_map()->kill_field(field, all_offsets); + assert(field->type()->basic_type() >= 0 && field->type()->basic_type() <= T_ARRAY, "Invalid type"); + _has_field_store[field->type()->basic_type()] = true; + } + void kill_array(ValueType* type) { + current_map()->kill_array(type); + BasicType basic_type = as_BasicType(type); assert(basic_type >= 0 && basic_type <= T_ARRAY, "Invalid type"); + _has_indexed_store[basic_type] = true; + } public: ShortLoopOptimizer(GlobalValueNumbering* gvn) @@ -290,11 +291,141 @@ , _loop_blocks(ValueMapMaxLoopSize) , _too_complicated_loop(false) { + for (int i=0; i<= T_ARRAY; i++){ + _has_field_store[i] = false; + _has_indexed_store[i] = false; + } + } + + bool has_field_store(BasicType type) { + assert(type >= 0 && type <= T_ARRAY, "Invalid type"); + return _has_field_store[type]; + } + + bool has_indexed_store(BasicType type) { + assert(type >= 0 && type <= T_ARRAY, "Invalid type"); + return _has_indexed_store[type]; } bool process(BlockBegin* loop_header); }; +class LoopInvariantCodeMotion : public StackObj { + private: + GlobalValueNumbering* _gvn; + ShortLoopOptimizer* _short_loop_optimizer; + Instruction* _insertion_point; + ValueStack * _state; + + void set_invariant(Value v) const { _gvn->set_processed(v); } + bool is_invariant(Value v) const { return _gvn->is_processed(v); } + + void process_block(BlockBegin* block); + + public: + LoopInvariantCodeMotion(ShortLoopOptimizer *slo, GlobalValueNumbering* gvn, BlockBegin* loop_header, BlockList* loop_blocks); +}; + +LoopInvariantCodeMotion::LoopInvariantCodeMotion(ShortLoopOptimizer *slo, GlobalValueNumbering* gvn, BlockBegin* loop_header, BlockList* loop_blocks) + : _gvn(gvn), _short_loop_optimizer(slo) { + + TRACE_VALUE_NUMBERING(tty->print_cr("using loop invariant code motion loop_header = %d", loop_header->block_id())); + TRACE_VALUE_NUMBERING(tty->print_cr("** loop invariant code motion for short loop B%d", loop_header->block_id())); + + BlockBegin* insertion_block = loop_header->dominator(); + if (insertion_block->number_of_preds() == 0) { + return; // only the entry block does not have a predecessor + } + + assert(insertion_block->end()->as_Base() == NULL, "cannot insert into entry block"); + _insertion_point = insertion_block->end()->prev(); + + BlockEnd *block_end = insertion_block->end(); + _state = block_end->state_before(); + + if (!_state) { + // If, TableSwitch and LookupSwitch always have state_before when + // loop invariant code motion happens.. + assert(block_end->as_Goto(), "Block has to be goto"); + _state = block_end->state(); + } + + // the loop_blocks are filled by going backward from the loop header, so this processing order is best + assert(loop_blocks->at(0) == loop_header, "loop header must be first loop block"); + process_block(loop_header); + for (int i = loop_blocks->length() - 1; i >= 1; i--) { + process_block(loop_blocks->at(i)); + } +} + +void LoopInvariantCodeMotion::process_block(BlockBegin* block) { + TRACE_VALUE_NUMBERING(tty->print_cr("processing block B%d", block->block_id())); + + Instruction* prev = block; + Instruction* cur = block->next(); + + while (cur != NULL) { + + // determine if cur instruction is loop invariant + // only selected instruction types are processed here + bool cur_invariant = false; + + if (cur->as_Constant() != NULL) { + cur_invariant = !cur->can_trap(); + } else if (cur->as_ArithmeticOp() != NULL || cur->as_LogicOp() != NULL || cur->as_ShiftOp() != NULL) { + assert(cur->as_Op2() != NULL, "must be Op2"); + Op2* op2 = (Op2*)cur; + cur_invariant = !op2->can_trap() && is_invariant(op2->x()) && is_invariant(op2->y()); + } else if (cur->as_LoadField() != NULL) { + LoadField* lf = (LoadField*)cur; + // deoptimizes on NullPointerException + cur_invariant = !lf->needs_patching() && !lf->field()->is_volatile() && !_short_loop_optimizer->has_field_store(lf->field()->type()->basic_type()) && is_invariant(lf->obj()); + } else if (cur->as_ArrayLength() != NULL) { + ArrayLength *length = cur->as_ArrayLength(); + cur_invariant = is_invariant(length->array()); + } else if (cur->as_LoadIndexed() != NULL) { + LoadIndexed *li = (LoadIndexed *)cur->as_LoadIndexed(); + cur_invariant = !_short_loop_optimizer->has_indexed_store(as_BasicType(cur->type())) && is_invariant(li->array()) && is_invariant(li->index()); + } + + if (cur_invariant) { + // perform value numbering and mark instruction as loop-invariant + _gvn->substitute(cur); + + if (cur->as_Constant() == NULL) { + // ensure that code for non-constant instructions is always generated + cur->pin(); + } + + // remove cur instruction from loop block and append it to block before loop + Instruction* next = cur->next(); + Instruction* in = _insertion_point->next(); + _insertion_point = _insertion_point->set_next(cur); + cur->set_next(in); + + // Deoptimize on exception + cur->set_flag(Instruction::DeoptimizeOnException, true); + + // Clear exception handlers + cur->set_exception_handlers(NULL); + + TRACE_VALUE_NUMBERING(tty->print_cr("Instruction %c%d is loop invariant", cur->type()->tchar(), cur->id())); + + if (cur->state_before() != NULL) { + cur->set_state_before(_state->copy()); + } + if (cur->exception_state() != NULL) { + cur->set_exception_state(_state->copy()); + } + + cur = prev->set_next(next); + + } else { + prev = cur; + cur = cur->next(); + } + } +} bool ShortLoopOptimizer::process(BlockBegin* loop_header) { TRACE_VALUE_NUMBERING(tty->print_cr("** loop header block")); @@ -316,6 +447,10 @@ for (int j = block->number_of_preds() - 1; j >= 0; j--) { BlockBegin* pred = block->pred_at(j); + if (pred->is_set(BlockBegin::osr_entry_flag)) { + return false; + } + ValueMap* pred_map = value_map_of(pred); if (pred_map != NULL) { current_map()->kill_map(pred_map); @@ -336,6 +471,12 @@ } } + bool optimistic = this->_gvn->compilation()->is_optimistic(); + + if (UseLoopInvariantCodeMotion && optimistic) { + LoopInvariantCodeMotion code_motion(this, _gvn, loop_header, &_loop_blocks); + } + TRACE_VALUE_NUMBERING(tty->print_cr("** loop successfully optimized")); return true; } @@ -344,11 +485,11 @@ GlobalValueNumbering::GlobalValueNumbering(IR* ir) : _current_map(NULL) , _value_maps(ir->linear_scan_order()->length(), NULL) + , _compilation(ir->compilation()) { TRACE_VALUE_NUMBERING(tty->print_cr("****** start of global value numbering")); ShortLoopOptimizer short_loop_optimizer(this); - int subst_count = 0; BlockList* blocks = ir->linear_scan_order(); int num_blocks = blocks->length(); @@ -357,6 +498,12 @@ assert(start_block == ir->start() && start_block->number_of_preds() == 0 && start_block->dominator() == NULL, "must be start block"); assert(start_block->next()->as_Base() != NULL && start_block->next()->next() == NULL, "start block must not have instructions"); + // method parameters are not linked in instructions list, so process them separateley + for_each_state_value(start_block->state(), value, + assert(value->as_Local() != NULL, "only method parameters allowed"); + set_processed(value); + ); + // initial, empty value map with nesting 0 set_value_map_of(start_block, new ValueMap()); @@ -374,7 +521,7 @@ // create new value map with increased nesting _current_map = new ValueMap(value_map_of(dominator)); - if (num_preds == 1) { + if (num_preds == 1 && !block->is_set(BlockBegin::exception_entry_flag)) { assert(dominator == block->pred_at(0), "dominator must be equal to predecessor"); // nothing to do here @@ -403,36 +550,41 @@ } } - if (block->is_set(BlockBegin::exception_entry_flag)) { - current_map()->kill_exception(); - } + // phi functions are not linked in instructions list, so process them separateley + for_each_phi_fun(block, phi, + set_processed(phi); + ); TRACE_VALUE_NUMBERING(tty->print("value map before processing block: "); current_map()->print()); // visit all instructions of this block for (Value instr = block->next(); instr != NULL; instr = instr->next()) { - assert(!instr->has_subst(), "substitution already set"); - // check if instruction kills any values instr->visit(this); - - if (instr->hash() != 0) { - Value f = current_map()->find_insert(instr); - if (f != instr) { - assert(!f->has_subst(), "can't have a substitution"); - instr->set_subst(f); - subst_count++; - } - } + // perform actual value numbering + substitute(instr); } // remember value map for successors set_value_map_of(block, current_map()); } - if (subst_count != 0) { + if (_has_substitutions) { SubstitutionResolver resolver(ir); } TRACE_VALUE_NUMBERING(tty->print("****** end of global value numbering. "); ValueMap::print_statistics()); } + +void GlobalValueNumbering::substitute(Instruction* instr) { + assert(!instr->has_subst(), "substitution already set"); + Value subst = current_map()->find_insert(instr); + if (subst != instr) { + assert(!subst->has_subst(), "can't have a substitution"); + + TRACE_VALUE_NUMBERING(tty->print_cr("substitution for %d set to %d", instr->id(), subst->id())); + instr->set_subst(subst); + _has_substitutions = true; + } + set_processed(instr); +} diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_ValueMap.hpp --- a/src/share/vm/c1/c1_ValueMap.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_ValueMap.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -206,6 +206,8 @@ void do_ProfileInvoke (ProfileInvoke* x) { /* nothing to do */ }; void do_RuntimeCall (RuntimeCall* x) { /* nothing to do */ }; void do_MemBar (MemBar* x) { /* nothing to do */ }; + void do_RangeCheckPredicate(RangeCheckPredicate* x) { /* nothing to do */ }; + void do_Assert (Assert* x) { /* nothing to do */ }; }; @@ -225,15 +227,22 @@ class GlobalValueNumbering: public ValueNumberingVisitor { private: + Compilation* _compilation; // compilation data ValueMap* _current_map; // value map of current block ValueMapArray _value_maps; // list of value maps for all blocks + ValueSet _processed_values; // marker for instructions that were already processed + bool _has_substitutions; // set to true when substitutions must be resolved public: // accessors + Compilation* compilation() const { return _compilation; } ValueMap* current_map() { return _current_map; } ValueMap* value_map_of(BlockBegin* block) { return _value_maps.at(block->linear_scan_number()); } void set_value_map_of(BlockBegin* block, ValueMap* map) { assert(value_map_of(block) == NULL, ""); _value_maps.at_put(block->linear_scan_number(), map); } + bool is_processed(Value v) { return _processed_values.contains(v); } + void set_processed(Value v) { _processed_values.put(v); } + // implementation for abstract methods of ValueNumberingVisitor void kill_memory() { current_map()->kill_memory(); } void kill_field(ciField* field, bool all_offsets) { current_map()->kill_field(field, all_offsets); } @@ -241,6 +250,7 @@ // main entry point that performs global value numbering GlobalValueNumbering(IR* ir); + void substitute(Instruction* instr); // substitute instruction if it is contained in current value map }; #endif // SHARE_VM_C1_C1_VALUEMAP_HPP diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/c1/c1_globals.hpp --- a/src/share/vm/c1/c1_globals.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/c1/c1_globals.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -119,6 +119,24 @@ develop(bool, UseGlobalValueNumbering, true, \ "Use Global Value Numbering (separate phase)") \ \ + product(bool, UseLoopInvariantCodeMotion, true, \ + "Simple loop invariant code motion for short loops during GVN") \ + \ + develop(bool, TracePredicateFailedTraps, false, \ + "trace runtime traps caused by predicate failure") \ + \ + develop(bool, StressLoopInvariantCodeMotion, false, \ + "stress loop invariant code motion") \ + \ + develop(bool, TraceRangeCheckElimination, false, \ + "Trace Range Check Elimination") \ + \ + develop(bool, AssertRangeCheckElimination, false, \ + "Assert Range Check Elimination") \ + \ + develop(bool, StressRangeCheckElimination, false, \ + "stress Range Check Elimination") \ + \ develop(bool, PrintValueNumbering, false, \ "Print Value Numbering") \ \ diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/ci/ciEnv.cpp --- a/src/share/vm/ci/ciEnv.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/ci/ciEnv.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -802,6 +802,7 @@ // require checks to make sure the expected type was found. Given that this // only occurs for clone() the more extensive fix seems like overkill so // instead we simply smear the array type into Object. + guarantee(method_holder != NULL, "no method holder"); if (method_holder->is_instance_klass()) { return method_holder->as_instance_klass(); } else if (method_holder->is_array_klass()) { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/ci/ciMethod.cpp --- a/src/share/vm/ci/ciMethod.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/ci/ciMethod.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -790,6 +790,17 @@ return count; } + +// ------------------------------------------------------------------ +// ciMethod::is_special_get_caller_class_method +// +bool ciMethod::is_ignored_by_security_stack_walk() const { + check_is_loaded(); + VM_ENTRY_MARK; + return get_Method()->is_ignored_by_security_stack_walk(); +} + + // ------------------------------------------------------------------ // invokedynamic support diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/ci/ciMethod.hpp --- a/src/share/vm/ci/ciMethod.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/ci/ciMethod.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -166,8 +166,9 @@ // Code size for inlining decisions. int code_size_for_inlining(); - bool force_inline() { return get_Method()->force_inline(); } - bool dont_inline() { return get_Method()->dont_inline(); } + bool caller_sensitive() { return get_Method()->caller_sensitive(); } + bool force_inline() { return get_Method()->force_inline(); } + bool dont_inline() { return get_Method()->dont_inline(); } int comp_level(); int highest_osr_comp_level(); @@ -264,6 +265,9 @@ int instructions_size(); int scale_count(int count, float prof_factor = 1.); // make MDO count commensurate with IIC + // Stack walking support + bool is_ignored_by_security_stack_walk() const; + // JSR 292 support bool is_method_handle_intrinsic() const; bool is_compiled_lambda_form() const; diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/classfile/classFileParser.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -1735,9 +1735,14 @@ Symbol* name) { vmSymbols::SID sid = vmSymbols::find_sid(name); // Privileged code can use all annotations. Other code silently drops some. - bool privileged = loader_data->is_the_null_class_loader_data() || - loader_data->is_anonymous(); + const bool privileged = loader_data->is_the_null_class_loader_data() || + loader_data->is_ext_class_loader_data() || + loader_data->is_anonymous(); switch (sid) { + case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_reflect_CallerSensitive_signature): + if (_location != _in_method) break; // only allow for methods + if (!privileged) break; // only allow in privileged code + return _method_CallerSensitive; case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_ForceInline_signature): if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code @@ -1775,6 +1780,8 @@ } void ClassFileParser::MethodAnnotationCollector::apply_to(methodHandle m) { + if (has_annotation(_method_CallerSensitive)) + m->set_caller_sensitive(true); if (has_annotation(_method_ForceInline)) m->set_force_inline(true); if (has_annotation(_method_DontInline)) @@ -2196,8 +2203,7 @@ true, // is LVTT CHECK_(nullHandle)); lvtt_cnt++; - } else if (UseSplitVerifier && - _major_version >= Verifier::STACKMAP_ATTRIBUTE_MAJOR_VERSION && + } else if (_major_version >= Verifier::STACKMAP_ATTRIBUTE_MAJOR_VERSION && _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_stack_map_table()) { // Stack map is only needed by the new verifier in JDK1.5. if (parsed_stackmap_attribute) { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/classfile/classFileParser.hpp --- a/src/share/vm/classfile/classFileParser.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/classfile/classFileParser.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -119,6 +119,7 @@ enum Location { _in_field, _in_method, _in_class }; enum ID { _unknown = 0, + _method_CallerSensitive, _method_ForceInline, _method_DontInline, _method_LambdaForm_Compiled, diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/classfile/classLoaderData.cpp --- a/src/share/vm/classfile/classLoaderData.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/classfile/classLoaderData.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -105,6 +105,7 @@ 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 @@ if (k->oop_is_instance()) { f(InstanceKlass::cast(k)); } + assert(k != k->next_link(), "no loops!"); } } @@ -258,6 +260,7 @@ return; } prev = k; + assert(k != k->next_link(), "no loops!"); } ShouldNotReachHere(); // should have found this class!! } @@ -318,6 +321,13 @@ } } +/** + * Returns true if this class loader data is for the extension class loader. + */ +bool ClassLoaderData::is_ext_class_loader_data() const { + return SystemDictionary::is_ext_class_loader(class_loader()); +} + Metaspace* ClassLoaderData::metaspace_non_null() { assert(!DumpSharedSpaces, "wrong metaspace!"); // If the metaspace has not been allocated, create a new one. Might want @@ -439,6 +449,7 @@ 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 +476,7 @@ for (Klass* k = _klasses; k != NULL; k = k->next_link()) { guarantee(k->class_loader_data() == this, "Must be the same"); k->verify(); + assert(k != k->next_link(), "no loops!"); } } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/classfile/classLoaderData.hpp --- a/src/share/vm/classfile/classLoaderData.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/classfile/classLoaderData.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -191,6 +191,7 @@ bool is_the_null_class_loader_data() const { return this == _the_null_class_loader_data; } + bool is_ext_class_loader_data() const; // The Metaspace is created lazily so may be NULL. This // method will allocate a Metaspace if needed. diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/classfile/defaultMethods.cpp --- a/src/share/vm/classfile/defaultMethods.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/classfile/defaultMethods.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -348,7 +348,7 @@ void disqualify_method(Method* method) { int* index = _member_index.get(method); - assert(index != NULL && *index >= 0 && *index < _members.length(), "bad index"); + guarantee(index != NULL && *index >= 0 && *index < _members.length(), "bad index"); _members.at(*index).second = DISQUALIFIED; } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/classfile/javaClasses.hpp --- a/src/share/vm/classfile/javaClasses.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/classfile/javaClasses.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -1050,15 +1050,16 @@ // Relevant integer codes (keep these in synch. with MethodHandleNatives.Constants): enum { - MN_IS_METHOD = 0x00010000, // method (not constructor) - MN_IS_CONSTRUCTOR = 0x00020000, // constructor - MN_IS_FIELD = 0x00040000, // field - MN_IS_TYPE = 0x00080000, // nested type + MN_IS_METHOD = 0x00010000, // method (not constructor) + MN_IS_CONSTRUCTOR = 0x00020000, // constructor + MN_IS_FIELD = 0x00040000, // field + MN_IS_TYPE = 0x00080000, // nested type + MN_CALLER_SENSITIVE = 0x00100000, // @CallerSensitive annotation detected MN_REFERENCE_KIND_SHIFT = 24, // refKind - MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT, + MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT, // The SEARCH_* bits are not for MN.flags but for the matchFlags argument of MHN.getMembers: - MN_SEARCH_SUPERCLASSES = 0x00100000, // walk super classes - MN_SEARCH_INTERFACES = 0x00200000 // walk implemented interfaces + MN_SEARCH_SUPERCLASSES = 0x00100000, // walk super classes + MN_SEARCH_INTERFACES = 0x00200000 // walk implemented interfaces }; // Accessors for code generation: diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/classfile/symbolTable.cpp --- a/src/share/vm/classfile/symbolTable.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/classfile/symbolTable.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -677,9 +677,14 @@ ResourceMark rm; int length; jchar* chars = symbol->as_unicode(length); - unsigned int hashValue = hash_string(chars, length); - int index = the_table()->hash_to_index(hashValue); - return the_table()->lookup(index, chars, length, hashValue); + return lookup(chars, length); +} + + +oop StringTable::lookup(jchar* name, int len) { + unsigned int hash = hash_string(name, len); + int index = the_table()->hash_to_index(hash); + return the_table()->lookup(index, name, len, hash); } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/classfile/symbolTable.hpp --- a/src/share/vm/classfile/symbolTable.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/classfile/symbolTable.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -287,6 +287,7 @@ // Probing static oop lookup(Symbol* symbol); + static oop lookup(jchar* chars, int length); // Interning static oop intern(Symbol* symbol, TRAPS); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/classfile/systemDictionary.cpp --- a/src/share/vm/classfile/systemDictionary.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/classfile/systemDictionary.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -146,6 +146,17 @@ } return false; } + +/** + * Returns true if the passed class loader is the extension class loader. + */ +bool SystemDictionary::is_ext_class_loader(Handle class_loader) { + if (class_loader.is_null()) { + return false; + } + return (class_loader->klass()->name() == vmSymbols::sun_misc_Launcher_ExtClassLoader()); +} + // ---------------------------------------------------------------------------- // Resolving of classes @@ -804,6 +815,47 @@ } } // 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 { + Klass *kk; + { + MutexLocker mu(SystemDictionary_lock, THREAD); + 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 { + // This must be done outside of the SystemDictionary_lock to + // avoid deadlock. + // + // Note that Klass::restore_unshareable_info (called via + // load_instance_class above) is also called outside + // of SystemDictionary_lock. Other threads are blocked from + // loading this class because they are waiting on the + // SystemDictionary_lock until this thread removes + // the placeholder below. + // + // This need to be re-thought when parallel-capable non-boot + // classloaders are supported by CDS (today they're not). + 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 +1192,6 @@ 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 +1252,19 @@ 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 @@ -2151,10 +2211,9 @@ // Make sure all class components (including arrays) in the given // signature will be resolved to the same class in both loaders. // Returns the name of the type that failed a loader constraint check, or -// NULL if no constraint failed. The returned C string needs cleaning up -// with a ResourceMark in the caller. No exception except OOME is thrown. +// NULL if no constraint failed. No exception except OOME is thrown. // Arrays are not added to the loader constraint table, their elements are. -char* SystemDictionary::check_signature_loaders(Symbol* signature, +Symbol* SystemDictionary::check_signature_loaders(Symbol* signature, Handle loader1, Handle loader2, bool is_method, TRAPS) { // Nothing to do if loaders are the same. @@ -2162,14 +2221,12 @@ return NULL; } - ResourceMark rm(THREAD); SignatureStream sig_strm(signature, is_method); while (!sig_strm.is_done()) { if (sig_strm.is_object()) { - Symbol* s = sig_strm.as_symbol(CHECK_NULL); - Symbol* sig = s; + Symbol* sig = sig_strm.as_symbol(CHECK_NULL); if (!add_loader_constraint(sig, loader1, loader2, THREAD)) { - return sig->as_C_string(); + return sig; } } sig_strm.next(); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/classfile/systemDictionary.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -106,6 +106,7 @@ do_klass(ThreadDeath_klass, java_lang_ThreadDeath, Pre ) \ do_klass(Exception_klass, java_lang_Exception, Pre ) \ do_klass(RuntimeException_klass, java_lang_RuntimeException, Pre ) \ + do_klass(SecurityManager_klass, java_lang_SecurityManager, Pre ) \ do_klass(ProtectionDomain_klass, java_security_ProtectionDomain, Pre ) \ do_klass(AccessControlContext_klass, java_security_AccessControlContext, Pre ) \ do_klass(ClassNotFoundException_klass, java_lang_ClassNotFoundException, Pre ) \ @@ -138,13 +139,14 @@ /* NOTE: needed too early in bootstrapping process to have checks based on JDK version */ \ /* Universe::is_gte_jdk14x_version() is not set up by this point. */ \ /* It's okay if this turns out to be NULL in non-1.4 JDKs. */ \ - do_klass(lambda_MagicLambdaImpl_klass, java_lang_invoke_MagicLambdaImpl, Opt ) \ + do_klass(lambda_MagicLambdaImpl_klass, java_lang_invoke_MagicLambdaImpl, Opt ) \ do_klass(reflect_MagicAccessorImpl_klass, sun_reflect_MagicAccessorImpl, Opt ) \ do_klass(reflect_MethodAccessorImpl_klass, sun_reflect_MethodAccessorImpl, Opt_Only_JDK14NewRef) \ do_klass(reflect_ConstructorAccessorImpl_klass, sun_reflect_ConstructorAccessorImpl, Opt_Only_JDK14NewRef) \ do_klass(reflect_DelegatingClassLoader_klass, sun_reflect_DelegatingClassLoader, Opt ) \ do_klass(reflect_ConstantPool_klass, sun_reflect_ConstantPool, Opt_Only_JDK15 ) \ do_klass(reflect_UnsafeStaticFieldAccessorImpl_klass, sun_reflect_UnsafeStaticFieldAccessorImpl, Opt_Only_JDK15 ) \ + do_klass(reflect_CallerSensitive_klass, sun_reflect_CallerSensitive, Opt ) \ \ /* support for dynamic typing; it's OK if these are NULL in earlier JDKs */ \ do_klass(MethodHandle_klass, java_lang_invoke_MethodHandle, Pre_JSR292 ) \ @@ -483,8 +485,8 @@ // Check class loader constraints static bool add_loader_constraint(Symbol* name, Handle loader1, Handle loader2, TRAPS); - static char* check_signature_loaders(Symbol* signature, Handle loader1, - Handle loader2, bool is_method, TRAPS); + static Symbol* check_signature_loaders(Symbol* signature, Handle loader1, + Handle loader2, bool is_method, TRAPS); // JSR 292 // find a java.lang.invoke.MethodHandle.invoke* method for a given signature @@ -621,18 +623,22 @@ 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); static bool is_parallelCapable(Handle class_loader); static bool is_parallelDefine(Handle class_loader); +public: + static bool is_ext_class_loader(Handle class_loader); + +private: static Klass* find_shared_class(Symbol* class_name); // Setup link to hierarchy static void add_to_hierarchy(instanceKlassHandle k, TRAPS); -private: // We pass in the hashtable index so we can calculate it outside of // the SystemDictionary_lock. diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/classfile/verifier.cpp --- a/src/share/vm/classfile/verifier.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/classfile/verifier.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -61,8 +61,9 @@ # include "bytes_ppc.hpp" #endif -#define NOFAILOVER_MAJOR_VERSION 51 -#define STATIC_METHOD_IN_INTERFACE_MAJOR_VERSION 52 +#define NOFAILOVER_MAJOR_VERSION 51 +#define NONZERO_PADDING_BYTES_IN_SWITCH_MAJOR_VERSION 51 +#define STATIC_METHOD_IN_INTERFACE_MAJOR_VERSION 52 // Access to external entry for VerifyClassCodes - old byte code verifier @@ -127,8 +128,7 @@ if (TraceClassInitialization) { tty->print_cr("Start class verification for: %s", klassName); } - if (UseSplitVerifier && - klass->major_version() >= STACKMAP_ATTRIBUTE_MAJOR_VERSION) { + if (klass->major_version() >= STACKMAP_ATTRIBUTE_MAJOR_VERSION) { ClassVerifier split_verifier(klass, THREAD); split_verifier.verify_class(THREAD); exception_name = split_verifier.result(); @@ -2027,16 +2027,19 @@ address bcp = bcs->bcp(); address aligned_bcp = (address) round_to((intptr_t)(bcp + 1), jintSize); - // 4639449 & 4647081: padding bytes must be 0 - u2 padding_offset = 1; - while ((bcp + padding_offset) < aligned_bcp) { - if(*(bcp + padding_offset) != 0) { - verify_error(ErrorContext::bad_code(bci), - "Nonzero padding byte in lookswitch or tableswitch"); - return; + if (_klass->major_version() < NONZERO_PADDING_BYTES_IN_SWITCH_MAJOR_VERSION) { + // 4639449 & 4647081: padding bytes must be 0 + u2 padding_offset = 1; + while ((bcp + padding_offset) < aligned_bcp) { + if(*(bcp + padding_offset) != 0) { + verify_error(ErrorContext::bad_code(bci), + "Nonzero padding byte in lookswitch or tableswitch"); + return; + } + padding_offset++; } - padding_offset++; } + int default_offset = (int) Bytes::get_Java_u4(aligned_bcp); int keys, delta; current_frame->pop_stack( diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/classfile/vmSymbols.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -91,6 +91,7 @@ template(java_lang_StringBuffer, "java/lang/StringBuffer") \ template(java_lang_StringBuilder, "java/lang/StringBuilder") \ template(java_lang_CharSequence, "java/lang/CharSequence") \ + template(java_lang_SecurityManager, "java/lang/SecurityManager") \ template(java_security_AccessControlContext, "java/security/AccessControlContext") \ template(java_security_ProtectionDomain, "java/security/ProtectionDomain") \ template(java_io_OutputStream, "java/io/OutputStream") \ @@ -211,6 +212,8 @@ template(sun_reflect_SerializationConstructorAccessorImpl, "sun/reflect/SerializationConstructorAccessorImpl") \ template(sun_reflect_DelegatingClassLoader, "sun/reflect/DelegatingClassLoader") \ template(sun_reflect_Reflection, "sun/reflect/Reflection") \ + template(sun_reflect_CallerSensitive, "sun/reflect/CallerSensitive") \ + template(sun_reflect_CallerSensitive_signature, "Lsun/reflect/CallerSensitive;") \ template(checkedExceptions_name, "checkedExceptions") \ template(clazz_name, "clazz") \ template(exceptionTypes_name, "exceptionTypes") \ @@ -343,6 +346,7 @@ template(contextClassLoader_name, "contextClassLoader") \ template(inheritedAccessControlContext_name, "inheritedAccessControlContext") \ template(isPrivileged_name, "isPrivileged") \ + template(getClassContext_name, "getClassContext") \ template(wait_name, "wait") \ template(checkPackageAccess_name, "checkPackageAccess") \ template(stackSize_name, "stackSize") \ @@ -463,6 +467,7 @@ template(void_classloader_signature, "()Ljava/lang/ClassLoader;") \ template(void_object_signature, "()Ljava/lang/Object;") \ template(void_class_signature, "()Ljava/lang/Class;") \ + template(void_class_array_signature, "()[Ljava/lang/Class;") \ template(void_string_signature, "()Ljava/lang/String;") \ template(object_array_object_signature, "([Ljava/lang/Object;)Ljava/lang/Object;") \ template(object_object_array_object_signature, "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")\ @@ -705,9 +710,8 @@ do_intrinsic(_getLength, java_lang_reflect_Array, getLength_name, object_int_signature, F_SN) \ do_name( getLength_name, "getLength") \ \ - do_intrinsic(_getCallerClass, sun_reflect_Reflection, getCallerClass_name, getCallerClass_signature, F_SN) \ + do_intrinsic(_getCallerClass, sun_reflect_Reflection, getCallerClass_name, void_class_signature, F_SN) \ do_name( getCallerClass_name, "getCallerClass") \ - do_signature(getCallerClass_signature, "(I)Ljava/lang/Class;") \ \ do_intrinsic(_newArray, java_lang_reflect_Array, newArray_name, newArray_signature, F_SN) \ do_name( newArray_name, "newArray") \ diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/code/codeBlob.cpp --- a/src/share/vm/code/codeBlob.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/code/codeBlob.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -186,7 +186,7 @@ FREE_C_HEAP_ARRAY(unsigned char, _oop_maps, mtCode); _oop_maps = NULL; } - _comments.free(); + _strings.free(); } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/code/codeBlob.hpp --- a/src/share/vm/code/codeBlob.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/code/codeBlob.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -66,7 +66,7 @@ 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 @@ // Print the comment associated with offset on stream, if there is one virtual void print_block_comment(outputStream* stream, address block_begin) const { intptr_t offset = (intptr_t)(block_begin - code_begin()); - _comments.print_block_comment(stream, offset); + _strings.print_block_comment(stream, offset); } // Transfer ownership of comments to this CodeBlob - void set_comments(CodeComments& comments) { - _comments.assign(comments); + void set_strings(CodeStrings& strings) { + _strings.assign(strings); } }; diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/code/codeCache.hpp --- a/src/share/vm/code/codeCache.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/code/codeCache.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -156,6 +156,11 @@ static address low_bound() { return (address) _heap->low_boundary(); } static address high_bound() { return (address) _heap->high_boundary(); } + static bool has_space(int size) { + // Always leave some room in the CodeCache for I2C/C2I adapters + return largest_free_block() > (CodeCacheMinimumFreeSpace + size); + } + // Profiling static address first_address(); // first address used for CodeBlobs static address last_address(); // last address used for CodeBlobs diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/code/compiledIC.cpp --- a/src/share/vm/code/compiledIC.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/code/compiledIC.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -552,7 +552,7 @@ void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) { address stub=find_stub(); - assert(stub!=NULL, "stub not found"); + guarantee(stub != NULL, "stub not found"); if (TraceICs) { ResourceMark rm; diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/code/icBuffer.hpp --- a/src/share/vm/code/icBuffer.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/code/icBuffer.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -50,7 +50,7 @@ friend class ICStubInterface; // This will be called only by ICStubInterface void initialize(int size, - CodeComments comments) { _size = size; _ic_site = NULL; } + CodeStrings strings) { _size = size; _ic_site = NULL; } void finalize(); // called when a method is removed // General info diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/code/nmethod.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -486,7 +486,6 @@ #endif // def HAVE_DTRACE_H } - nmethod* nmethod::new_native_nmethod(methodHandle method, int compile_id, CodeBuffer *code_buffer, @@ -502,17 +501,19 @@ { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); int native_nmethod_size = allocation_size(code_buffer, sizeof(nmethod)); - CodeOffsets offsets; - offsets.set_value(CodeOffsets::Verified_Entry, vep_offset); - offsets.set_value(CodeOffsets::Frame_Complete, frame_complete); - nm = new (native_nmethod_size) - nmethod(method(), native_nmethod_size, compile_id, &offsets, - code_buffer, frame_size, - basic_lock_owner_sp_offset, basic_lock_sp_offset, - oop_maps); - NOT_PRODUCT(if (nm != NULL) nmethod_stats.note_native_nmethod(nm)); - if (PrintAssembly && nm != NULL) - Disassembler::decode(nm); + if (CodeCache::has_space(native_nmethod_size)) { + CodeOffsets offsets; + offsets.set_value(CodeOffsets::Verified_Entry, vep_offset); + offsets.set_value(CodeOffsets::Frame_Complete, frame_complete); + nm = new (native_nmethod_size) nmethod(method(), native_nmethod_size, + compile_id, &offsets, + code_buffer, frame_size, + basic_lock_owner_sp_offset, + basic_lock_sp_offset, oop_maps); + NOT_PRODUCT(if (nm != NULL) nmethod_stats.note_native_nmethod(nm)); + if (PrintAssembly && nm != NULL) + Disassembler::decode(nm); + } } // verify nmethod debug_only(if (nm) nm->verify();) // might block @@ -537,16 +538,19 @@ { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); int nmethod_size = allocation_size(code_buffer, sizeof(nmethod)); - CodeOffsets offsets; - offsets.set_value(CodeOffsets::Verified_Entry, vep_offset); - offsets.set_value(CodeOffsets::Dtrace_trap, trap_offset); - offsets.set_value(CodeOffsets::Frame_Complete, frame_complete); + if (CodeCache::has_space(nmethod_size)) { + CodeOffsets offsets; + offsets.set_value(CodeOffsets::Verified_Entry, vep_offset); + offsets.set_value(CodeOffsets::Dtrace_trap, trap_offset); + offsets.set_value(CodeOffsets::Frame_Complete, frame_complete); - nm = new (nmethod_size) nmethod(method(), nmethod_size, &offsets, code_buffer, frame_size); + nm = new (nmethod_size) nmethod(method(), nmethod_size, + &offsets, code_buffer, frame_size); - NOT_PRODUCT(if (nm != NULL) nmethod_stats.note_nmethod(nm)); - if (PrintAssembly && nm != NULL) - Disassembler::decode(nm); + NOT_PRODUCT(if (nm != NULL) nmethod_stats.note_nmethod(nm)); + if (PrintAssembly && nm != NULL) + Disassembler::decode(nm); + } } // verify nmethod debug_only(if (nm) nm->verify();) // might block @@ -587,7 +591,8 @@ + round_to(handler_table->size_in_bytes(), oopSize) + round_to(nul_chk_table->size_in_bytes(), oopSize) + round_to(debug_info->data_size() , oopSize); - nm = new (nmethod_size) + if (CodeCache::has_space(nmethod_size)) { + nm = new (nmethod_size) nmethod(method(), nmethod_size, compile_id, entry_bci, offsets, orig_pc_offset, debug_info, dependencies, code_buffer, frame_size, oop_maps, @@ -595,6 +600,7 @@ nul_chk_table, compiler, comp_level); + } if (nm != NULL) { // To make dependency checking during class loading fast, record // the nmethod dependencies in the classes it is dependent on. @@ -793,9 +799,9 @@ #endif // def HAVE_DTRACE_H void* nmethod::operator new(size_t size, int nmethod_size) { - // Always leave some room in the CodeCache for I2C/C2I adapters - if (CodeCache::largest_free_block() < CodeCacheMinimumFreeSpace) return NULL; - return CodeCache::allocate(nmethod_size); + void* alloc = CodeCache::allocate(nmethod_size); + guarantee(alloc != NULL, "CodeCache should have enough space"); + return alloc; } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/code/stubs.cpp --- a/src/share/vm/code/stubs.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/code/stubs.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -101,8 +101,8 @@ 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 @@ 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 @@ // 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 @@ } -void StubQueue::commit(int committed_code_size, CodeComments& comments) { +void StubQueue::commit(int committed_code_size, CodeStrings& strings) { assert(committed_code_size > 0, "committed_code_size must be > 0"); int committed_size = round_to(stub_code_size_to_size(committed_code_size), CodeEntryAlignment); Stub* s = current_stub(); assert(committed_size <= stub_size(s), "committed size must not exceed requested size"); - stub_initialize(s, committed_size, comments); + stub_initialize(s, committed_size, strings); _queue_end += committed_size; _number_of_stubs++; if (_mutex != NULL) _mutex->unlock(); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/code/stubs.hpp --- a/src/share/vm/code/stubs.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/code/stubs.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -73,7 +73,7 @@ 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 @@ 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 @@ 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 @@ // 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 @@ Stub* request_committed(int code_size); // request a stub that provides exactly code_size space for code Stub* request(int requested_code_size); // request a stub with a (maximum) code space - locks the queue void commit (int committed_code_size, - CodeComments& comments); // commit the previously requested stub - unlocks the queue + CodeStrings& strings); // commit the previously requested stub - unlocks the queue // Stub deallocation void remove_first(); // remove the first stub in the queue diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/compiler/compileBroker.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -65,9 +65,8 @@ 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 @@ 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 @@ #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 @@ #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_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() { 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 @@ // 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 @@ 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_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 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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,13 +2157,18 @@ 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(); + tty->print_cr(" Total compiled methods : %6d methods", CompileBroker::_total_compile_count); + tty->print_cr(" Standard compilation : %6d methods", CompileBroker::_total_standard_compile_count); + tty->print_cr(" On stack replacement : %6d methods", CompileBroker::_total_osr_compile_count); int tcb = CompileBroker::_sum_osr_bytes_compiled + CompileBroker::_sum_standard_bytes_compiled; tty->print_cr(" Total compiled bytecodes : %6d bytes", tcb); tty->print_cr(" Standard compilation : %6d bytes", CompileBroker::_sum_standard_bytes_compiled); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/compiler/compileBroker.hpp --- a/src/share/vm/compiler/compileBroker.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/compiler/compileBroker.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -418,6 +418,9 @@ static void print_last_compile(); static void print_compiler_threads_on(outputStream* st); + + // compiler name for debugging + static const char* compiler_name(int comp_level); }; #endif // SHARE_VM_COMPILER_COMPILEBROKER_HPP diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/compiler/compileLog.cpp --- a/src/share/vm/compiler/compileLog.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/compiler/compileLog.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -60,28 +60,6 @@ } -// Advance kind up to a null or space, return this tail. -// Make sure kind is null-terminated, not space-terminated. -// Use the buffer if necessary. -static const char* split_attrs(const char* &kind, char* buffer) { - const char* attrs = strchr(kind, ' '); - // Tease apart the first word from the rest: - if (attrs == NULL) { - return ""; // no attrs, no split - } else if (kind == buffer) { - ((char*) attrs)[-1] = 0; - return attrs; - } else { - // park it in the buffer, so we can put a null on the end - assert(!(kind >= buffer && kind < buffer+100), "not obviously in buffer"); - int klen = attrs - kind; - strncpy(buffer, kind, klen); - buffer[klen] = 0; - kind = buffer; // return by reference - return attrs; - } -} - // see_tag, pop_tag: Override the default do-nothing methods on xmlStream. // These methods provide a hook for managing the the extra context markup. void CompileLog::see_tag(const char* tag, bool push) { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/compiler/compilerOracle.cpp --- a/src/share/vm/compiler/compilerOracle.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/compiler/compilerOracle.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -237,13 +237,6 @@ "help" }; -static const char * command_name(OracleCommand command) { - if (command < OracleFirstCommand || command >= OracleCommandCount) { - return "unknown command"; - } - return command_names[command]; -} - class MethodMatcher; static MethodMatcher* lists[OracleCommandCount] = { 0, }; diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/compiler/disassembler.cpp --- a/src/share/vm/compiler/disassembler.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/compiler/disassembler.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -158,7 +158,7 @@ private: nmethod* _nm; CodeBlob* _code; - CodeComments _comments; + CodeStrings _strings; outputStream* _output; address _start, _end; @@ -198,7 +198,7 @@ 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 @@ 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 @@ 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 @@ env.decode_instructions(cb->code_begin(), cb->code_end()); } -void Disassembler::decode(address start, address end, outputStream* st, CodeComments c) { +void Disassembler::decode(address start, address end, outputStream* st, CodeStrings c) { if (!load_library()) return; decode_env env(CodeCache::find_blob_unsafe(start), st, c); env.decode_instructions(start, end); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/compiler/disassembler.hpp --- a/src/share/vm/compiler/disassembler.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/compiler/disassembler.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -100,7 +100,7 @@ } static void decode(CodeBlob *cb, outputStream* st = NULL); static void decode(nmethod* nm, outputStream* st = NULL); - static void decode(address begin, address end, outputStream* st = NULL, CodeComments c = CodeComments()); + static void decode(address begin, address end, outputStream* st = NULL, CodeStrings c = CodeStrings()); }; #endif // SHARE_VM_COMPILER_DISASSEMBLER_HPP diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -6068,6 +6068,10 @@ verify_work_stacks_empty(); verify_overflow_empty(); + if (should_unload_classes()) { + ClassLoaderDataGraph::purge(); + } + _intra_sweep_timer.stop(); _intra_sweep_estimate.sample(_intra_sweep_timer.seconds()); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -784,7 +784,7 @@ } } -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 @@ _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 @@ // 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 @@ gclog_or_tty->print_cr("[%u] leaving first barrier", worker_id); } - // let the task associated with with worker 0 do this - if (worker_id == 0) { - // task 0 is responsible for clearing the global data structures - // We should be here because of an overflow. During STW we should - // not clear the overflow flag since we rely on it being true when - // we exit this method to abort the pause and restart concurent - // marking. - reset_marking_state(concurrent() /* clear_overflow */); - force_overflow()->update(); - - if (G1Log::fine()) { - gclog_or_tty->date_stamp(PrintGCDateStamps); - gclog_or_tty->stamp(PrintGCTimeStamps); - gclog_or_tty->print_cr("[GC concurrent-mark-reset-for-overflow]"); + // If we're executing the concurrent phase of marking, reset the marking + // state; otherwise the marking state is reset after reference processing, + // during the remark pause. + // If we reset here as a result of an overflow during the remark we will + // see assertion failures from any subsequent set_concurrency_and_phase() + // calls. + if (concurrent()) { + // let the task associated with with worker 0 do this + if (worker_id == 0) { + // task 0 is responsible for clearing the global data structures + // We should be here because of an overflow. During STW we should + // not clear the overflow flag since we rely on it being true when + // we exit this method to abort the pause and restart concurent + // marking. + reset_marking_state(true /* clear_overflow */); + force_overflow()->update(); + + if (G1Log::fine()) { + gclog_or_tty->date_stamp(PrintGCDateStamps); + gclog_or_tty->stamp(PrintGCTimeStamps); + gclog_or_tty->print_cr("[GC concurrent-mark-reset-for-overflow]"); + } } } @@ -1007,7 +1021,7 @@ 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 @@ 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 @@ 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 @@ if (has_overflown()) { // Oops. We overflowed. Restart concurrent marking. _restart_for_overflow = true; + 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(); - if (G1TraceMarkStackOverflow) { - gclog_or_tty->print_cr("\nRemark led to restart for overflow."); - } } else { // Aggregate the per-task counting data that we have accumulated // while marking. @@ -2184,14 +2208,17 @@ // 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 @@ 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 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 @@ // 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 @@ ProcessTask& _proc_task; G1CollectedHeap* _g1h; ConcurrentMark* _cm; - bool _processing_is_mt; public: G1CMRefProcTaskProxy(ProcessTask& proc_task, @@ -2336,15 +2353,15 @@ 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 @@ 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 @@ 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 @@ 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 = (rp->processing_is_mt() - ? &par_task_executor - : NULL); + AbstractRefProcTaskExecutor* executor = (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 @@ 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 @@ 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 @@ 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 @@ } } - 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 @@ active_workers = (uint) ParallelGCThreads; g1h->workers()->set_active_workers(active_workers); } - set_phase(active_workers, false /* concurrent */); + set_concurrency_and_phase(active_workers, false /* concurrent */); // Leave _parallel_marking_threads at it's // value originally calculated in the ConcurrentMark // constructor and pass values of the active workers // through the gang in the task. - CMRemarkTask remarkTask(this, active_workers); + CMRemarkTask remarkTask(this, active_workers, false /* is_serial */); + // We will start all available threads, even if we decide that the + // active_workers will be fewer. The extra ones will just bail out + // immediately. g1h->set_par_threads(active_workers); g1h->workers()->run_task(&remarkTask); g1h->set_par_threads(0); } else { G1CollectedHeap::StrongRootsScope srs(g1h); - // this is remark, so we'll use up all available threads uint active_workers = 1; - set_phase(active_workers, false /* concurrent */); - - CMRemarkTask remarkTask(this, active_workers); - // We will start all available threads, even if we decide that the - // active_workers will be fewer. The extra ones will just bail out - // immediately. + set_concurrency_and_phase(active_workers, false /* concurrent */); + + // Note - if there's no work gang then the VMThread will be + // the thread to execute the remark - serially. We have + // to pass true for the is_serial parameter so that + // CMTask::do_marking_step() doesn't enter the sync + // barriers in the event of an overflow. Doing so will + // cause an assert that the current thread is not a + // concurrent GC thread. + CMRemarkTask remarkTask(this, active_workers, true /* is_serial*/); remarkTask.work(0); } SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); - guarantee(satb_mq_set.completed_buffers_num() == 0, "invariant"); + guarantee(has_overflown() || + satb_mq_set.completed_buffers_num() == 0, + err_msg("Invariant: has_overflown = %s, num buffers = %d", + BOOL_TO_STR(has_overflown()), + satb_mq_set.completed_buffers_num())); print_stats(); } @@ -3854,8 +3914,8 @@ /***************************************************************************** - 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 @@ 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 @@ (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 @@ 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 @@ _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 @@ } _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 @@ gclog_or_tty->print_cr("[%u] detected overflow", _worker_id); } - _cm->enter_first_sync_barrier(_worker_id); - // When we exit this sync barrier we know that all tasks have - // stopped doing marking work. So, it's now safe to - // re-initialise our data structures. At the end of this method, - // task 0 will clear the global data structures. + if (!is_serial) { + // We only need to enter the sync barrier if being called + // from a parallel context + _cm->enter_first_sync_barrier(_worker_id); + + // When we exit this sync barrier we know that all tasks have + // stopped doing marking work. So, it's now safe to + // re-initialise our data structures. At the end of this method, + // task 0 will clear the global data structures. + } statsOnly( ++_aborted_overflow ); // We clear the local state of this task... clear_region_fields(); - // ...and enter the second barrier. - _cm->enter_second_sync_barrier(_worker_id); - // At this point everything has bee re-initialised and we're + if (!is_serial) { + // ...and enter the second barrier. + _cm->enter_second_sync_barrier(_worker_id); + } + // At this point, if we're during the concurrent phase of + // marking, everything has been re-initialized and we're // ready to restart. } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/gc_implementation/g1/concurrentMark.hpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -166,7 +166,7 @@ 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 @@ // 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 @@ // trying not to exceed the given duration. However, it might exit // prematurely, according to some conditions (i.e. SATB buffers are // available for processing). - void do_marking_step(double target_ms, bool do_stealing, bool do_termination); + void do_marking_step(double target_ms, + bool do_termination, + bool is_serial); // These two calls start and stop the timer void record_start_time() { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -854,7 +854,8 @@ assert(!isHumongous(word_size), "we do not allow humongous TLABs"); unsigned int dummy_gc_count_before; - return attempt_allocation(word_size, &dummy_gc_count_before); + int dummy_gclocker_retry_count = 0; + return attempt_allocation(word_size, &dummy_gc_count_before, &dummy_gclocker_retry_count); } HeapWord* @@ -863,14 +864,14 @@ assert_heap_not_locked_and_not_at_safepoint(); // Loop until the allocation is satisified, or unsatisfied after GC. - for (int try_count = 1; /* we'll return */; try_count += 1) { + for (int try_count = 1, gclocker_retry_count = 0; /* we'll return */; try_count += 1) { unsigned int gc_count_before; HeapWord* result = NULL; if (!isHumongous(word_size)) { - result = attempt_allocation(word_size, &gc_count_before); + result = attempt_allocation(word_size, &gc_count_before, &gclocker_retry_count); } else { - result = attempt_allocation_humongous(word_size, &gc_count_before); + result = attempt_allocation_humongous(word_size, &gc_count_before, &gclocker_retry_count); } if (result != NULL) { return result; @@ -894,6 +895,9 @@ } return result; } else { + if (gclocker_retry_count > GCLockerRetryAllocationCount) { + return NULL; + } assert(op.result() == NULL, "the result should be NULL if the VM op did not succeed"); } @@ -910,7 +914,8 @@ } HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size, - unsigned int *gc_count_before_ret) { + unsigned int *gc_count_before_ret, + int* gclocker_retry_count_ret) { // Make sure you read the note in attempt_allocation_humongous(). assert_heap_not_locked_and_not_at_safepoint(); @@ -986,10 +991,16 @@ return NULL; } } else { + if (*gclocker_retry_count_ret > GCLockerRetryAllocationCount) { + MutexLockerEx x(Heap_lock); + *gc_count_before_ret = total_collections(); + return NULL; + } // The GCLocker is either active or the GCLocker initiated // GC has not yet been performed. Stall until it is and // then retry the allocation. GC_locker::stall_until_clear(); + (*gclocker_retry_count_ret) += 1; } // We can reach here if we were unsuccessul in scheduling a @@ -1019,7 +1030,8 @@ } HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size, - unsigned int * gc_count_before_ret) { + unsigned int * gc_count_before_ret, + int* gclocker_retry_count_ret) { // The structure of this method has a lot of similarities to // attempt_allocation_slow(). The reason these two were not merged // into a single one is that such a method would require several "if @@ -1104,10 +1116,16 @@ return NULL; } } else { + if (*gclocker_retry_count_ret > GCLockerRetryAllocationCount) { + MutexLockerEx x(Heap_lock); + *gc_count_before_ret = total_collections(); + return NULL; + } // The GCLocker is either active or the GCLocker initiated // GC has not yet been performed. Stall until it is and // then retry the allocation. GC_locker::stall_until_clear(); + (*gclocker_retry_count_ret) += 1; } // We can reach here if we were unsuccessul in scheduling a @@ -3270,12 +3288,12 @@ void G1CollectedHeap::verify(bool silent, VerifyOption vo) { - if (SafepointSynchronize::is_at_safepoint() || ! UseTLAB) { + if (SafepointSynchronize::is_at_safepoint()) { if (!silent) { gclog_or_tty->print("Roots "); } VerifyRootsClosure rootsCl(vo); assert(Thread::current()->is_VM_thread(), - "Expected to be executed serially by the VM thread at this point"); + "Expected to be executed serially by the VM thread at this point"); CodeBlobToOopClosure blobsCl(&rootsCl, /*do_marking=*/ false); VerifyKlassClosure klassCl(this, &rootsCl); @@ -3360,7 +3378,8 @@ } guarantee(!failures, "there should not have been any failures"); } else { - if (!silent) gclog_or_tty->print("(SKIPPING roots, heapRegions, remset) "); + if (!silent) + gclog_or_tty->print("(SKIPPING roots, heapRegionSets, heapRegions, remset) "); } } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -559,18 +559,21 @@ // the mutator alloc region without taking the Heap_lock. This // should only be used for non-humongous allocations. inline HeapWord* attempt_allocation(size_t word_size, - unsigned int* gc_count_before_ret); + unsigned int* gc_count_before_ret, + int* gclocker_retry_count_ret); // Second-level mutator allocation attempt: take the Heap_lock and // retry the allocation attempt, potentially scheduling a GC // pause. This should only be used for non-humongous allocations. HeapWord* attempt_allocation_slow(size_t word_size, - unsigned int* gc_count_before_ret); + unsigned int* gc_count_before_ret, + int* gclocker_retry_count_ret); // Takes the Heap_lock and attempts a humongous allocation. It can // potentially schedule a GC pause. HeapWord* attempt_allocation_humongous(size_t word_size, - unsigned int* gc_count_before_ret); + unsigned int* gc_count_before_ret, + int* gclocker_retry_count_ret); // Allocation attempt that should be called during safepoints (e.g., // at the end of a successful GC). expect_null_mutator_alloc_region diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -60,7 +60,8 @@ inline HeapWord* G1CollectedHeap::attempt_allocation(size_t word_size, - unsigned int* gc_count_before_ret) { + unsigned int* gc_count_before_ret, + int* gclocker_retry_count_ret) { assert_heap_not_locked_and_not_at_safepoint(); assert(!isHumongous(word_size), "attempt_allocation() should not " "be called for humongous allocation requests"); @@ -68,7 +69,9 @@ HeapWord* result = _mutator_alloc_region.attempt_allocation(word_size, false /* bot_updates */); if (result == NULL) { - result = attempt_allocation_slow(word_size, gc_count_before_ret); + result = attempt_allocation_slow(word_size, + gc_count_before_ret, + gclocker_retry_count_ret); } assert_heap_not_locked(); if (result != NULL) { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -1359,18 +1359,6 @@ #endif // PRODUCT } -#ifndef PRODUCT -// for debugging, bit of a hack... -static char* -region_num_to_mbs(int length) { - static char buffer[64]; - double bytes = (double) (length * HeapRegion::GrainBytes); - double mbs = bytes / (double) (1024 * 1024); - sprintf(buffer, "%7.2lfMB", mbs); - return buffer; -} -#endif // PRODUCT - uint G1CollectorPolicy::max_regions(int purpose) { switch (purpose) { case GCAllocForSurvived: diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/gc_implementation/g1/ptrQueue.cpp --- a/src/share/vm/gc_implementation/g1/ptrQueue.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -53,15 +53,6 @@ } -static int byte_index_to_index(int ind) { - assert((ind % oopSize) == 0, "Invariant."); - return ind / oopSize; -} - -static int index_to_byte_index(int byte_ind) { - return byte_ind * oopSize; -} - void PtrQueue::enqueue_known_active(void* ptr) { assert(0 <= _index && _index <= _sz, "Invariant."); assert(_index == 0 || _buf != NULL, "invariant"); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -326,6 +326,7 @@ uint loop_count = 0; uint gc_count = 0; + int gclocker_stalled_count = 0; while (result == NULL) { // We don't want to have multiple collections for a single filled generation. @@ -354,6 +355,10 @@ return result; } + if (gclocker_stalled_count > GCLockerRetryAllocationCount) { + return NULL; + } + // Failed to allocate without a gc. if (GC_locker::is_active_and_needs_gc()) { // If this thread is not in a jni critical section, we stall @@ -366,6 +371,7 @@ if (!jthr->in_critical()) { MutexUnlocker mul(Heap_lock); GC_locker::stall_until_clear(); + gclocker_stalled_count += 1; continue; } else { if (CheckJNICalls) { @@ -656,7 +662,7 @@ tty->print_cr("[Accumulated GC generation 0 time %3.7f secs]", time); } if (TraceGen1Time) { - double time = PSMarkSweep::accumulated_time()->seconds(); + double time = UseParallelOldGC ? PSParallelCompact::accumulated_time()->seconds() : PSMarkSweep::accumulated_time()->seconds(); tty->print_cr("[Accumulated GC generation 1 time %3.7f secs]", time); } } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -256,7 +256,7 @@ } if (PrintGC && Verbose) { - if (success && GC_locker::is_active()) { + if (success && GC_locker::is_active_and_needs_gc()) { gclog_or_tty->print_cr("Garbage collection disabled, expanded heap instead"); } } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/interpreter/interpreter.cpp --- a/src/share/vm/interpreter/interpreter.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/interpreter/interpreter.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -76,7 +76,7 @@ if (PrintInterpreter) { st->cr(); - Disassembler::decode(code_begin(), code_end(), st, DEBUG_ONLY(_comments) NOT_DEBUG(CodeComments())); + Disassembler::decode(code_begin(), code_end(), st, DEBUG_ONLY(_strings) NOT_DEBUG(CodeStrings())); } } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/interpreter/interpreter.hpp --- a/src/share/vm/interpreter/interpreter.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/interpreter/interpreter.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -48,12 +48,12 @@ 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 @@ // commit Codelet - AbstractInterpreter::code()->commit((*_masm)->code()->pure_insts_size(), (*_masm)->code()->comments()); + AbstractInterpreter::code()->commit((*_masm)->code()->pure_insts_size(), (*_masm)->code()->strings()); // make sure nobody can use _masm outside a CodeletMark lifespan *_masm = NULL; } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/interpreter/interpreterRuntime.cpp --- a/src/share/vm/interpreter/interpreterRuntime.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/interpreter/interpreterRuntime.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -557,11 +557,6 @@ // be shared by method invocation and synchronized blocks. //%note synchronization_3 -static void trace_locking(Handle& h_locking_obj, bool is_locking) { - ObjectSynchronizer::trace_locking(h_locking_obj, false, true, is_locking); -} - - //%note monitor_1 IRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* thread, BasicObjectLock* elem)) #ifdef ASSERT diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/interpreter/linkResolver.cpp --- a/src/share/vm/interpreter/linkResolver.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/interpreter/linkResolver.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -458,25 +458,27 @@ Handle class_loader (THREAD, resolved_method->method_holder()->class_loader()); { ResourceMark rm(THREAD); - char* failed_type_name = + Symbol* failed_type_symbol = SystemDictionary::check_signature_loaders(method_signature, loader, class_loader, true, CHECK); - if (failed_type_name != NULL) { + if (failed_type_symbol != NULL) { const char* msg = "loader constraint violation: when resolving method" " \"%s\" the class loader (instance of %s) of the current class, %s," - " and the class loader (instance of %s) for resolved class, %s, have" + " and the class loader (instance of %s) for the method's defining class, %s, have" " different Class objects for the type %s used in the signature"; char* sig = Method::name_and_sig_as_C_string(resolved_klass(),method_name,method_signature); const char* loader1 = SystemDictionary::loader_name(loader()); char* current = InstanceKlass::cast(current_klass())->name()->as_C_string(); const char* loader2 = SystemDictionary::loader_name(class_loader()); - char* resolved = InstanceKlass::cast(resolved_klass())->name()->as_C_string(); + char* target = InstanceKlass::cast(resolved_method->method_holder()) + ->name()->as_C_string(); + char* failed_type_name = failed_type_symbol->as_C_string(); size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) + - strlen(current) + strlen(loader2) + strlen(resolved) + - strlen(failed_type_name); + strlen(current) + strlen(loader2) + strlen(target) + + strlen(failed_type_name) + 1; char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen); jio_snprintf(buf, buflen, msg, sig, loader1, current, loader2, - resolved, failed_type_name); + target, failed_type_name); THROW_MSG(vmSymbols::java_lang_LinkageError(), buf); } } @@ -520,26 +522,28 @@ Handle class_loader (THREAD, resolved_method->method_holder()->class_loader()); { ResourceMark rm(THREAD); - char* failed_type_name = + Symbol* failed_type_symbol = SystemDictionary::check_signature_loaders(method_signature, loader, class_loader, true, CHECK); - if (failed_type_name != NULL) { + if (failed_type_symbol != NULL) { const char* msg = "loader constraint violation: when resolving " "interface method \"%s\" the class loader (instance of %s) of the " "current class, %s, and the class loader (instance of %s) for " - "resolved class, %s, have different Class objects for the type %s " + "the method's defining class, %s, have different Class objects for the type %s " "used in the signature"; char* sig = Method::name_and_sig_as_C_string(resolved_klass(),method_name,method_signature); const char* loader1 = SystemDictionary::loader_name(loader()); char* current = InstanceKlass::cast(current_klass())->name()->as_C_string(); const char* loader2 = SystemDictionary::loader_name(class_loader()); - char* resolved = InstanceKlass::cast(resolved_klass())->name()->as_C_string(); + char* target = InstanceKlass::cast(resolved_method->method_holder()) + ->name()->as_C_string(); + char* failed_type_name = failed_type_symbol->as_C_string(); size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) + - strlen(current) + strlen(loader2) + strlen(resolved) + - strlen(failed_type_name); + strlen(current) + strlen(loader2) + strlen(target) + + strlen(failed_type_name) + 1; char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen); jio_snprintf(buf, buflen, msg, sig, loader1, current, loader2, - resolved, failed_type_name); + target, failed_type_name); THROW_MSG(vmSymbols::java_lang_LinkageError(), buf); } } @@ -642,12 +646,12 @@ Symbol* signature_ref = pool->signature_ref_at(index); { ResourceMark rm(THREAD); - char* failed_type_name = + Symbol* failed_type_symbol = SystemDictionary::check_signature_loaders(signature_ref, ref_loader, sel_loader, false, CHECK); - if (failed_type_name != NULL) { + if (failed_type_symbol != NULL) { const char* msg = "loader constraint violation: when resolving field" " \"%s\" the class loader (instance of %s) of the referring class, " "%s, and the class loader (instance of %s) for the field's resolved " @@ -656,8 +660,9 @@ const char* loader1 = SystemDictionary::loader_name(ref_loader()); char* sel = InstanceKlass::cast(sel_klass())->name()->as_C_string(); const char* loader2 = SystemDictionary::loader_name(sel_loader()); + char* failed_type_name = failed_type_symbol->as_C_string(); size_t buflen = strlen(msg) + strlen(field_name) + strlen(loader1) + - strlen(sel) + strlen(loader2) + strlen(failed_type_name); + strlen(sel) + strlen(loader2) + strlen(failed_type_name) + 1; char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen); jio_snprintf(buf, buflen, msg, field_name, loader1, sel, loader2, failed_type_name); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/memory/collectorPolicy.cpp --- a/src/share/vm/memory/collectorPolicy.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/memory/collectorPolicy.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -532,7 +532,7 @@ // Loop until the allocation is satisified, // or unsatisfied after GC. - for (int try_count = 1; /* return or throw */; try_count += 1) { + for (int try_count = 1, gclocker_stalled_count = 0; /* return or throw */; try_count += 1) { HandleMark hm; // discard any handles allocated in each iteration // First allocation attempt is lock-free. @@ -576,6 +576,10 @@ } } + if (gclocker_stalled_count > GCLockerRetryAllocationCount) { + return NULL; // we didn't get to do a GC and we didn't get any memory + } + // If this thread is not in a jni critical section, we stall // the requestor until the critical section has cleared and // GC allowed. When the critical section clears, a GC is @@ -587,6 +591,7 @@ MutexUnlocker mul(Heap_lock); // Wait for JNI critical section to be exited GC_locker::stall_until_clear(); + gclocker_stalled_count += 1; continue; } else { if (CheckJNICalls) { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/memory/filemap.cpp --- a/src/share/vm/memory/filemap.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/memory/filemap.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -372,7 +372,7 @@ // other reserved memory (like the code cache). ReservedSpace rs(size, alignment, false, requested_addr); if (!rs.is_reserved()) { - fail_continue(err_msg("Unable to reserved shared space at required address " INTPTR_FORMAT, requested_addr)); + fail_continue(err_msg("Unable to reserve shared space at required address " INTPTR_FORMAT, requested_addr)); return rs; } // the reserved virtual memory is for mapping class data sharing archive diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/memory/genCollectedHeap.cpp --- a/src/share/vm/memory/genCollectedHeap.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/memory/genCollectedHeap.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -554,6 +554,8 @@ } 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 @@ gc_epilogue(complete); - // Delete metaspaces for unloaded class loaders and clean up loader_data graph - if (complete) { - ClassLoaderDataGraph::purge(); - } - if (must_restore_marks_for_biased_locking) { BiasedLocking::restore_marks(); } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/memory/heap.cpp --- a/src/share/vm/memory/heap.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/memory/heap.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -79,13 +79,6 @@ } -static size_t align_to_allocation_size(size_t size) { - const size_t alignment = (size_t)os::vm_allocation_granularity(); - assert(is_power_of_2(alignment), "no kidding ???"); - return (size + alignment - 1) & ~(alignment - 1); -} - - void CodeHeap::on_code_mapping(char* base, size_t size) { #ifdef LINUX extern void linux_wrap_code(char* base, size_t size); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/memory/metaspace.cpp --- a/src/share/vm/memory/metaspace.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/memory/metaspace.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -334,27 +334,19 @@ // byte_size is the size of the associated virtualspace. VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(0) { - // 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 - // compressed oops don't work with CDS (offsets in metadata are wrong), so - // borrow the same address. + // align up to vm allocation granularity + byte_size = align_size_up(byte_size, os::vm_allocation_granularity()); + + // This allocates memory with mmap. For DumpSharedspaces, try to reserve + // configurable address, generally at the top of the Java heap so other + // memory addresses don't conflict. if (DumpSharedSpaces) { - char* shared_base = (char*)HeapBaseMinAddress; + char* shared_base = (char*)SharedBaseAddress; _rs = ReservedSpace(byte_size, 0, false, shared_base, 0); if (_rs.is_reserved()) { - assert(_rs.base() == shared_base, "should match"); + assert(shared_base == 0 || _rs.base() == shared_base, "should match"); } else { - // If we are dumping the heap, then allocate a wasted block of address - // space in order to push the heap to a lower address. This extra - // address range allows for other (or larger) libraries to be loaded - // without them occupying the space required for the shared spaces. - uintx reserved = 0; - uintx block_size = 64*1024*1024; - while (reserved < SharedDummyBlockSize) { - char* dummy = os::reserve_memory(block_size); - reserved += block_size; - } + // Get a mmap region anywhere if the SharedBaseAddress fails. _rs = ReservedSpace(byte_size); } MetaspaceShared::set_shared_rs(&_rs); @@ -1100,25 +1092,24 @@ } 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 +1299,7 @@ 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 +1959,9 @@ } 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 +1979,7 @@ // Have to update before the chunks_in_use lists are emptied // below. - chunk_manager->inc_free_chunks_total(sum_capacity_in_chunks_in_use(), + chunk_manager->inc_free_chunks_total(in_use_before, sum_count_in_chunks_in_use()); // Add all the chunks in use by this space manager diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/memory/metaspace.hpp diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/memory/sharedHeap.cpp --- a/src/share/vm/memory/sharedHeap.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/memory/sharedHeap.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -178,7 +178,7 @@ SystemDictionary::always_strong_oops_do(roots); ClassLoaderDataGraph::always_strong_oops_do(roots, klass_closure, !is_scavenging); } else { - ShouldNotReachHere2("We should always have selected either SO_AllClasses or SO_SystemClasses"); + fatal("We should always have selected either SO_AllClasses or SO_SystemClasses"); } } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/memory/universe.cpp --- a/src/share/vm/memory/universe.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/memory/universe.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -953,15 +953,6 @@ void universe2_init() { EXCEPTION_MARK; Universe::genesis(CATCH); - // Although we'd like to verify here that the state of the heap - // is good, we can't because the main thread has not yet added - // itself to the threads list (so, using current interfaces - // we can't "fill" its TLAB), unless TLABs are disabled. - if (VerifyBeforeGC && !UseTLAB && - Universe::heap()->total_collections() >= VerifyGCStartAt) { - Universe::heap()->prepare_for_verify(); - Universe::verify(); // make sure we're starting with a clean slate - } } @@ -1335,6 +1326,8 @@ static uintptr_t _verify_klass_data[2] = {0, (uintptr_t)-1}; +#ifndef PRODUCT + static void calculate_verify_data(uintptr_t verify_data[2], HeapWord* low_boundary, HeapWord* high_boundary) { @@ -1369,9 +1362,7 @@ verify_data[1] = bits; } - // Oop verification (see MacroAssembler::verify_oop) -#ifndef PRODUCT uintptr_t Universe::verify_oop_mask() { MemRegion m = heap()->reserved_region(); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/oops/constMethod.cpp --- a/src/share/vm/oops/constMethod.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/oops/constMethod.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -363,6 +363,26 @@ return (AnnotationArray**)constMethod_end() - offset; } +// copy annotations from 'cm' to 'this' +void ConstMethod::copy_annotations_from(ConstMethod* cm) { + if (cm->has_method_annotations()) { + assert(has_method_annotations(), "should be allocated already"); + set_method_annotations(cm->method_annotations()); + } + if (cm->has_parameter_annotations()) { + assert(has_parameter_annotations(), "should be allocated already"); + set_parameter_annotations(cm->parameter_annotations()); + } + if (cm->has_type_annotations()) { + assert(has_type_annotations(), "should be allocated already"); + set_type_annotations(cm->type_annotations()); + } + if (cm->has_default_annotations()) { + assert(has_default_annotations(), "should be allocated already"); + set_default_annotations(cm->default_annotations()); + } +} + // Printing void ConstMethod::print_on(outputStream* st) const { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/oops/constMethod.hpp --- a/src/share/vm/oops/constMethod.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/oops/constMethod.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -441,6 +441,9 @@ return has_default_annotations() ? default_annotations()->length() : 0; } + // Copy annotations from other ConstMethod + void copy_annotations_from(ConstMethod* cm); + // byte codes void set_code(address code) { if (code_size() > 0) { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/oops/constantPool.cpp --- a/src/share/vm/oops/constantPool.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/oops/constantPool.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -1378,12 +1378,13 @@ // JVMTI GetConstantPool support -// For temporary use until code is stable. -#define DBG(code) +// For debugging of constant pool +const bool debug_cpool = false; -static const char* WARN_MSG = "Must not be such entry!"; +#define DBG(code) do { if (debug_cpool) { (code); } } while(0) static void print_cpool_bytes(jint cnt, u1 *bytes) { + const char* WARN_MSG = "Must not be such entry!"; jint size = 0; u2 idx1, idx2; @@ -1669,8 +1670,7 @@ idx1 = tbl->symbol_to_value(sym); assert(idx1 != 0, "Have not found a hashtable entry"); Bytes::put_Java_u2((address) (bytes+1), idx1); - DBG(char *str = sym->as_utf8()); - DBG(printf("JVM_CONSTANT_String: idx=#%03hd, %s", idx1, str)); + DBG(printf("JVM_CONSTANT_String: idx=#%03hd, %s", idx1, sym->as_utf8())); break; } case JVM_CONSTANT_Fieldref: @@ -1745,6 +1745,8 @@ return (int)(bytes - start_bytes); } /* end copy_cpool_bytes */ +#undef DBG + void ConstantPool::set_on_stack(const bool value) { if (value) { @@ -1852,6 +1854,7 @@ switch (tag_at(index).value()) { case JVM_CONSTANT_Class : { Klass* k = klass_at(index, CATCH); + guarantee(k != NULL, "need klass"); k->print_value_on(st); st->print(" {0x%lx}", (address)k); } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/oops/fieldInfo.hpp --- a/src/share/vm/oops/fieldInfo.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/oops/fieldInfo.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -108,11 +108,11 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ return; #ifndef PRODUCT case FIELDINFO_TAG_TYPE_CONTENDED: - ShouldNotReachHere2("Overwriting contended group"); + fatal("Overwriting contended group"); case FIELDINFO_TAG_BLANK: - ShouldNotReachHere2("Setting contended group for the blank field"); + fatal("Setting contended group for the blank field"); case FIELDINFO_TAG_OFFSET: - ShouldNotReachHere2("Setting contended group for field with offset"); + fatal("Setting contended group for field with offset"); #endif } ShouldNotReachHere(); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/oops/generateOopMap.cpp --- a/src/share/vm/oops/generateOopMap.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/oops/generateOopMap.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -762,6 +762,7 @@ // 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 @@ 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 @@ // 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 @@ // Find basicblock and report results BasicBlock* bb = get_basic_block_containing(bci); + guarantee(bb != NULL, "no basic block for bci"); assert(bb->is_reachable(), "getting result from unreachable basicblock"); bb->set_changed(true); interp_bb(bb); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/oops/instanceKlass.cpp --- a/src/share/vm/oops/instanceKlass.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/oops/instanceKlass.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -2228,8 +2228,6 @@ } void InstanceKlass::clean_method_data(BoolObjectClosure* is_alive) { -#ifdef COMPILER2 - // Currently only used by C2. for (int m = 0; m < methods()->length(); m++) { MethodData* mdo = methods()->at(m)->method_data(); if (mdo != NULL) { @@ -2240,15 +2238,6 @@ } } } -#else -#ifdef ASSERT - // Verify that we haven't started to use MDOs for C1. - for (int m = 0; m < methods()->length(); m++) { - MethodData* mdo = methods()->at(m)->method_data(); - assert(mdo == NULL, "Didn't expect C1 to use MDOs"); - } -#endif // ASSERT -#endif // !COMPILER2 } @@ -3168,7 +3157,7 @@ Array* method_ordering = this->method_ordering(); int length = method_ordering->length(); if (JvmtiExport::can_maintain_original_method_order() || - (UseSharedSpaces && length != 0)) { + ((UseSharedSpaces || DumpSharedSpaces) && length != 0)) { guarantee(length == methods()->length(), "invalid method ordering length"); jlong sum = 0; for (int j = 0; j < length; j++) { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/oops/klass.cpp --- a/src/share/vm/oops/klass.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/oops/klass.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -486,6 +486,12 @@ } void Klass::remove_unshareable_info() { + if (!DumpSharedSpaces) { + // Clean up after OOM during class loading + if (class_loader_data() != NULL) { + class_loader_data()->remove_class(this); + } + } set_subklass(NULL); set_next_sibling(NULL); // Clear the java mirror diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/oops/klassVtable.cpp --- a/src/share/vm/oops/klassVtable.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/oops/klassVtable.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -327,11 +327,11 @@ if (target_loader() != super_loader()) { ResourceMark rm(THREAD); - char* failed_type_name = + Symbol* failed_type_symbol = SystemDictionary::check_signature_loaders(signature, target_loader, super_loader, true, CHECK_(false)); - if (failed_type_name != NULL) { + if (failed_type_symbol != NULL) { const char* msg = "loader constraint violation: when resolving " "overridden method \"%s\" the class loader (instance" " of %s) of the current class, %s, and its superclass loader " @@ -341,6 +341,7 @@ const char* loader1 = SystemDictionary::loader_name(target_loader()); char* current = _klass->name()->as_C_string(); const char* loader2 = SystemDictionary::loader_name(super_loader()); + char* failed_type_name = failed_type_symbol->as_C_string(); size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) + strlen(current) + strlen(loader2) + strlen(failed_type_name); char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen); @@ -787,12 +788,12 @@ Handle method_holder_loader (THREAD, target->method_holder()->class_loader()); if (method_holder_loader() != interface_loader()) { ResourceMark rm(THREAD); - char* failed_type_name = + Symbol* failed_type_symbol = SystemDictionary::check_signature_loaders(method_signature, method_holder_loader, interface_loader, true, CHECK); - if (failed_type_name != NULL) { + if (failed_type_symbol != NULL) { const char* msg = "loader constraint violation in interface " "itable initialization: when resolving method \"%s\" the class" " loader (instance of %s) of the current class, %s, " @@ -804,6 +805,7 @@ char* current = klass->name()->as_C_string(); const char* loader2 = SystemDictionary::loader_name(interface_loader()); char* iface = InstanceKlass::cast(interf_h())->name()->as_C_string(); + char* failed_type_name = failed_type_symbol->as_C_string(); size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) + strlen(current) + strlen(loader2) + strlen(iface) + strlen(failed_type_name); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/oops/method.cpp --- a/src/share/vm/oops/method.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/oops/method.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -798,7 +798,15 @@ 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); @@ -959,6 +967,32 @@ return false; } + +/** + * Returns true if this is one of the specially treated methods for + * security related stack walks (like Reflection.getCallerClass). + */ +bool Method::is_ignored_by_security_stack_walk() const { + const bool use_new_reflection = JDK_Version::is_gte_jdk14x_version() && UseNewReflection; + + assert(intrinsic_id() != vmIntrinsics::_invoke || Universe::reflect_invoke_cache()->is_same_method((Method*)this), "sanity"); + if (intrinsic_id() == vmIntrinsics::_invoke) { + // This is Method.invoke() -- ignore it + return true; + } + if (use_new_reflection && + method_holder()->is_subclass_of(SystemDictionary::reflect_MethodAccessorImpl_klass())) { + // This is an auxilary frame -- ignore it + return true; + } + if (is_method_handle_intrinsic() || is_compiled_lambda_form()) { + // This is an internal adapter frame for method handles -- ignore it + return true; + } + return false; +} + + // Constant pool structure for invoke methods: enum { _imcp_invoke_name = 1, // utf8: 'invokeExact', etc. @@ -1162,6 +1196,8 @@ newm->set_stackmap_data(stackmap_data); } + // copy annotations over to new method + newcm->copy_annotations_from(cm); return newm; } @@ -1170,13 +1206,13 @@ // because we are not loading from core libraries // exception: the AES intrinsics come from lib/ext/sunjce_provider.jar // which does not use the class default class loader so we check for its loader here - if ((InstanceKlass::cast(holder)->class_loader() != NULL) && - InstanceKlass::cast(holder)->class_loader()->klass()->name() != vmSymbols::sun_misc_Launcher_ExtClassLoader()) { + InstanceKlass* ik = InstanceKlass::cast(holder); + if ((ik->class_loader() != NULL) && !SystemDictionary::is_ext_class_loader(ik->class_loader())) { return vmSymbols::NO_SID; // regardless of name, no intrinsics here } // see if the klass name is well-known: - Symbol* klass_name = InstanceKlass::cast(holder)->name(); + Symbol* klass_name = ik->name(); return vmSymbols::find_sid(klass_name); } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/oops/method.hpp --- a/src/share/vm/oops/method.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/oops/method.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -118,11 +118,12 @@ #endif u2 _method_size; // size of this object u1 _intrinsic_id; // vmSymbols::intrinsic_id (0 == _none) - u1 _jfr_towrite : 1, // Flags - _force_inline : 1, - _hidden : 1, - _dont_inline : 1, - : 4; + u1 _jfr_towrite : 1, // Flags + _caller_sensitive : 1, + _force_inline : 1, + _hidden : 1, + _dont_inline : 1, + : 3; u2 _interpreter_throwout_count; // Count of times method was exited via exception while interpreting u2 _number_of_breakpoints; // fullspeed debugging support InvocationCounter _invocation_counter; // Incremented before each activation of the method - used to trigger frequency-based optimizations @@ -618,6 +619,9 @@ // Reflection support bool is_overridden_in(Klass* k) const; + // Stack walking support + bool is_ignored_by_security_stack_walk() const; + // JSR 292 support bool is_method_handle_intrinsic() const; // MethodHandles::is_signature_polymorphic_intrinsic(intrinsic_id) bool is_compiled_lambda_form() const; // intrinsic_id() == vmIntrinsics::_compiledLambdaForm @@ -705,15 +709,16 @@ void init_intrinsic_id(); // updates from _none if a match static vmSymbols::SID klass_id_for_intrinsics(Klass* holder); - bool jfr_towrite() { return _jfr_towrite; } - void set_jfr_towrite(bool towrite) { _jfr_towrite = towrite; } - - bool force_inline() { return _force_inline; } - void set_force_inline(bool x) { _force_inline = x; } - bool dont_inline() { return _dont_inline; } - void set_dont_inline(bool x) { _dont_inline = x; } - bool is_hidden() { return _hidden; } - void set_hidden(bool x) { _hidden = x; } + bool jfr_towrite() { return _jfr_towrite; } + void set_jfr_towrite(bool x) { _jfr_towrite = x; } + bool caller_sensitive() { return _caller_sensitive; } + void set_caller_sensitive(bool x) { _caller_sensitive = x; } + bool force_inline() { return _force_inline; } + void set_force_inline(bool x) { _force_inline = x; } + bool dont_inline() { return _dont_inline; } + void set_dont_inline(bool x) { _dont_inline = x; } + bool is_hidden() { return _hidden; } + void set_hidden(bool x) { _hidden = x; } ConstMethod::MethodType method_type() const { return _constMethod->method_type(); } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/oops/methodData.cpp --- a/src/share/vm/oops/methodData.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/oops/methodData.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -392,6 +392,9 @@ } int MethodData::bytecode_cell_count(Bytecodes::Code code) { +#if defined(COMPILER1) && !defined(COMPILER2) + return no_profile_data; +#else switch (code) { case Bytecodes::_checkcast: case Bytecodes::_instanceof: @@ -438,6 +441,7 @@ return variable_cell_count; } return no_profile_data; +#endif } // Compute the size of the profiling information corresponding to @@ -509,6 +513,9 @@ // the segment in bytes. int MethodData::initialize_data(BytecodeStream* stream, int data_index) { +#if defined(COMPILER1) && !defined(COMPILER2) + return 0; +#else int cell_count = -1; int tag = DataLayout::no_tag; DataLayout* data_layout = data_layout_at(data_index); @@ -587,6 +594,7 @@ assert(!bytecode_has_profile(c), "agree w/ !BHP"); return 0; } +#endif } // Get the data at an arbitrary (sort of) data index. diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/oops/symbol.cpp --- a/src/share/vm/oops/symbol.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/oops/symbol.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -162,7 +162,7 @@ const char *ptr = (const char *)&_body[0]; int quoted_length = UTF8::quoted_ascii_length(ptr, utf8_length()); char* result = NEW_RESOURCE_ARRAY(char, quoted_length + 1); - UTF8::as_quoted_ascii(ptr, result, quoted_length + 1); + UTF8::as_quoted_ascii(ptr, utf8_length(), result, quoted_length + 1); return result; } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/block.cpp --- a/src/share/vm/opto/block.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/block.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -1028,26 +1028,6 @@ } #ifndef PRODUCT -static void edge_dump(GrowableArray *edges) { - tty->print_cr("---- Edges ----"); - for (int i = 0; i < edges->length(); i++) { - CFGEdge *e = edges->at(i); - if (e != NULL) { - edges->at(i)->dump(); - } - } -} - -static void trace_dump(Trace *traces[], int count) { - tty->print_cr("---- Traces ----"); - for (int i = 0; i < count; i++) { - Trace *tr = traces[i]; - if (tr != NULL) { - tr->dump(); - } - } -} - void Trace::dump( ) const { tty->print_cr("Trace (freq %f)", first_block()->_freq); for (Block *b = first_block(); b != NULL; b = next(b)) { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/bytecodeInfo.cpp --- a/src/share/vm/opto/bytecodeInfo.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/bytecodeInfo.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -157,9 +157,10 @@ } else { // Not hot. Check for medium-sized pre-existing nmethod at cold sites. if (callee_method->has_compiled_code() && - callee_method->instructions_size() > inline_small_code_size) + callee_method->instructions_size() > inline_small_code_size) { set_msg("already compiled into a medium method"); return false; + } } if (size > max_inline_size) { if (max_inline_size > default_max_inline_size) { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/compile.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -2326,12 +2326,14 @@ int get_inner_loop_count() const { return _inner_loop_count; } }; +#ifdef ASSERT static bool oop_offset_is_sane(const TypeInstPtr* tp) { ciInstanceKlass *k = tp->klass()->as_instance_klass(); // Make sure the offset goes inside the instance layout. return k->contains_field_offset(tp->offset()); // Note that OffsetBot and OffsetTop are very negative. } +#endif // Eliminate trivially redundant StoreCMs and accumulate their // precedence edges. diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/connode.cpp --- a/src/share/vm/opto/connode.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/connode.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -465,29 +465,6 @@ return (phase->type(in(1)) == phase->type(this)) ? in(1) : this; } -// Determine whether "n" is a node which can cause an alias of one of its inputs. Node types -// which can create aliases are: CheckCastPP, Phi, and any store (if there is also a load from -// the location.) -// Note: this checks for aliases created in this compilation, not ones which may -// be potentially created at call sites. -static bool can_cause_alias(Node *n, PhaseTransform *phase) { - bool possible_alias = false; - - if (n->is_Store()) { - possible_alias = !n->as_Store()->value_never_loaded(phase); - } else { - int opc = n->Opcode(); - possible_alias = n->is_Phi() || - opc == Op_CheckCastPP || - opc == Op_StorePConditional || - opc == Op_CompareAndSwapP || - opc == Op_CompareAndSwapN || - opc == Op_GetAndSetP || - opc == Op_GetAndSetN; - } - return possible_alias; -} - //------------------------------Value------------------------------------------ // Take 'join' of input and cast-up type, unless working with an Interface const Type *CheckCastPPNode::Value( PhaseTransform *phase ) const { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/graphKit.cpp --- a/src/share/vm/opto/graphKit.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/graphKit.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -3445,7 +3445,6 @@ void GraphKit::final_sync(IdealKit& ideal) { // Final sync IdealKit and graphKit. - __ drain_delay_transform(); sync_kit(ideal); } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/idealKit.cpp --- a/src/share/vm/opto/idealKit.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/idealKit.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -48,9 +48,9 @@ _cvstate = NULL; // We can go memory state free or else we need the entire memory state assert(_initial_memory == NULL || _initial_memory->Opcode() == Op_MergeMem, "memory must be pre-split"); + assert(!_gvn.is_IterGVN(), "IdealKit can't be used during Optimize phase"); int init_size = 5; _pending_cvstates = new (C->node_arena()) GrowableArray(C->node_arena(), init_size, 0, 0); - _delay_transform = new (C->node_arena()) GrowableArray(C->node_arena(), init_size, 0, 0); DEBUG_ONLY(_state = new (C->node_arena()) GrowableArray(C->node_arena(), init_size, 0, 0)); if (!has_declarations) { declarations_done(); @@ -296,19 +296,16 @@ return delay_transform(n); } else { n = gvn().transform(n); - if (!gvn().is_IterGVN()) { - C->record_for_igvn(n); - } + C->record_for_igvn(n); return n; } } //-----------------------------delay_transform----------------------------------- Node* IdealKit::delay_transform(Node* n) { - if (!gvn().is_IterGVN() || !gvn().is_IterGVN()->delay_transform()) { - gvn().set_type(n, n->bottom_type()); - } - _delay_transform->push(n); + // Delay transform until IterativeGVN + gvn().set_type(n, n->bottom_type()); + C->record_for_igvn(n); return n; } @@ -332,17 +329,6 @@ for (uint i = 0; i < m->req(); i++) m->set_req(i, NULL); } -//-----------------------------drain_delay_transform---------------------------- -void IdealKit::drain_delay_transform() { - while (_delay_transform->length() > 0) { - Node* n = _delay_transform->pop(); - gvn().transform(n); - if (!gvn().is_IterGVN()) { - C->record_for_igvn(n); - } - } -} - //-----------------------------IdealVariable---------------------------- IdealVariable::IdealVariable(IdealKit &k) { k.declare(this); @@ -351,9 +337,7 @@ Node* IdealKit::memory(uint alias_idx) { MergeMemNode* mem = merged_memory(); Node* p = mem->memory_at(alias_idx); - if (!gvn().is_IterGVN() || !gvn().is_IterGVN()->delay_transform()) { - _gvn.set_type(p, Type::MEMORY); // must be mapped - } + _gvn.set_type(p, Type::MEMORY); // must be mapped return p; } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/idealKit.hpp --- a/src/share/vm/opto/idealKit.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/idealKit.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -102,7 +102,6 @@ Compile * const C; PhaseGVN &_gvn; GrowableArray* _pending_cvstates; // stack of cvstates - GrowableArray* _delay_transform; // delay invoking gvn.transform until drain Node* _cvstate; // current cvstate (control, memory and variables) uint _var_ct; // number of variables bool _delay_all_transforms; // flag forcing all transforms to be delayed @@ -121,7 +120,7 @@ void clear(Node* m); // clear a cvstate void stop() { clear(_cvstate); } // clear current cvstate Node* delay_transform(Node* n); - Node* transform(Node* n); // gvn.transform or push node on delay list + Node* transform(Node* n); // gvn.transform or skip it Node* promote_to_phi(Node* n, Node* reg);// Promote "n" to a phi on region "reg" bool was_promoted_to_phi(Node* n, Node* reg) { return (n->is_Phi() && n->in(0) == reg); @@ -146,7 +145,6 @@ IdealKit(GraphKit* gkit, bool delay_all_transforms = false, bool has_declarations = false); ~IdealKit() { stop(); - drain_delay_transform(); } void sync_kit(GraphKit* gkit); @@ -173,7 +171,6 @@ void bind(Node* lab); void goto_(Node* lab, bool bind = false); void declarations_done(); - void drain_delay_transform(); Node* IfTrue(IfNode* iff) { return transform(new (C) IfTrueNode(iff)); } Node* IfFalse(IfNode* iff) { return transform(new (C) IfFalseNode(iff)); } @@ -198,7 +195,11 @@ Node* thread() { return gvn().transform(new (C) ThreadLocalNode()); } // Pointers - Node* AddP(Node *base, Node *ptr, Node *off) { return transform(new (C) AddPNode(base, ptr, off)); } + + // Raw address should be transformed regardless 'delay_transform' flag + // to produce canonical form CastX2P(offset). + Node* AddP(Node *base, Node *ptr, Node *off) { return _gvn.transform(new (C) AddPNode(base, ptr, off)); } + Node* CmpP(Node* l, Node* r) { return transform(new (C) CmpPNode(l, r)); } #ifdef _LP64 Node* XorX(Node* l, Node* r) { return transform(new (C) XorLNode(l, r)); } @@ -208,8 +209,6 @@ Node* URShiftX(Node* l, Node* r) { return transform(new (C) URShiftXNode(l, r)); } Node* ConX(jint k) { return (Node*)gvn().MakeConX(k); } Node* CastPX(Node* ctl, Node* p) { return transform(new (C) CastP2XNode(ctl, p)); } - // Add a fixed offset to a pointer - Node* basic_plus_adr(Node* base, Node* ptr, intptr_t offset); // Memory operations diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/ifg.cpp --- a/src/share/vm/opto/ifg.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/ifg.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -37,8 +37,6 @@ #include "opto/memnode.hpp" #include "opto/opcodes.hpp" -#define EXACT_PRESSURE 1 - //============================================================================= //------------------------------IFG-------------------------------------------- PhaseIFG::PhaseIFG( Arena *arena ) : Phase(Interference_Graph), _arena(arena) { @@ -445,23 +443,15 @@ pressure[1] -= lrg->reg_pressure(); if( pressure[1] == (uint)FLOATPRESSURE ) { hrp_index[1] = where; -#ifdef EXACT_PRESSURE - if( pressure[1] > b->_freg_pressure ) - b->_freg_pressure = pressure[1]+1; -#else - b->_freg_pressure = (uint)FLOATPRESSURE+1; -#endif + if( pressure[1] > b->_freg_pressure ) + b->_freg_pressure = pressure[1]+1; } } else if( lrg->mask().overlap(*Matcher::idealreg2regmask[Op_RegI]) ) { pressure[0] -= lrg->reg_pressure(); if( pressure[0] == (uint)INTPRESSURE ) { hrp_index[0] = where; -#ifdef EXACT_PRESSURE - if( pressure[0] > b->_reg_pressure ) - b->_reg_pressure = pressure[0]+1; -#else - b->_reg_pressure = (uint)INTPRESSURE+1; -#endif + if( pressure[0] > b->_reg_pressure ) + b->_reg_pressure = pressure[0]+1; } } } @@ -526,17 +516,13 @@ if (lrg.mask().is_UP() && lrg.mask_size()) { if (lrg._is_float || lrg._is_vector) { // Count float pressure pressure[1] += lrg.reg_pressure(); -#ifdef EXACT_PRESSURE if( pressure[1] > b->_freg_pressure ) b->_freg_pressure = pressure[1]; -#endif // Count int pressure, but do not count the SP, flags } else if( lrgs(lidx).mask().overlap(*Matcher::idealreg2regmask[Op_RegI]) ) { pressure[0] += lrg.reg_pressure(); -#ifdef EXACT_PRESSURE if( pressure[0] > b->_reg_pressure ) b->_reg_pressure = pressure[0]; -#endif } } } @@ -589,30 +575,20 @@ RegMask itmp = lrgs(r).mask(); itmp.AND(*Matcher::idealreg2regmask[Op_RegI]); int iregs = itmp.Size(); -#ifdef EXACT_PRESSURE if( pressure[0]+iregs > b->_reg_pressure ) b->_reg_pressure = pressure[0]+iregs; -#endif if( pressure[0] <= (uint)INTPRESSURE && pressure[0]+iregs > (uint)INTPRESSURE ) { -#ifndef EXACT_PRESSURE - b->_reg_pressure = (uint)INTPRESSURE+1; -#endif hrp_index[0] = j-1; } // Count the float-only registers RegMask ftmp = lrgs(r).mask(); ftmp.AND(*Matcher::idealreg2regmask[Op_RegD]); int fregs = ftmp.Size(); -#ifdef EXACT_PRESSURE if( pressure[1]+fregs > b->_freg_pressure ) b->_freg_pressure = pressure[1]+fregs; -#endif if( pressure[1] <= (uint)FLOATPRESSURE && pressure[1]+fregs > (uint)FLOATPRESSURE ) { -#ifndef EXACT_PRESSURE - b->_freg_pressure = (uint)FLOATPRESSURE+1; -#endif hrp_index[1] = j-1; } } @@ -769,16 +745,12 @@ if (lrg.mask().is_UP() && lrg.mask_size()) { if (lrg._is_float || lrg._is_vector) { pressure[1] += lrg.reg_pressure(); -#ifdef EXACT_PRESSURE if( pressure[1] > b->_freg_pressure ) b->_freg_pressure = pressure[1]; -#endif } else if( lrg.mask().overlap(*Matcher::idealreg2regmask[Op_RegI]) ) { pressure[0] += lrg.reg_pressure(); -#ifdef EXACT_PRESSURE if( pressure[0] > b->_reg_pressure ) b->_reg_pressure = pressure[0]; -#endif } } assert( pressure[0] == count_int_pressure (&liveout), "" ); @@ -794,21 +766,13 @@ // the whole block is high pressure. if( pressure[0] > (uint)INTPRESSURE ) { hrp_index[0] = 0; -#ifdef EXACT_PRESSURE if( pressure[0] > b->_reg_pressure ) b->_reg_pressure = pressure[0]; -#else - b->_reg_pressure = (uint)INTPRESSURE+1; -#endif } if( pressure[1] > (uint)FLOATPRESSURE ) { hrp_index[1] = 0; -#ifdef EXACT_PRESSURE if( pressure[1] > b->_freg_pressure ) b->_freg_pressure = pressure[1]; -#else - b->_freg_pressure = (uint)FLOATPRESSURE+1; -#endif } // Compute high pressure indice; avoid landing in the middle of projnodes diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/library_call.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -231,7 +231,6 @@ void copy_to_clone(Node* obj, Node* alloc_obj, Node* obj_size, bool is_array, bool card_mark); bool inline_native_clone(bool is_virtual); bool inline_native_Reflection_getCallerClass(); - bool is_method_invoke_or_aux_frame(JVMState* jvms); // Helper function for inlining native object hash method bool inline_native_hashcode(bool is_virtual, bool is_static); bool inline_native_getClass(); @@ -393,7 +392,7 @@ case vmIntrinsics::_getCallerClass: if (!UseNewReflection) return NULL; if (!InlineReflectionGetCallerClass) return NULL; - if (!JDK_Version::is_gte_jdk14x_version()) return NULL; + if (SystemDictionary::reflect_CallerSensitive_klass() == NULL) return NULL; break; case vmIntrinsics::_bitCount_i: @@ -3872,13 +3871,13 @@ } //-----------------inline_native_Reflection_getCallerClass--------------------- -// public static native Class sun.reflect.Reflection.getCallerClass(int realFramesToSkip); +// public static native Class sun.reflect.Reflection.getCallerClass(); // // In the presence of deep enough inlining, getCallerClass() becomes a no-op. // -// NOTE that this code must perform the same logic as -// vframeStream::security_get_caller_frame in that it must skip -// Method.invoke() and auxiliary frames. +// NOTE: This code must perform the same logic as JVM_GetCallerClass +// in that it must skip particular security frames and checks for +// caller sensitive methods. bool LibraryCallKit::inline_native_Reflection_getCallerClass() { #ifndef PRODUCT if ((PrintIntrinsics || PrintInlining || PrintOptoInlining) && Verbose) { @@ -3886,35 +3885,6 @@ } #endif - Node* caller_depth_node = argument(0); - - // The depth value must be a constant in order for the runtime call - // to be eliminated. - const TypeInt* caller_depth_type = _gvn.type(caller_depth_node)->isa_int(); - if (caller_depth_type == NULL || !caller_depth_type->is_con()) { -#ifndef PRODUCT - if ((PrintIntrinsics || PrintInlining || PrintOptoInlining) && Verbose) { - tty->print_cr(" Bailing out because caller depth was not a constant"); - } -#endif - return false; - } - // Note that the JVM state at this point does not include the - // getCallerClass() frame which we are trying to inline. The - // semantics of getCallerClass(), however, are that the "first" - // frame is the getCallerClass() frame, so we subtract one from the - // requested depth before continuing. We don't inline requests of - // getCallerClass(0). - int caller_depth = caller_depth_type->get_con() - 1; - if (caller_depth < 0) { -#ifndef PRODUCT - if ((PrintIntrinsics || PrintInlining || PrintOptoInlining) && Verbose) { - tty->print_cr(" Bailing out because caller depth was %d", caller_depth); - } -#endif - return false; - } - if (!jvms()->has_method()) { #ifndef PRODUCT if ((PrintIntrinsics || PrintInlining || PrintOptoInlining) && Verbose) { @@ -3923,96 +3893,67 @@ #endif return false; } - int _depth = jvms()->depth(); // cache call chain depth // Walk back up the JVM state to find the caller at the required - // depth. NOTE that this code must perform the same logic as - // vframeStream::security_get_caller_frame in that it must skip - // Method.invoke() and auxiliary frames. Note also that depth is - // 1-based (1 is the bottom of the inlining). - int inlining_depth = _depth; - JVMState* caller_jvms = NULL; - - if (inlining_depth > 0) { - caller_jvms = jvms(); - assert(caller_jvms = jvms()->of_depth(inlining_depth), "inlining_depth == our depth"); - do { - // The following if-tests should be performed in this order - if (is_method_invoke_or_aux_frame(caller_jvms)) { - // Skip a Method.invoke() or auxiliary frame - } else if (caller_depth > 0) { - // Skip real frame - --caller_depth; - } else { - // We're done: reached desired caller after skipping. - break; + // depth. + JVMState* caller_jvms = jvms(); + + // Cf. JVM_GetCallerClass + // NOTE: Start the loop at depth 1 because the current JVM state does + // not include the Reflection.getCallerClass() frame. + for (int n = 1; caller_jvms != NULL; caller_jvms = caller_jvms->caller(), n++) { + ciMethod* m = caller_jvms->method(); + switch (n) { + case 0: + fatal("current JVM state does not include the Reflection.getCallerClass frame"); + break; + case 1: + // Frame 0 and 1 must be caller sensitive (see JVM_GetCallerClass). + if (!m->caller_sensitive()) { +#ifndef PRODUCT + if ((PrintIntrinsics || PrintInlining || PrintOptoInlining) && Verbose) { + tty->print_cr(" Bailing out: CallerSensitive annotation expected at frame %d", n); + } +#endif + return false; // bail-out; let JVM_GetCallerClass do the work } - caller_jvms = caller_jvms->caller(); - --inlining_depth; - } while (inlining_depth > 0); - } - - if (inlining_depth == 0) { + break; + default: + if (!m->is_ignored_by_security_stack_walk()) { + // We have reached the desired frame; return the holder class. + // Acquire method holder as java.lang.Class and push as constant. + ciInstanceKlass* caller_klass = caller_jvms->method()->holder(); + ciInstance* caller_mirror = caller_klass->java_mirror(); + set_result(makecon(TypeInstPtr::make(caller_mirror))); + #ifndef PRODUCT - if ((PrintIntrinsics || PrintInlining || PrintOptoInlining) && Verbose) { - tty->print_cr(" Bailing out because caller depth (%d) exceeded inlining depth (%d)", caller_depth_type->get_con(), _depth); - tty->print_cr(" JVM state at this point:"); - for (int i = _depth; i >= 1; i--) { - ciMethod* m = jvms()->of_depth(i)->method(); - tty->print_cr(" %d) %s.%s", i, m->holder()->name()->as_utf8(), m->name()->as_utf8()); - } - } + if ((PrintIntrinsics || PrintInlining || PrintOptoInlining) && Verbose) { + tty->print_cr(" Succeeded: caller = %d) %s.%s, JVMS depth = %d", n, caller_klass->name()->as_utf8(), caller_jvms->method()->name()->as_utf8(), jvms()->depth()); + tty->print_cr(" JVM state at this point:"); + for (int i = jvms()->depth(), n = 1; i >= 1; i--, n++) { + ciMethod* m = jvms()->of_depth(i)->method(); + tty->print_cr(" %d) %s.%s", n, m->holder()->name()->as_utf8(), m->name()->as_utf8()); + } + } #endif - return false; // Reached end of inlining + return true; + } + break; + } } - // Acquire method holder as java.lang.Class - ciInstanceKlass* caller_klass = caller_jvms->method()->holder(); - ciInstance* caller_mirror = caller_klass->java_mirror(); - - // Push this as a constant - set_result(makecon(TypeInstPtr::make(caller_mirror))); - #ifndef PRODUCT if ((PrintIntrinsics || PrintInlining || PrintOptoInlining) && Verbose) { - tty->print_cr(" Succeeded: caller = %s.%s, caller depth = %d, depth = %d", caller_klass->name()->as_utf8(), caller_jvms->method()->name()->as_utf8(), caller_depth_type->get_con(), _depth); + tty->print_cr(" Bailing out because caller depth exceeded inlining depth = %d", jvms()->depth()); tty->print_cr(" JVM state at this point:"); - for (int i = _depth; i >= 1; i--) { + for (int i = jvms()->depth(), n = 1; i >= 1; i--, n++) { ciMethod* m = jvms()->of_depth(i)->method(); - tty->print_cr(" %d) %s.%s", i, m->holder()->name()->as_utf8(), m->name()->as_utf8()); + tty->print_cr(" %d) %s.%s", n, m->holder()->name()->as_utf8(), m->name()->as_utf8()); } } #endif - return true; -} - -// Helper routine for above -bool LibraryCallKit::is_method_invoke_or_aux_frame(JVMState* jvms) { - ciMethod* method = jvms->method(); - - // Is this the Method.invoke method itself? - if (method->intrinsic_id() == vmIntrinsics::_invoke) - return true; - - // Is this a helper, defined somewhere underneath MethodAccessorImpl. - ciKlass* k = method->holder(); - if (k->is_instance_klass()) { - ciInstanceKlass* ik = k->as_instance_klass(); - for (; ik != NULL; ik = ik->super()) { - if (ik->name() == ciSymbol::sun_reflect_MethodAccessorImpl() && - ik == env()->find_system_klass(ik->name())) { - return true; - } - } - } - - if (method->is_method_handle_intrinsic() || - method->is_compiled_lambda_form()) { - // This is an internal adapter frame from the MethodHandleCompiler -- skip it - return true; - } - - return false; + + return false; // bail-out; let JVM_GetCallerClass do the work } bool LibraryCallKit::inline_fp_conversions(vmIntrinsics::ID id) { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/loopTransform.cpp --- a/src/share/vm/opto/loopTransform.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/loopTransform.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -888,6 +888,7 @@ 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 @@ 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 @@ 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 @@ Node* n = lpt->_body.at(i); // These values can be replaced with other nodes if they are used // outside the loop. - if (n == store || n == head->loopexit() || n == head->incr() || n == store->in(MemNode::Memory)) continue; + if (n == store || n == loop_exit || n == head->incr() || n == store->in(MemNode::Memory)) continue; for (SimpleDUIterator iter(n); iter.has_next(); iter.next()) { Node* use = iter.get(); if (!lpt->_body.contains(use)) { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/loopnode.cpp --- a/src/share/vm/opto/loopnode.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/loopnode.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -2251,6 +2251,11 @@ return; } + // clear out the dead code after build_loop_late + while (_deadlist.size()) { + _igvn.remove_globally_dead_node(_deadlist.pop()); + } + if (stop_early) { assert(do_expensive_nodes, "why are we here?"); if (process_expensive_nodes()) { @@ -2260,9 +2265,7 @@ // nodes again. C->set_major_progress(); } - _igvn.optimize(); - return; } @@ -2273,11 +2276,6 @@ eliminate_useless_predicates(); } - // clear out the dead code - while(_deadlist.size()) { - _igvn.remove_globally_dead_node(_deadlist.pop()); - } - #ifndef PRODUCT C->verify_graph_edges(); if (_verify_me) { // Nested verify pass? diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/loopnode.hpp --- a/src/share/vm/opto/loopnode.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/loopnode.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -603,7 +603,10 @@ } 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 @@ return n; } uint dom_depth(Node* d) const { - assert(d->_idx < _idom_size, ""); + guarantee(d != NULL, "Null dominator info."); + guarantee(d->_idx < _idom_size, ""); return _dom_depth[d->_idx]; } void set_idom(Node* d, Node* n, uint dom_depth); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/loopopts.cpp --- a/src/share/vm/opto/loopopts.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/loopopts.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -232,7 +232,11 @@ // 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 @@ // 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 @@ //------------------------------ 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 @@ 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 @@ 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 @@ } // Create a new region on the exit path RegionNode* reg = insert_region_before_proj(lp_exit); + guarantee(reg != NULL, "null region node"); // Clone the if-cmpu-true-false using a signed compare BoolTest::mask rel_i = stride > 0 ? bol->_test._test : BoolTest::ge; diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/output.cpp --- a/src/share/vm/opto/output.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/output.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -449,6 +449,17 @@ int max_loop_pad = nb->code_alignment()-relocInfo::addr_unit(); if (max_loop_pad > 0) { assert(is_power_of_2(max_loop_pad+relocInfo::addr_unit()), ""); + // Adjust last_call_adr and/or last_avoid_back_to_back_adr. + // If either is the last instruction in this block, bump by + // max_loop_pad in lock-step with blk_size, so sizing + // calculations in subsequent blocks still can conservatively + // detect that it may the last instruction in this block. + if (last_call_adr == blk_starts[i]+blk_size) { + last_call_adr += max_loop_pad; + } + if (last_avoid_back_to_back_adr == blk_starts[i]+blk_size) { + last_avoid_back_to_back_adr += max_loop_pad; + } blk_size += max_loop_pad; } } @@ -1193,8 +1204,6 @@ int last_call_offset = -1; int last_avoid_back_to_back_offset = -1; #ifdef ASSERT - int block_alignment_padding = 0; - uint* jmp_target = NEW_RESOURCE_ARRAY(uint,nblocks); uint* jmp_offset = NEW_RESOURCE_ARRAY(uint,nblocks); uint* jmp_size = NEW_RESOURCE_ARRAY(uint,nblocks); @@ -1228,8 +1237,6 @@ Node *delay_slot = NULL; for (uint i=0; i < nblocks; i++) { - guarantee(blk_starts[i] >= (uint)cb->insts_size(),"should not increase size"); - Block *b = _cfg->_blocks[i]; Node *head = b->head(); @@ -1250,14 +1257,6 @@ jmp_offset[i] = 0; jmp_size[i] = 0; jmp_rule[i] = 0; - - // Maximum alignment padding for loop block was used - // during first round of branches shortening, as result - // padding for nodes (sfpt after call) was not added. - // Take this into account for block's size change check - // and allow increase block's size by the difference - // of maximum and actual alignment paddings. - int orig_blk_size = blk_starts[i+1] - blk_starts[i] + block_alignment_padding; #endif int blk_offset = current_offset; @@ -1557,8 +1556,6 @@ } } // End for all instructions in block - assert((uint)blk_offset <= blk_starts[i], "shouldn't increase distance"); - blk_starts[i] = blk_offset; // If the next block is the top of a loop, pad this block out to align // the loop top a little. Helps prevent pipe stalls at loop back branches. @@ -1572,16 +1569,13 @@ nop->emit(*cb, _regalloc); current_offset = cb->insts_size(); } -#ifdef ASSERT - int max_loop_pad = nb->code_alignment()-relocInfo::addr_unit(); - block_alignment_padding = (max_loop_pad - padding); - assert(block_alignment_padding >= 0, "sanity"); -#endif } // Verify that the distance for generated before forward // short branches is still valid. - assert(orig_blk_size >= (current_offset - blk_offset), "shouldn't increase block size"); - + guarantee((int)(blk_starts[i+1] - blk_starts[i]) >= (current_offset - blk_offset), "shouldn't increase block size"); + + // Save new block start offset + blk_starts[i] = blk_offset; } // End of for all blocks blk_starts[nblocks] = current_offset; @@ -2518,6 +2512,7 @@ // Schedule the remaining instructions in the block while ( _available.size() > 0 ) { Node *n = ChooseNodeToBundle(); + guarantee(n != NULL, "no nodes available"); AddNodeToBundle(n,bb); } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/parse2.cpp --- a/src/share/vm/opto/parse2.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/parse2.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -104,7 +104,8 @@ if (C->log() != NULL) C->log()->elem("observe that='!need_range_check'"); } - if (!arytype->klass()->is_loaded()) { + ciKlass * arytype_klass = arytype->klass(); + if ((arytype_klass != NULL) && (!arytype_klass->is_loaded())) { // Only fails for some -Xcomp runs // The class is unloaded. We have to run this bytecode in the interpreter. uncommon_trap(Deoptimization::Reason_unloaded, @@ -1385,6 +1386,7 @@ if (TraceOptoParse) { tty->print(" @"); dump_bci(bci()); + tty->cr(); } #endif diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/phaseX.cpp --- a/src/share/vm/opto/phaseX.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/phaseX.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -1166,31 +1166,30 @@ if (progress_state == PROCESS_INPUTS) { // After following inputs, continue to outputs _stack.set_index(PROCESS_OUTPUTS); - // Remove from iterative worklist - _worklist.remove(dead); if (!dead->is_Con()) { // Don't kill cons but uses bool recurse = false; // Remove from hash table _table.hash_delete( dead ); // Smash all inputs to 'dead', isolating him completely - for( uint i = 0; i < dead->req(); i++ ) { + for (uint i = 0; i < dead->req(); i++) { Node *in = dead->in(i); - if( in ) { // Points to something? - dead->set_req(i,NULL); // Kill the edge - if (in->outcnt() == 0 && in != C->top()) {// Made input go dead? + if (in != NULL && in != C->top()) { // Points to something? + int nrep = dead->replace_edge(in, NULL); // Kill edges + assert((nrep > 0), "sanity"); + if (in->outcnt() == 0) { // Made input go dead? _stack.push(in, PROCESS_INPUTS); // Recursively remove recurse = true; } else if (in->outcnt() == 1 && in->has_special_unique_user()) { _worklist.push(in->unique_out()); } else if (in->outcnt() <= 2 && dead->is_Phi()) { - if( in->Opcode() == Op_Region ) + if (in->Opcode() == Op_Region) { _worklist.push(in); - else if( in->is_Store() ) { + } else if (in->is_Store()) { DUIterator_Fast imax, i = in->fast_outs(imax); _worklist.push(in->fast_out(i)); i++; - if(in->outcnt() == 2) { + if (in->outcnt() == 2) { _worklist.push(in->fast_out(i)); i++; } @@ -1209,38 +1208,42 @@ } } } - } - } - C->record_dead_node(dead->_idx); - if (dead->is_macro()) { - C->remove_macro_node(dead); - } - if (dead->is_expensive()) { - C->remove_expensive_node(dead); - } - + } // if (in != NULL && in != C->top()) + } // for (uint i = 0; i < dead->req(); i++) if (recurse) { continue; } - } - // Constant node that has no out-edges and has only one in-edge from - // root is usually dead. However, sometimes reshaping walk makes - // it reachable by adding use edges. So, we will NOT count Con nodes - // as dead to be conservative about the dead node count at any - // given time. - } + } // if (!dead->is_Con()) + } // if (progress_state == PROCESS_INPUTS) // Aggressively kill globally dead uses // (Rather than pushing all the outs at once, we push one at a time, // plus the parent to resume later, because of the indefinite number // of edge deletions per loop trip.) if (dead->outcnt() > 0) { - // Recursively remove + // Recursively remove output edges _stack.push(dead->raw_out(0), PROCESS_INPUTS); } else { + // Finished disconnecting all input and output edges. _stack.pop(); + // Remove dead node from iterative worklist + _worklist.remove(dead); + // Constant node that has no out-edges and has only one in-edge from + // root is usually dead. However, sometimes reshaping walk makes + // it reachable by adding use edges. So, we will NOT count Con nodes + // as dead to be conservative about the dead node count at any + // given time. + if (!dead->is_Con()) { + C->record_dead_node(dead->_idx); + } + if (dead->is_macro()) { + C->remove_macro_node(dead); + } + if (dead->is_expensive()) { + C->remove_expensive_node(dead); + } } - } + } // while (_stack.is_nonempty()) } //------------------------------subsume_node----------------------------------- diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/subnode.cpp --- a/src/share/vm/opto/subnode.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/subnode.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -1078,16 +1078,6 @@ return (_test._test == b->_test._test); } -//------------------------------clone_cmp-------------------------------------- -// Clone a compare/bool tree -static Node *clone_cmp( Node *cmp, Node *cmp1, Node *cmp2, PhaseGVN *gvn, BoolTest::mask test ) { - Node *ncmp = cmp->clone(); - ncmp->set_req(1,cmp1); - ncmp->set_req(2,cmp2); - ncmp = gvn->transform( ncmp ); - return new (gvn->C) BoolNode( ncmp, test ); -} - //-------------------------------make_predicate-------------------------------- Node* BoolNode::make_predicate(Node* test_value, PhaseGVN* phase) { if (test_value->is_Con()) return test_value; diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/opto/type.cpp --- a/src/share/vm/opto/type.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/opto/type.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -4193,6 +4193,7 @@ bool xk = klass_is_exact(); //return TypeInstPtr::make(TypePtr::NotNull, k, xk, NULL, 0); const TypeOopPtr* toop = TypeOopPtr::make_from_klass_raw(k); + guarantee(toop != NULL, "need type for given klass"); toop = toop->cast_to_ptr_type(TypePtr::NotNull)->is_oopptr(); return toop->cast_to_exactness(xk)->is_oopptr(); } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/prims/jni.cpp --- a/src/share/vm/prims/jni.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/prims/jni.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -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 @@ -1289,32 +1289,6 @@ JNI_NONVIRTUAL }; -static methodHandle jni_resolve_interface_call(Handle recv, methodHandle method, TRAPS) { - assert(!method.is_null() , "method should not be null"); - - KlassHandle recv_klass; // Default to NULL (use of ?: can confuse gcc) - if (recv.not_null()) recv_klass = KlassHandle(THREAD, recv->klass()); - KlassHandle spec_klass (THREAD, method->method_holder()); - Symbol* name = method->name(); - Symbol* signature = method->signature(); - CallInfo info; - LinkResolver::resolve_interface_call(info, recv, recv_klass, spec_klass, name, signature, KlassHandle(), false, true, CHECK_(methodHandle())); - return info.selected_method(); -} - -static methodHandle jni_resolve_virtual_call(Handle recv, methodHandle method, TRAPS) { - assert(!method.is_null() , "method should not be null"); - - KlassHandle recv_klass; // Default to NULL (use of ?: can confuse gcc) - if (recv.not_null()) recv_klass = KlassHandle(THREAD, recv->klass()); - KlassHandle spec_klass (THREAD, method->method_holder()); - Symbol* name = method->name(); - Symbol* signature = method->signature(); - CallInfo info; - LinkResolver::resolve_virtual_call(info, recv, recv_klass, spec_klass, name, signature, KlassHandle(), false, true, CHECK_(methodHandle())); - return info.selected_method(); -} - static void jni_invoke_static(JNIEnv *env, JavaValue* result, jobject receiver, JNICallType call_type, jmethodID method_id, JNI_ArgumentPusher *args, TRAPS) { @@ -5053,6 +5027,7 @@ void execute_internal_vm_tests() { if (ExecuteInternalVMTests) { tty->print_cr("Running internal VM tests"); + run_unit_test(GlobalDefinitions::test_globals()); run_unit_test(arrayOopDesc::test_max_array_length()); run_unit_test(CollectedHeap::test_is_in()); run_unit_test(QuickSort::test_quick_sort()); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/prims/jni.h --- a/src/share/vm/prims/jni.h Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/prims/jni.h Fri Apr 12 10:14:42 2013 +0100 @@ -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 @@ #define JNI_VERSION_1_2 0x00010002 #define JNI_VERSION_1_4 0x00010004 #define JNI_VERSION_1_6 0x00010006 +#define JNI_VERSION_1_8 0x00010008 #ifdef __cplusplus } /* extern "C" */ diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/prims/jniCheck.hpp --- a/src/share/vm/prims/jniCheck.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/prims/jniCheck.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -33,7 +33,7 @@ // within IN_VM macro), one to be called when in NATIVE state. // When in VM state: - static void ReportJNIFatalError(JavaThread* thr, const char *msg) { + static inline void ReportJNIFatalError(JavaThread* thr, const char *msg) { tty->print_cr("FATAL ERROR in native method: %s", msg); thr->print_stack(); os::abort(true); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/prims/jvm.cpp --- a/src/share/vm/prims/jvm.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/prims/jvm.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -30,6 +30,7 @@ #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "gc_interface/collectedHeap.inline.hpp" +#include "interpreter/bytecode.hpp" #include "memory/oopFactory.hpp" #include "memory/universe.inline.hpp" #include "oops/fieldStreams.hpp" @@ -665,8 +666,51 @@ JVM_ENTRY(jclass, JVM_GetCallerClass(JNIEnv* env, int depth)) JVMWrapper("JVM_GetCallerClass"); - Klass* k = thread->security_get_caller_class(depth); - return (k == NULL) ? NULL : (jclass) JNIHandles::make_local(env, k->java_mirror()); + + // Pre-JDK 8 and early builds of JDK 8 don't have a CallerSensitive annotation. + if (SystemDictionary::reflect_CallerSensitive_klass() == NULL) { + Klass* k = thread->security_get_caller_class(depth); + return (k == NULL) ? NULL : (jclass) JNIHandles::make_local(env, k->java_mirror()); + } else { + // Basic handshaking with Java_sun_reflect_Reflection_getCallerClass + assert(depth == -1, "wrong handshake depth"); + } + + // Getting the class of the caller frame. + // + // The call stack at this point looks something like this: + // + // [0] [ @CallerSensitive public sun.reflect.Reflection.getCallerClass ] + // [1] [ @CallerSensitive API.method ] + // [.] [ (skipped intermediate frames) ] + // [n] [ caller ] + vframeStream vfst(thread); + // Cf. LibraryCallKit::inline_native_Reflection_getCallerClass + for (int n = 0; !vfst.at_end(); vfst.security_next(), n++) { + Method* m = vfst.method(); + assert(m != NULL, "sanity"); + switch (n) { + case 0: + // This must only be called from Reflection.getCallerClass + if (m->intrinsic_id() != vmIntrinsics::_getCallerClass) { + THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "JVM_GetCallerClass must only be called from Reflection.getCallerClass"); + } + // fall-through + case 1: + // Frame 0 and 1 must be caller sensitive. + if (!m->caller_sensitive()) { + THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), err_msg("CallerSensitive annotation expected at frame %d", n)); + } + break; + default: + if (!m->is_ignored_by_security_stack_walk()) { + // We have reached the desired frame; return the holder class. + return (jclass) JNIHandles::make_local(env, m->method_holder()->java_mirror()); + } + break; + } + } + return NULL; JVM_END @@ -1457,7 +1501,7 @@ JVM_ENTRY(jbyteArray, JVM_GetClassAnnotations(JNIEnv *env, jclass cls)) assert (cls != NULL, "illegal class"); JVMWrapper("JVM_GetClassAnnotations"); - ResourceMark rm(THREAD); + // Return null for arrays and primitives if (!java_lang_Class::is_primitive(JNIHandles::resolve(cls))) { Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve(cls)); @@ -1470,20 +1514,15 @@ JVM_END -JVM_ENTRY(jbyteArray, JVM_GetFieldAnnotations(JNIEnv *env, jobject field)) - assert(field != NULL, "illegal field"); - JVMWrapper("JVM_GetFieldAnnotations"); - +static bool jvm_get_field_common(jobject field, fieldDescriptor& fd, TRAPS) { // some of this code was adapted from from jni_FromReflectedField - // field is a handle to a java.lang.reflect.Field object oop reflected = JNIHandles::resolve_non_null(field); oop mirror = java_lang_reflect_Field::clazz(reflected); Klass* k = java_lang_Class::as_Klass(mirror); int slot = java_lang_reflect_Field::slot(reflected); int modifiers = java_lang_reflect_Field::modifiers(reflected); - fieldDescriptor fd; KlassHandle kh(THREAD, k); intptr_t offset = InstanceKlass::cast(kh())->field_offset(slot); @@ -1491,16 +1530,29 @@ // for static fields we only look in the current class if (!InstanceKlass::cast(kh())->find_local_field_from_offset(offset, true, &fd)) { assert(false, "cannot find static field"); - return NULL; // robustness + return false; } } else { // for instance fields we start with the current class and work // our way up through the superclass chain if (!InstanceKlass::cast(kh())->find_field_from_offset(offset, false, &fd)) { assert(false, "cannot find instance field"); - return NULL; // robustness + return false; } } + return true; +} + +JVM_ENTRY(jbyteArray, JVM_GetFieldAnnotations(JNIEnv *env, jobject field)) + // field is a handle to a java.lang.reflect.Field object + assert(field != NULL, "illegal field"); + JVMWrapper("JVM_GetFieldAnnotations"); + + fieldDescriptor fd; + bool gotFd = jvm_get_field_common(field, fd, CHECK_NULL); + if (!gotFd) { + return NULL; + } return (jbyteArray) JNIHandles::make_local(env, Annotations::make_java_array(fd.annotations(), THREAD)); JVM_END @@ -1525,12 +1577,8 @@ Klass* k = java_lang_Class::as_Klass(mirror); Method* m = InstanceKlass::cast(k)->method_with_idnum(slot); - if (m == NULL) { - assert(false, "cannot find method"); - return NULL; // robustness - } - - return m; + assert(m != NULL, "cannot find method"); + return m; // caller has to deal with NULL in product mode } @@ -1539,6 +1587,10 @@ // method is a handle to a java.lang.reflect.Method object Method* m = jvm_get_method_common(method); + if (m == NULL) { + return NULL; + } + return (jbyteArray) JNIHandles::make_local(env, Annotations::make_java_array(m->annotations(), THREAD)); JVM_END @@ -1549,6 +1601,10 @@ // method is a handle to a java.lang.reflect.Method object Method* m = jvm_get_method_common(method); + if (m == NULL) { + return NULL; + } + return (jbyteArray) JNIHandles::make_local(env, Annotations::make_java_array(m->annotation_default(), THREAD)); JVM_END @@ -1559,6 +1615,10 @@ // method is a handle to a java.lang.reflect.Method object Method* m = jvm_get_method_common(method); + if (m == NULL) { + return NULL; + } + return (jbyteArray) JNIHandles::make_local(env, Annotations::make_java_array(m->parameter_annotations(), THREAD)); JVM_END @@ -1583,6 +1643,38 @@ return NULL; JVM_END +JVM_ENTRY(jbyteArray, JVM_GetMethodTypeAnnotations(JNIEnv *env, jobject method)) + assert (method != NULL, "illegal method"); + JVMWrapper("JVM_GetMethodTypeAnnotations"); + + // method is a handle to a java.lang.reflect.Method object + Method* m = jvm_get_method_common(method); + if (m == NULL) { + return NULL; + } + + AnnotationArray* type_annotations = m->type_annotations(); + if (type_annotations != NULL) { + typeArrayOop a = Annotations::make_java_array(type_annotations, CHECK_NULL); + return (jbyteArray) JNIHandles::make_local(env, a); + } + + return NULL; +JVM_END + +JVM_ENTRY(jbyteArray, JVM_GetFieldTypeAnnotations(JNIEnv *env, jobject field)) + assert (field != NULL, "illegal field"); + JVMWrapper("JVM_GetFieldTypeAnnotations"); + + fieldDescriptor fd; + bool gotFd = jvm_get_field_common(field, fd, CHECK_NULL); + if (!gotFd) { + return NULL; + } + + return (jbyteArray) JNIHandles::make_local(env, Annotations::make_java_array(fd.type_annotations(), THREAD)); +JVM_END + static void bounds_check(constantPoolHandle cp, jint index, TRAPS) { if (!cp->is_within_bounds(index)) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Constant pool index out of bounds"); @@ -1722,7 +1814,7 @@ int i; for (i = 0; i < methods_length; i++) { methodHandle method(THREAD, methods->at(i)); - if (!method->is_initializer()) { + if (!method->is_initializer() && !method->is_overpass()) { if (!publicOnly || method->is_public()) { ++num_methods; } @@ -1736,7 +1828,7 @@ int out_idx = 0; for (i = 0; i < methods_length; i++) { methodHandle method(THREAD, methods->at(i)); - if (!method->is_initializer()) { + if (!method->is_initializer() && !method->is_overpass()) { if (!publicOnly || method->is_public()) { oop m = Reflection::new_method(method, UseNewReflection, false, CHECK_NULL); result->obj_at_put(out_idx, m); @@ -3160,11 +3252,24 @@ KlassLink* first = NULL; KlassLink* last = NULL; int depth = 0; - - for(vframeStream vfst(thread); !vfst.at_end(); vfst.security_get_caller_frame(1)) { + vframeStream vfst(thread); + + if (SystemDictionary::reflect_CallerSensitive_klass() != NULL) { + // This must only be called from SecurityManager.getClassContext + Method* m = vfst.method(); + if (!(m->method_holder() == SystemDictionary::SecurityManager_klass() && + m->name() == vmSymbols::getClassContext_name() && + m->signature() == vmSymbols::void_class_array_signature())) { + THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "JVM_GetClassContext must only be called from SecurityManager.getClassContext"); + } + } + + // Collect method holders + for (; !vfst.at_end(); vfst.security_next()) { + Method* m = vfst.method(); // Native frames are not returned - if (!vfst.method()->is_native()) { - Klass* holder = vfst.method()->method_holder(); + if (!m->is_ignored_by_security_stack_walk() && !m->is_native()) { + Klass* holder = m->method_holder(); assert(holder->is_klass(), "just checking"); depth++; KlassLink* l = new KlassLink(KlassHandle(thread, holder)); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/prims/jvm.h --- a/src/share/vm/prims/jvm.h Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/prims/jvm.h Fri Apr 12 10:14:42 2013 +0100 @@ -523,6 +523,14 @@ JNIEXPORT jbyteArray JNICALL JVM_GetClassTypeAnnotations(JNIEnv *env, jclass cls); +// field is a handle to a java.lang.reflect.Field object +JNIEXPORT jbyteArray JNICALL +JVM_GetFieldTypeAnnotations(JNIEnv *env, jobject field); + +// method is a handle to a java.lang.reflect.Method object +JNIEXPORT jbyteArray JNICALL +JVM_GetMethodTypeAnnotations(JNIEnv *env, jobject method); + /* * New (JDK 1.4) reflection implementation */ diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/prims/jvmtiEventController.cpp --- a/src/share/vm/prims/jvmtiEventController.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/prims/jvmtiEventController.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -39,7 +39,12 @@ #include "runtime/vm_operations.hpp" #ifdef JVMTI_TRACE -#define EC_TRACE(out) if (JvmtiTrace::trace_event_controller()) { SafeResourceMark rm; tty->print_cr out; } while (0) +#define EC_TRACE(out) do { \ + if (JvmtiTrace::trace_event_controller()) { \ + SafeResourceMark rm; \ + tty->print_cr out; \ + } \ +} while (0) #else #define EC_TRACE(out) #endif /*JVMTI_TRACE */ diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/prims/jvmtiRedefineClassesTrace.hpp --- a/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -72,36 +72,6 @@ // 0x20000000 | 536870912 - unused // 0x40000000 | 1073741824 - unused // 0x80000000 | 2147483648 - unused -// -// Note: The ResourceMark is to cleanup resource allocated args. -// The "while (0)" is so we can use semi-colon at end of RC_TRACE(). -#define RC_TRACE(level, args) \ - if ((TraceRedefineClasses & level) != 0) { \ - ResourceMark rm; \ - tty->print("RedefineClasses-0x%x: ", level); \ - tty->print_cr args; \ - } while (0) - -#define RC_TRACE_NO_CR(level, args) \ - if ((TraceRedefineClasses & level) != 0) { \ - ResourceMark rm; \ - tty->print("RedefineClasses-0x%x: ", level); \ - tty->print args; \ - } while (0) - -#define RC_TRACE_WITH_THREAD(level, thread, args) \ - if ((TraceRedefineClasses & level) != 0) { \ - ResourceMark rm(thread); \ - tty->print("RedefineClasses-0x%x: ", level); \ - tty->print_cr args; \ - } while (0) - -#define RC_TRACE_MESG(args) \ - { \ - ResourceMark rm; \ - tty->print("RedefineClasses: "); \ - tty->print_cr args; \ - } while (0) // Macro for checking if TraceRedefineClasses has a specific bit // enabled. Returns true if the bit specified by level is set. @@ -120,16 +90,49 @@ #define RC_TRACE_IN_RANGE(low, high) \ (((TraceRedefineClasses & ((high << 1) - 1)) & ~(low - 1)) != 0) -// Timer support macros. Only do timer operations if timer tracing -// is enabled. The "while (0)" is so we can use semi-colon at end of -// the macro. -#define RC_TIMER_START(t) \ +// Note: The ResourceMark is to cleanup resource allocated args. +// The "do {...} while (0)" is so we can use semi-colon at end of RC_TRACE(). +#define RC_TRACE(level, args) do { \ + if (RC_TRACE_ENABLED(level)) { \ + ResourceMark rm; \ + tty->print("RedefineClasses-0x%x: ", level); \ + tty->print_cr args; \ + } \ +} while (0) + +#define RC_TRACE_NO_CR(level, args) do { \ + if (RC_TRACE_ENABLED(level)) { \ + ResourceMark rm; \ + tty->print("RedefineClasses-0x%x: ", level); \ + tty->print args; \ + } \ +} while (0) + +#define RC_TRACE_WITH_THREAD(level, thread, args) do { \ + if (RC_TRACE_ENABLED(level)) { \ + ResourceMark rm(thread); \ + tty->print("RedefineClasses-0x%x: ", level); \ + tty->print_cr args; \ + } \ +} while (0) + +#define RC_TRACE_MESG(args) do { \ + ResourceMark rm; \ + tty->print("RedefineClasses: "); \ + tty->print_cr args; \ +} while (0) + +// Timer support macros. Only do timer operations if timer tracing is enabled. +// The "do {...} while (0)" is so we can use semi-colon at end of the macro. +#define RC_TIMER_START(t) do { \ if (RC_TRACE_ENABLED(0x00000004)) { \ t.start(); \ - } while (0) -#define RC_TIMER_STOP(t) \ + } \ +} while (0) +#define RC_TIMER_STOP(t) do { \ if (RC_TRACE_ENABLED(0x00000004)) { \ t.stop(); \ - } while (0) + } \ +} while (0) #endif // SHARE_VM_PRIMS_JVMTIREDEFINECLASSESTRACE_HPP diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/prims/methodHandles.cpp --- a/src/share/vm/prims/methodHandles.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/prims/methodHandles.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -105,14 +105,15 @@ // import java_lang_invoke_MemberName.* enum { - IS_METHOD = java_lang_invoke_MemberName::MN_IS_METHOD, - IS_CONSTRUCTOR = java_lang_invoke_MemberName::MN_IS_CONSTRUCTOR, - IS_FIELD = java_lang_invoke_MemberName::MN_IS_FIELD, - IS_TYPE = java_lang_invoke_MemberName::MN_IS_TYPE, + IS_METHOD = java_lang_invoke_MemberName::MN_IS_METHOD, + IS_CONSTRUCTOR = java_lang_invoke_MemberName::MN_IS_CONSTRUCTOR, + IS_FIELD = java_lang_invoke_MemberName::MN_IS_FIELD, + IS_TYPE = java_lang_invoke_MemberName::MN_IS_TYPE, + CALLER_SENSITIVE = java_lang_invoke_MemberName::MN_CALLER_SENSITIVE, REFERENCE_KIND_SHIFT = java_lang_invoke_MemberName::MN_REFERENCE_KIND_SHIFT, REFERENCE_KIND_MASK = java_lang_invoke_MemberName::MN_REFERENCE_KIND_MASK, - SEARCH_SUPERCLASSES = java_lang_invoke_MemberName::MN_SEARCH_SUPERCLASSES, - SEARCH_INTERFACES = java_lang_invoke_MemberName::MN_SEARCH_INTERFACES, + SEARCH_SUPERCLASSES = java_lang_invoke_MemberName::MN_SEARCH_SUPERCLASSES, + SEARCH_INTERFACES = java_lang_invoke_MemberName::MN_SEARCH_INTERFACES, ALL_KINDS = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE }; @@ -207,10 +208,15 @@ vmindex = m->vtable_index(); } - java_lang_invoke_MemberName::set_flags(mname_oop, flags); + // @CallerSensitive annotation detected + if (m->caller_sensitive()) { + flags |= CALLER_SENSITIVE; + } + + java_lang_invoke_MemberName::set_flags( mname_oop, flags); java_lang_invoke_MemberName::set_vmtarget(mname_oop, m); - java_lang_invoke_MemberName::set_vmindex(mname_oop, vmindex); // vtable/itable index - java_lang_invoke_MemberName::set_clazz(mname_oop, receiver_limit->java_mirror()); + java_lang_invoke_MemberName::set_vmindex( mname_oop, vmindex); // vtable/itable index + java_lang_invoke_MemberName::set_clazz( mname_oop, receiver_limit->java_mirror()); // Note: name and type can be lazily computed by resolve_MemberName, // if Java code needs them as resolved String and MethodType objects. // The clazz must be eagerly stored, because it provides a GC @@ -940,6 +946,7 @@ template(java_lang_invoke_MemberName,MN_IS_CONSTRUCTOR) \ template(java_lang_invoke_MemberName,MN_IS_FIELD) \ template(java_lang_invoke_MemberName,MN_IS_TYPE) \ + template(java_lang_invoke_MemberName,MN_CALLER_SENSITIVE) \ template(java_lang_invoke_MemberName,MN_SEARCH_SUPERCLASSES) \ template(java_lang_invoke_MemberName,MN_SEARCH_INTERFACES) \ template(java_lang_invoke_MemberName,MN_REFERENCE_KIND_SHIFT) \ diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/prims/unsafe.cpp --- a/src/share/vm/prims/unsafe.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/prims/unsafe.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -868,7 +868,7 @@ env->ThrowNew(cls, msg); } -static jclass Unsafe_DefineClass(JNIEnv *env, jstring name, jbyteArray data, int offset, int length, jobject loader, jobject pd) { +static jclass Unsafe_DefineClass_impl(JNIEnv *env, jstring name, jbyteArray data, int offset, int length, jobject loader, jobject pd) { { // Code lifted from JDK 1.3 ClassLoader.c @@ -939,6 +939,15 @@ } +UNSAFE_ENTRY(jclass, Unsafe_DefineClass(JNIEnv *env, jobject unsafe, jstring name, jbyteArray data, int offset, int length, jobject loader, jobject pd)) + UnsafeWrapper("Unsafe_DefineClass"); + { + ThreadToNativeFromVM ttnfv(thread); + return Unsafe_DefineClass_impl(env, name, data, offset, length, loader, pd); + } +UNSAFE_END + + UNSAFE_ENTRY(jclass, Unsafe_DefineClass0(JNIEnv *env, jobject unsafe, jstring name, jbyteArray data, int offset, int length)) UnsafeWrapper("Unsafe_DefineClass"); { @@ -949,20 +958,11 @@ jobject loader = (caller == NULL) ? NULL : JVM_GetClassLoader(env, caller); jobject pd = (caller == NULL) ? NULL : JVM_GetProtectionDomain(env, caller); - return Unsafe_DefineClass(env, name, data, offset, length, loader, pd); + return Unsafe_DefineClass_impl(env, name, data, offset, length, loader, pd); } UNSAFE_END -UNSAFE_ENTRY(jclass, Unsafe_DefineClass1(JNIEnv *env, jobject unsafe, jstring name, jbyteArray data, int offset, int length, jobject loader, jobject pd)) - UnsafeWrapper("Unsafe_DefineClass"); - { - ThreadToNativeFromVM ttnfv(thread); - - return Unsafe_DefineClass(env, name, data, offset, length, loader, pd); - } -UNSAFE_END - #define DAC_Args CLS"[B["OBJ // define a class but do not make it known to the class loader or system dictionary // - host_class: supplies context for linkage, access control, protection domain, and class loader @@ -1323,7 +1323,7 @@ #define THR LANG"Throwable;" #define DC0_Args LANG"String;[BII" -#define DC1_Args DC0_Args LANG"ClassLoader;" "Ljava/security/ProtectionDomain;" +#define DC_Args DC0_Args LANG"ClassLoader;" "Ljava/security/ProtectionDomain;" #define CC (char*) /*cast a literal from (const char*)*/ #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f) @@ -1352,10 +1352,8 @@ -// %%% These are temporarily supported until the SDK sources -// contain the necessarily updated Unsafe.java. +// These are the methods for 1.4.0 static JNINativeMethod methods_140[] = { - {CC"getObject", CC"("OBJ"I)"OBJ"", FN_PTR(Unsafe_GetObject140)}, {CC"putObject", CC"("OBJ"I"OBJ")V", FN_PTR(Unsafe_SetObject140)}, @@ -1381,12 +1379,10 @@ {CC"allocateMemory", CC"(J)"ADR, FN_PTR(Unsafe_AllocateMemory)}, {CC"reallocateMemory", CC"("ADR"J)"ADR, FN_PTR(Unsafe_ReallocateMemory)}, -// {CC"setMemory", CC"("ADR"JB)V", FN_PTR(Unsafe_SetMemory)}, -// {CC"copyMemory", CC"("ADR ADR"J)V", FN_PTR(Unsafe_CopyMemory)}, {CC"freeMemory", CC"("ADR")V", FN_PTR(Unsafe_FreeMemory)}, - {CC"fieldOffset", CC"("FLD")I", FN_PTR(Unsafe_FieldOffset)}, //deprecated - {CC"staticFieldBase", CC"("CLS")"OBJ, FN_PTR(Unsafe_StaticFieldBaseFromClass)}, //deprecated + {CC"fieldOffset", CC"("FLD")I", FN_PTR(Unsafe_FieldOffset)}, + {CC"staticFieldBase", CC"("CLS")"OBJ, FN_PTR(Unsafe_StaticFieldBaseFromClass)}, {CC"ensureClassInitialized",CC"("CLS")V", FN_PTR(Unsafe_EnsureClassInitialized)}, {CC"arrayBaseOffset", CC"("CLS")I", FN_PTR(Unsafe_ArrayBaseOffset)}, {CC"arrayIndexScale", CC"("CLS")I", FN_PTR(Unsafe_ArrayIndexScale)}, @@ -1394,16 +1390,15 @@ {CC"pageSize", CC"()I", FN_PTR(Unsafe_PageSize)}, {CC"defineClass", CC"("DC0_Args")"CLS, FN_PTR(Unsafe_DefineClass0)}, - {CC"defineClass", CC"("DC1_Args")"CLS, FN_PTR(Unsafe_DefineClass1)}, + {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, {CC"throwException", CC"("THR")V", FN_PTR(Unsafe_ThrowException)} }; -// These are the old methods prior to the JSR 166 changes in 1.5.0 +// These are the methods prior to the JSR 166 changes in 1.5.0 static JNINativeMethod methods_141[] = { - {CC"getObject", CC"("OBJ"J)"OBJ"", FN_PTR(Unsafe_GetObject)}, {CC"putObject", CC"("OBJ"J"OBJ")V", FN_PTR(Unsafe_SetObject)}, @@ -1429,8 +1424,6 @@ {CC"allocateMemory", CC"(J)"ADR, FN_PTR(Unsafe_AllocateMemory)}, {CC"reallocateMemory", CC"("ADR"J)"ADR, FN_PTR(Unsafe_ReallocateMemory)}, -// {CC"setMemory", CC"("ADR"JB)V", FN_PTR(Unsafe_SetMemory)}, -// {CC"copyMemory", CC"("ADR ADR"J)V", FN_PTR(Unsafe_CopyMemory)}, {CC"freeMemory", CC"("ADR")V", FN_PTR(Unsafe_FreeMemory)}, {CC"objectFieldOffset", CC"("FLD")J", FN_PTR(Unsafe_ObjectFieldOffset)}, @@ -1443,7 +1436,7 @@ {CC"pageSize", CC"()I", FN_PTR(Unsafe_PageSize)}, {CC"defineClass", CC"("DC0_Args")"CLS, FN_PTR(Unsafe_DefineClass0)}, - {CC"defineClass", CC"("DC1_Args")"CLS, FN_PTR(Unsafe_DefineClass1)}, + {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, @@ -1451,9 +1444,8 @@ }; -// These are the old methods prior to the JSR 166 changes in 1.6.0 +// These are the methods prior to the JSR 166 changes in 1.6.0 static JNINativeMethod methods_15[] = { - {CC"getObject", CC"("OBJ"J)"OBJ"", FN_PTR(Unsafe_GetObject)}, {CC"putObject", CC"("OBJ"J"OBJ")V", FN_PTR(Unsafe_SetObject)}, {CC"getObjectVolatile",CC"("OBJ"J)"OBJ"", FN_PTR(Unsafe_GetObjectVolatile)}, @@ -1482,8 +1474,6 @@ {CC"allocateMemory", CC"(J)"ADR, FN_PTR(Unsafe_AllocateMemory)}, {CC"reallocateMemory", CC"("ADR"J)"ADR, FN_PTR(Unsafe_ReallocateMemory)}, -// {CC"setMemory", CC"("ADR"JB)V", FN_PTR(Unsafe_SetMemory)}, -// {CC"copyMemory", CC"("ADR ADR"J)V", FN_PTR(Unsafe_CopyMemory)}, {CC"freeMemory", CC"("ADR")V", FN_PTR(Unsafe_FreeMemory)}, {CC"objectFieldOffset", CC"("FLD")J", FN_PTR(Unsafe_ObjectFieldOffset)}, @@ -1496,7 +1486,7 @@ {CC"pageSize", CC"()I", FN_PTR(Unsafe_PageSize)}, {CC"defineClass", CC"("DC0_Args")"CLS, FN_PTR(Unsafe_DefineClass0)}, - {CC"defineClass", CC"("DC1_Args")"CLS, FN_PTR(Unsafe_DefineClass1)}, + {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, @@ -1509,14 +1499,69 @@ }; -// These are the correct methods, moving forward: -static JNINativeMethod methods[] = { - +// These are the methods for 1.6.0 and 1.7.0 +static JNINativeMethod methods_16[] = { {CC"getObject", CC"("OBJ"J)"OBJ"", FN_PTR(Unsafe_GetObject)}, {CC"putObject", CC"("OBJ"J"OBJ")V", FN_PTR(Unsafe_SetObject)}, {CC"getObjectVolatile",CC"("OBJ"J)"OBJ"", FN_PTR(Unsafe_GetObjectVolatile)}, {CC"putObjectVolatile",CC"("OBJ"J"OBJ")V", FN_PTR(Unsafe_SetObjectVolatile)}, + DECLARE_GETSETOOP(Boolean, Z), + DECLARE_GETSETOOP(Byte, B), + DECLARE_GETSETOOP(Short, S), + DECLARE_GETSETOOP(Char, C), + DECLARE_GETSETOOP(Int, I), + DECLARE_GETSETOOP(Long, J), + DECLARE_GETSETOOP(Float, F), + DECLARE_GETSETOOP(Double, D), + + DECLARE_GETSETNATIVE(Byte, B), + DECLARE_GETSETNATIVE(Short, S), + DECLARE_GETSETNATIVE(Char, C), + DECLARE_GETSETNATIVE(Int, I), + DECLARE_GETSETNATIVE(Long, J), + DECLARE_GETSETNATIVE(Float, F), + DECLARE_GETSETNATIVE(Double, D), + + {CC"getAddress", CC"("ADR")"ADR, FN_PTR(Unsafe_GetNativeAddress)}, + {CC"putAddress", CC"("ADR""ADR")V", FN_PTR(Unsafe_SetNativeAddress)}, + + {CC"allocateMemory", CC"(J)"ADR, FN_PTR(Unsafe_AllocateMemory)}, + {CC"reallocateMemory", CC"("ADR"J)"ADR, FN_PTR(Unsafe_ReallocateMemory)}, + {CC"freeMemory", CC"("ADR")V", FN_PTR(Unsafe_FreeMemory)}, + + {CC"objectFieldOffset", CC"("FLD")J", FN_PTR(Unsafe_ObjectFieldOffset)}, + {CC"staticFieldOffset", CC"("FLD")J", FN_PTR(Unsafe_StaticFieldOffset)}, + {CC"staticFieldBase", CC"("FLD")"OBJ, FN_PTR(Unsafe_StaticFieldBaseFromField)}, + {CC"ensureClassInitialized",CC"("CLS")V", FN_PTR(Unsafe_EnsureClassInitialized)}, + {CC"arrayBaseOffset", CC"("CLS")I", FN_PTR(Unsafe_ArrayBaseOffset)}, + {CC"arrayIndexScale", CC"("CLS")I", FN_PTR(Unsafe_ArrayIndexScale)}, + {CC"addressSize", CC"()I", FN_PTR(Unsafe_AddressSize)}, + {CC"pageSize", CC"()I", FN_PTR(Unsafe_PageSize)}, + + {CC"defineClass", CC"("DC0_Args")"CLS, FN_PTR(Unsafe_DefineClass0)}, + {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, + {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, + {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, + {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, + {CC"tryMonitorEnter", CC"("OBJ")Z", FN_PTR(Unsafe_TryMonitorEnter)}, + {CC"throwException", CC"("THR")V", FN_PTR(Unsafe_ThrowException)}, + {CC"compareAndSwapObject", CC"("OBJ"J"OBJ""OBJ")Z", FN_PTR(Unsafe_CompareAndSwapObject)}, + {CC"compareAndSwapInt", CC"("OBJ"J""I""I"")Z", FN_PTR(Unsafe_CompareAndSwapInt)}, + {CC"compareAndSwapLong", CC"("OBJ"J""J""J"")Z", FN_PTR(Unsafe_CompareAndSwapLong)}, + {CC"putOrderedObject", CC"("OBJ"J"OBJ")V", FN_PTR(Unsafe_SetOrderedObject)}, + {CC"putOrderedInt", CC"("OBJ"JI)V", FN_PTR(Unsafe_SetOrderedInt)}, + {CC"putOrderedLong", CC"("OBJ"JJ)V", FN_PTR(Unsafe_SetOrderedLong)}, + {CC"park", CC"(ZJ)V", FN_PTR(Unsafe_Park)}, + {CC"unpark", CC"("OBJ")V", FN_PTR(Unsafe_Unpark)} +}; + +// These are the methods for 1.8.0 +static JNINativeMethod methods_18[] = { + {CC"getObject", CC"("OBJ"J)"OBJ"", FN_PTR(Unsafe_GetObject)}, + {CC"putObject", CC"("OBJ"J"OBJ")V", FN_PTR(Unsafe_SetObject)}, + {CC"getObjectVolatile",CC"("OBJ"J)"OBJ"", FN_PTR(Unsafe_GetObjectVolatile)}, + {CC"putObjectVolatile",CC"("OBJ"J"OBJ")V", FN_PTR(Unsafe_SetObjectVolatile)}, DECLARE_GETSETOOP(Boolean, Z), DECLARE_GETSETOOP(Byte, B), @@ -1540,8 +1585,6 @@ {CC"allocateMemory", CC"(J)"ADR, FN_PTR(Unsafe_AllocateMemory)}, {CC"reallocateMemory", CC"("ADR"J)"ADR, FN_PTR(Unsafe_ReallocateMemory)}, -// {CC"setMemory", CC"("ADR"JB)V", FN_PTR(Unsafe_SetMemory)}, -// {CC"copyMemory", CC"("ADR ADR"J)V", FN_PTR(Unsafe_CopyMemory)}, {CC"freeMemory", CC"("ADR")V", FN_PTR(Unsafe_FreeMemory)}, {CC"objectFieldOffset", CC"("FLD")J", FN_PTR(Unsafe_ObjectFieldOffset)}, @@ -1553,8 +1596,7 @@ {CC"addressSize", CC"()I", FN_PTR(Unsafe_AddressSize)}, {CC"pageSize", CC"()I", FN_PTR(Unsafe_PageSize)}, - {CC"defineClass", CC"("DC0_Args")"CLS, FN_PTR(Unsafe_DefineClass0)}, - {CC"defineClass", CC"("DC1_Args")"CLS, FN_PTR(Unsafe_DefineClass1)}, + {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, @@ -1566,23 +1608,12 @@ {CC"putOrderedObject", CC"("OBJ"J"OBJ")V", FN_PTR(Unsafe_SetOrderedObject)}, {CC"putOrderedInt", CC"("OBJ"JI)V", FN_PTR(Unsafe_SetOrderedInt)}, {CC"putOrderedLong", CC"("OBJ"JJ)V", FN_PTR(Unsafe_SetOrderedLong)}, - {CC"loadFence", CC"()V", FN_PTR(Unsafe_LoadFence)}, - {CC"storeFence", CC"()V", FN_PTR(Unsafe_StoreFence)}, - {CC"fullFence", CC"()V", FN_PTR(Unsafe_FullFence)}, {CC"park", CC"(ZJ)V", FN_PTR(Unsafe_Park)}, {CC"unpark", CC"("OBJ")V", FN_PTR(Unsafe_Unpark)} - -// {CC"getLoadAverage", CC"([DI)I", FN_PTR(Unsafe_Loadavg)}, - -// {CC"prefetchRead", CC"("OBJ"J)V", FN_PTR(Unsafe_PrefetchRead)}, -// {CC"prefetchWrite", CC"("OBJ"J)V", FN_PTR(Unsafe_PrefetchWrite)} -// {CC"prefetchReadStatic", CC"("OBJ"J)V", FN_PTR(Unsafe_PrefetchRead)}, -// {CC"prefetchWriteStatic",CC"("OBJ"J)V", FN_PTR(Unsafe_PrefetchWrite)} - }; JNINativeMethod loadavg_method[] = { - {CC"getLoadAverage", CC"([DI)I", FN_PTR(Unsafe_Loadavg)} + {CC"getLoadAverage", CC"([DI)I", FN_PTR(Unsafe_Loadavg)} }; JNINativeMethod prefetch_methods[] = { @@ -1592,7 +1623,7 @@ {CC"prefetchWriteStatic",CC"("OBJ"J)V", FN_PTR(Unsafe_PrefetchWrite)} }; -JNINativeMethod memcopy_methods[] = { +JNINativeMethod memcopy_methods_17[] = { {CC"copyMemory", CC"("OBJ"J"OBJ"JJ)V", FN_PTR(Unsafe_CopyMemory2)}, {CC"setMemory", CC"("OBJ"JJB)V", FN_PTR(Unsafe_SetMemory2)} }; @@ -1610,6 +1641,12 @@ {CC"shouldBeInitialized",CC"("CLS")Z", FN_PTR(Unsafe_ShouldBeInitialized)}, }; +JNINativeMethod fence_methods[] = { + {CC"loadFence", CC"()V", FN_PTR(Unsafe_LoadFence)}, + {CC"storeFence", CC"()V", FN_PTR(Unsafe_StoreFence)}, + {CC"fullFence", CC"()V", FN_PTR(Unsafe_FullFence)}, +}; + #undef CC #undef FN_PTR @@ -1622,12 +1659,32 @@ #undef MTH #undef THR #undef DC0_Args -#undef DC1_Args +#undef DC_Args #undef DECLARE_GETSETOOP #undef DECLARE_GETSETNATIVE +/** + * Helper method to register native methods. + */ +static bool register_natives(const char* message, JNIEnv* env, jclass clazz, const JNINativeMethod* methods, jint nMethods) { + int status = env->RegisterNatives(clazz, methods, nMethods); + if (status < 0 || env->ExceptionOccurred()) { + if (PrintMiscellaneous && (Verbose || WizardMode)) { + tty->print_cr("Unsafe: failed registering %s", message); + } + env->ExceptionClear(); + return false; + } else { + if (PrintMiscellaneous && (Verbose || WizardMode)) { + tty->print_cr("Unsafe: successfully registered %s", message); + } + return true; + } +} + + // This one function is exported, used by NativeLookup. // The Unsafe_xxx functions above are called only from the interpreter. // The optimizer looks at names and signatures to recognize @@ -1637,83 +1694,57 @@ UnsafeWrapper("JVM_RegisterUnsafeMethods"); { ThreadToNativeFromVM ttnfv(thread); - { - env->RegisterNatives(unsafecls, loadavg_method, sizeof(loadavg_method)/sizeof(JNINativeMethod)); - if (env->ExceptionOccurred()) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - tty->print_cr("Warning: SDK 1.6 Unsafe.loadavg not found."); - } - env->ExceptionClear(); - } - } + + // Unsafe methods { - env->RegisterNatives(unsafecls, prefetch_methods, sizeof(prefetch_methods)/sizeof(JNINativeMethod)); - if (env->ExceptionOccurred()) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - tty->print_cr("Warning: SDK 1.6 Unsafe.prefetchRead/Write not found."); - } - env->ExceptionClear(); + bool success = false; + // We need to register the 1.6 methods first because the 1.8 methods would register fine on 1.7 and 1.6 + if (!success) { + success = register_natives("1.6 methods", env, unsafecls, methods_16, sizeof(methods_16)/sizeof(JNINativeMethod)); + } + if (!success) { + success = register_natives("1.8 methods", env, unsafecls, methods_18, sizeof(methods_18)/sizeof(JNINativeMethod)); + } + if (!success) { + success = register_natives("1.5 methods", env, unsafecls, methods_15, sizeof(methods_15)/sizeof(JNINativeMethod)); + } + if (!success) { + success = register_natives("1.4.1 methods", env, unsafecls, methods_141, sizeof(methods_141)/sizeof(JNINativeMethod)); } + if (!success) { + success = register_natives("1.4.0 methods", env, unsafecls, methods_140, sizeof(methods_140)/sizeof(JNINativeMethod)); + } + guarantee(success, "register unsafe natives"); } + + // Unsafe.getLoadAverage + register_natives("1.6 loadavg method", env, unsafecls, loadavg_method, sizeof(loadavg_method)/sizeof(JNINativeMethod)); + + // Prefetch methods + register_natives("1.6 prefetch methods", env, unsafecls, prefetch_methods, sizeof(prefetch_methods)/sizeof(JNINativeMethod)); + + // Memory copy methods { - env->RegisterNatives(unsafecls, memcopy_methods, sizeof(memcopy_methods)/sizeof(JNINativeMethod)); - if (env->ExceptionOccurred()) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - tty->print_cr("Warning: SDK 1.7 Unsafe.copyMemory not found."); - } - env->ExceptionClear(); - env->RegisterNatives(unsafecls, memcopy_methods_15, sizeof(memcopy_methods_15)/sizeof(JNINativeMethod)); - if (env->ExceptionOccurred()) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - tty->print_cr("Warning: SDK 1.5 Unsafe.copyMemory not found."); - } - env->ExceptionClear(); - } + bool success = false; + if (!success) { + success = register_natives("1.7 memory copy methods", env, unsafecls, memcopy_methods_17, sizeof(memcopy_methods_17)/sizeof(JNINativeMethod)); + } + if (!success) { + success = register_natives("1.5 memory copy methods", env, unsafecls, memcopy_methods_15, sizeof(memcopy_methods_15)/sizeof(JNINativeMethod)); } } + + // Unsafe.defineAnonymousClass if (EnableInvokeDynamic) { - env->RegisterNatives(unsafecls, anonk_methods, sizeof(anonk_methods)/sizeof(JNINativeMethod)); - if (env->ExceptionOccurred()) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - tty->print_cr("Warning: SDK 1.7 Unsafe.defineClass (anonymous version) not found."); - } - env->ExceptionClear(); - } - } - if (EnableInvokeDynamic) { - env->RegisterNatives(unsafecls, lform_methods, sizeof(lform_methods)/sizeof(JNINativeMethod)); - if (env->ExceptionOccurred()) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - tty->print_cr("Warning: SDK 1.7 LambdaForm support in Unsafe not found."); - } - env->ExceptionClear(); - } + register_natives("1.7 define anonymous class method", env, unsafecls, anonk_methods, sizeof(anonk_methods)/sizeof(JNINativeMethod)); } - int status = env->RegisterNatives(unsafecls, methods, sizeof(methods)/sizeof(JNINativeMethod)); - if (env->ExceptionOccurred()) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - tty->print_cr("Warning: SDK 1.6 version of Unsafe not found."); - } - env->ExceptionClear(); - // %%% For now, be backward compatible with an older class: - status = env->RegisterNatives(unsafecls, methods_15, sizeof(methods_15)/sizeof(JNINativeMethod)); + + // Unsafe.shouldBeInitialized + if (EnableInvokeDynamic) { + register_natives("1.7 LambdaForm support", env, unsafecls, lform_methods, sizeof(lform_methods)/sizeof(JNINativeMethod)); } - if (env->ExceptionOccurred()) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - tty->print_cr("Warning: SDK 1.5 version of Unsafe not found."); - } - env->ExceptionClear(); - // %%% For now, be backward compatible with an older class: - status = env->RegisterNatives(unsafecls, methods_141, sizeof(methods_141)/sizeof(JNINativeMethod)); - } - if (env->ExceptionOccurred()) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - tty->print_cr("Warning: SDK 1.4.1 version of Unsafe not found."); - } - env->ExceptionClear(); - // %%% For now, be backward compatible with an older class: - status = env->RegisterNatives(unsafecls, methods_140, sizeof(methods_140)/sizeof(JNINativeMethod)); - } - guarantee(status == 0, "register unsafe natives"); + + // Fence methods + register_natives("1.8 fence methods", env, unsafecls, fence_methods, sizeof(fence_methods)/sizeof(JNINativeMethod)); } JVM_END diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/prims/whitebox.cpp --- a/src/share/vm/prims/whitebox.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/prims/whitebox.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -118,45 +118,46 @@ #endif // INCLUDE_ALL_GCS #ifdef INCLUDE_NMT -// Keep track of the 3 allocations in NMTAllocTest so we can free them later -// on and verify that they're not visible anymore -static void* nmtMtTest1 = NULL, *nmtMtTest2 = NULL, *nmtMtTest3 = NULL; - // Alloc memory using the test memory type so that we can use that to see if // NMT picks it up correctly -WB_ENTRY(jboolean, WB_NMTAllocTest(JNIEnv* env)) - void *mem; +WB_ENTRY(jlong, WB_NMTMalloc(JNIEnv* env, jobject o, jlong size)) + jlong addr = 0; - if (!MemTracker::is_on() || MemTracker::shutdown_in_progress()) { - return false; + if (MemTracker::is_on() && !MemTracker::shutdown_in_progress()) { + addr = (jlong)(uintptr_t)os::malloc(size, mtTest); } - // Allocate 2 * 128k + 256k + 1024k and free the 1024k one to make sure we track - // everything correctly. Total should be 512k held alive. - nmtMtTest1 = os::malloc(128 * 1024, mtTest); - mem = os::malloc(1024 * 1024, mtTest); - nmtMtTest2 = os::malloc(256 * 1024, mtTest); - os::free(mem, mtTest); - nmtMtTest3 = os::malloc(128 * 1024, mtTest); - - return true; + return addr; WB_END // Free the memory allocated by NMTAllocTest -WB_ENTRY(jboolean, WB_NMTFreeTestMemory(JNIEnv* env)) +WB_ENTRY(void, WB_NMTFree(JNIEnv* env, jobject o, jlong mem)) + os::free((void*)(uintptr_t)mem, mtTest); +WB_END - if (nmtMtTest1 == NULL || nmtMtTest2 == NULL || nmtMtTest3 == NULL) { - return false; +WB_ENTRY(jlong, WB_NMTReserveMemory(JNIEnv* env, jobject o, jlong size)) + jlong addr = 0; + + if (MemTracker::is_on() && !MemTracker::shutdown_in_progress()) { + addr = (jlong)(uintptr_t)os::reserve_memory(size); + MemTracker::record_virtual_memory_type((address)addr, mtTest); } - os::free(nmtMtTest1, mtTest); - nmtMtTest1 = NULL; - os::free(nmtMtTest2, mtTest); - nmtMtTest2 = NULL; - os::free(nmtMtTest3, mtTest); - nmtMtTest3 = NULL; + return addr; +WB_END + - return true; +WB_ENTRY(void, WB_NMTCommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size)) + os::commit_memory((char *)(uintptr_t)addr, size); + MemTracker::record_virtual_memory_type((address)(uintptr_t)addr, mtTest); +WB_END + +WB_ENTRY(void, WB_NMTUncommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size)) + os::uncommit_memory((char *)(uintptr_t)addr, size); +WB_END + +WB_ENTRY(void, WB_NMTReleaseMemory(JNIEnv* env, jobject o, jlong addr, jlong size)) + os::release_memory((char *)(uintptr_t)addr, size); WB_END // Block until the current generation of NMT data to be merged, used to reliably test the NMT feature @@ -254,6 +255,24 @@ CompileBroker::queue_size(CompLevel_full_profile) /* C1 */; WB_END +WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString)) + ResourceMark rm(THREAD); + int len; + jchar* name = java_lang_String::as_unicode_string(JNIHandles::resolve(javaString), len); + oop found_string = StringTable::the_table()->lookup(name, len); + if (found_string == NULL) { + return false; + } + return true; +WB_END + + +WB_ENTRY(void, WB_FullGC(JNIEnv* env, jobject o)) + Universe::heap()->collector_policy()->set_should_clear_all_soft_refs(true); + Universe::heap()->collect(GCCause::_last_ditch_collection); +WB_END + + //Some convenience methods to deal with objects from java int WhiteBox::offset_for_field(const char* field_name, oop object, Symbol* signature_symbol) { @@ -322,9 +341,13 @@ {CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize }, #endif // INCLUDE_ALL_GCS #ifdef INCLUDE_NMT - {CC"NMTAllocTest", CC"()Z", (void*)&WB_NMTAllocTest }, - {CC"NMTFreeTestMemory", CC"()Z", (void*)&WB_NMTFreeTestMemory }, - {CC"NMTWaitForDataMerge",CC"()Z", (void*)&WB_NMTWaitForDataMerge}, + {CC"NMTMalloc", CC"(J)J", (void*)&WB_NMTMalloc }, + {CC"NMTFree", CC"(J)V", (void*)&WB_NMTFree }, + {CC"NMTReserveMemory", CC"(J)J", (void*)&WB_NMTReserveMemory }, + {CC"NMTCommitMemory", CC"(JJ)V", (void*)&WB_NMTCommitMemory }, + {CC"NMTUncommitMemory", CC"(JJ)V", (void*)&WB_NMTUncommitMemory }, + {CC"NMTReleaseMemory", CC"(JJ)V", (void*)&WB_NMTReleaseMemory }, + {CC"NMTWaitForDataMerge", CC"()Z", (void*)&WB_NMTWaitForDataMerge}, #endif // INCLUDE_NMT {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll }, {CC"deoptimizeMethod", CC"(Ljava/lang/reflect/Method;)I", @@ -343,6 +366,8 @@ CC"(Ljava/lang/reflect/Method;)I", (void*)&WB_GetMethodCompilationLevel}, {CC"getCompileQueuesSize", CC"()I", (void*)&WB_GetCompileQueuesSize}, + {CC"isInStringTable", CC"(Ljava/lang/String;)Z", (void*)&WB_IsInStringTable }, + {CC"fullGC", CC"()V", (void*)&WB_FullGC }, }; #undef CC diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/runtime/arguments.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -260,6 +260,7 @@ { "CMSRevisitStackSize", JDK_Version::jdk(8), JDK_Version::jdk(9) }, { "PrintRevisitStats", JDK_Version::jdk(8), JDK_Version::jdk(9) }, { "UseVectoredExceptions", JDK_Version::jdk(8), JDK_Version::jdk(9) }, + { "UseSplitVerifier", JDK_Version::jdk(8), JDK_Version::jdk(9) }, #ifdef PRODUCT { "DesiredMethodLimit", JDK_Version::jdk_update(7, 2), JDK_Version::jdk(8) }, @@ -1169,7 +1170,6 @@ set_parnew_gc_flags(); } - // MaxHeapSize is aligned down in collectorPolicy size_t max_heap = align_size_down(MaxHeapSize, CardTableRS::ct_max_alignment_constraint()); @@ -1207,10 +1207,6 @@ } // Code along this path potentially sets NewSize and OldSize - - assert(max_heap >= InitialHeapSize, "Error"); - assert(max_heap >= NewSize, "Error"); - if (PrintGCDetails && Verbose) { // Too early to use gclog_or_tty tty->print_cr("CMS set min_heap_size: " SIZE_FORMAT @@ -1557,6 +1553,15 @@ } } +julong Arguments::limit_by_allocatable_memory(julong limit) { + julong max_allocatable; + julong result = limit; + if (os::has_allocatable_memory_limit(&max_allocatable)) { + result = MIN2(result, max_allocatable / MaxVirtMemFraction); + } + return result; +} + void Arguments::set_heap_size() { if (!FLAG_IS_DEFAULT(DefaultMaxRAMFraction)) { // Deprecated flag @@ -1595,12 +1600,12 @@ } reasonable_max = MIN2(reasonable_max, max_coop_heap); } - reasonable_max = os::allocatable_physical_memory(reasonable_max); + reasonable_max = limit_by_allocatable_memory(reasonable_max); if (!FLAG_IS_DEFAULT(InitialHeapSize)) { // An initial heap size was specified on the command line, // so be sure that the maximum size is consistent. Done - // after call to allocatable_physical_memory because that + // after call to limit_by_allocatable_memory because that // method might reduce the allocation size. reasonable_max = MAX2(reasonable_max, (julong)InitialHeapSize); } @@ -1620,14 +1625,14 @@ reasonable_minimum = MIN2(reasonable_minimum, (julong)MaxHeapSize); - reasonable_minimum = os::allocatable_physical_memory(reasonable_minimum); + reasonable_minimum = limit_by_allocatable_memory(reasonable_minimum); julong reasonable_initial = phys_mem / InitialRAMFraction; reasonable_initial = MAX2(reasonable_initial, reasonable_minimum); reasonable_initial = MIN2(reasonable_initial, (julong)MaxHeapSize); - reasonable_initial = os::allocatable_physical_memory(reasonable_initial); + reasonable_initial = limit_by_allocatable_memory(reasonable_initial); if (PrintGCDetails && Verbose) { // Cannot use gclog_or_tty yet. @@ -1749,11 +1754,15 @@ return false; } +#if !INCLUDE_ALL_GCS +#ifdef ASSERT static bool verify_serial_gc_flags() { return (UseSerialGC && !(UseParNewGC || (UseConcMarkSweepGC || CMSIncrementalMode) || UseG1GC || UseParallelGC || UseParallelOldGC)); } +#endif // ASSERT +#endif // INCLUDE_ALL_GCS // check if do gclog rotation // +UseGCLogFileRotation is a must, @@ -2613,9 +2622,7 @@ initHeapSize = MIN2(total_memory / (julong)2, total_memory - (julong)160*M); - // Make sure that if we have a lot of memory we cap the 32 bit - // process space. The 64bit VM version of this function is a nop. - initHeapSize = os::allocatable_physical_memory(initHeapSize); + initHeapSize = limit_by_allocatable_memory(initHeapSize); if (FLAG_IS_DEFAULT(MaxHeapSize)) { FLAG_SET_CMDLINE(uintx, MaxHeapSize, initHeapSize); @@ -3089,6 +3096,7 @@ } \ } while(0) +#if !INCLUDE_ALL_GCS static void force_serial_gc() { FLAG_SET_DEFAULT(UseSerialGC, true); FLAG_SET_DEFAULT(CMSIncrementalMode, false); // special CMS suboption @@ -3098,6 +3106,7 @@ UNSUPPORTED_GC_OPTION(UseConcMarkSweepGC); UNSUPPORTED_GC_OPTION(UseParNewGC); } +#endif // INCLUDE_ALL_GCS // Parse entry point called from JNI_CreateJavaVM @@ -3324,6 +3333,13 @@ } check_deprecated_gcs(); check_deprecated_gc_flags(); + if (AssumeMP && !UseSerialGC) { + if (FLAG_IS_DEFAULT(ParallelGCThreads) && ParallelGCThreads == 1) { + warning("If the number of processors is expected to increase from one, then" + " you should configure the number of parallel GC threads appropriately" + " using -XX:ParallelGCThreads=N"); + } + } #else // INCLUDE_ALL_GCS assert(verify_serial_gc_flags(), "SerialGC unset"); #endif // INCLUDE_ALL_GCS diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/runtime/arguments.hpp --- a/src/share/vm/runtime/arguments.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/runtime/arguments.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -312,6 +312,9 @@ static void set_use_compressed_oops(); static void set_ergonomics_flags(); static void set_shared_spaces_flags(); + // limits the given memory size by the maximum amount of memory this process is + // currently allowed to allocate or reserve. + static julong limit_by_allocatable_memory(julong size); // Setup heap size static void set_heap_size(); // Based on automatic selection criteria, should the diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/runtime/globals.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -457,6 +457,9 @@ lp64_product(intx, ObjectAlignmentInBytes, 8, \ "Default object alignment in bytes, 8 is minimum") \ \ + product(bool, AssumeMP, false, \ + "Instruct the VM to assume multiple processors are available") \ + \ /* UseMembar is theoretically a temp flag used for memory barrier \ * removal testing. It was supposed to be removed before FCS but has \ * been re-added (see 6401008) */ \ @@ -679,9 +682,6 @@ product(bool, UseCompilerSafepoints, true, \ "Stop at safepoints in compiled code") \ \ - product(bool, UseSplitVerifier, true, \ - "use split verifier with StackMapTable attributes") \ - \ product(bool, FailOverToOldVerifier, true, \ "fail over to old verifier when split verifier fails") \ \ @@ -869,6 +869,11 @@ diagnostic(bool, PrintNMTStatistics, false, \ "Print native memory tracking summary data if it is on") \ \ + diagnostic(bool, AutoShutdownNMT, true, \ + "Automatically shutdown native memory tracking under stress " \ + "situation. When set to false, native memory tracking tries to " \ + "stay alive at the expense of JVM performance") \ + \ diagnostic(bool, LogCompilation, false, \ "Log compilation activity in detail to hotspot.log or LogFile") \ \ @@ -1402,6 +1407,10 @@ "How much the GC can expand the eden by while the GC locker " \ "is active (as a percentage)") \ \ + diagnostic(intx, GCLockerRetryAllocationCount, 2, \ + "Number of times to retry allocations when" \ + " blocked by the GC locker") \ + \ develop(bool, UseCMSAdaptiveFreeLists, true, \ "Use Adaptive Free Lists in the CMS generation") \ \ @@ -1958,6 +1967,10 @@ product(uintx, InitialRAMFraction, 64, \ "Fraction (1/n) of real memory used for initial heap size") \ \ + develop(uintx, MaxVirtMemFraction, 2, \ + "Maximum fraction (1/n) of virtual memory used for ergonomically" \ + "determining maximum heap size") \ + \ product(bool, UseAutoGCSelectPolicy, false, \ "Use automatic collection selection policy") \ \ @@ -2515,7 +2528,7 @@ "disable locking assertions (for speed)") \ \ product(bool, RangeCheckElimination, true, \ - "Split loop iterations to eliminate range checks") \ + "Eliminate range checks") \ \ develop_pd(bool, UncommonNullCast, \ "track occurrences of null in casts; adjust compiler tactics") \ @@ -2905,6 +2918,10 @@ "if non-zero, start verifying C heap after Nth call to " \ "malloc/realloc/free") \ \ + diagnostic(uintx, MallocMaxTestWords, 0, \ + "if non-zero, max # of Words that malloc/realloc can allocate " \ + "(for testing only)") \ + \ product(intx, TypeProfileWidth, 2, \ "number of receiver types to record in call/cast profile") \ \ @@ -3569,8 +3586,9 @@ product(uintx, SharedMiscCodeSize, 120*K, \ "Size of the shared miscellaneous code area (in bytes)") \ \ - product(uintx, SharedDummyBlockSize, 0, \ - "Size of dummy block used to shift heap addresses (in bytes)") \ + product(uintx, SharedBaseAddress, LP64_ONLY(32*G) \ + NOT_LP64(LINUX_ONLY(2*G) NOT_LINUX(0)), \ + "Address to allocate shared memory region for class data") \ \ diagnostic(bool, EnableInvokeDynamic, true, \ "support JSR 292 (method handles, invokedynamic, " \ diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/runtime/init.cpp --- a/src/share/vm/runtime/init.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/runtime/init.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -132,15 +132,6 @@ javaClasses_init(); // must happen after vtable initialization stubRoutines_init2(); // note: StubRoutines need 2-phase init - // Although we'd like to, we can't easily do a heap verify - // here because the main thread isn't yet a JavaThread, so - // its TLAB may not be made parseable from the usual interfaces. - if (VerifyBeforeGC && !UseTLAB && - Universe::heap()->total_collections() >= VerifyGCStartAt) { - Universe::heap()->prepare_for_verify(); - Universe::verify(); // make sure we're starting with a clean slate - } - // All the flags that get adjusted by VM_Version_init and os::init_2 // have been set so dump the flags now. if (PrintFlagsFinal) { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/runtime/os.cpp --- a/src/share/vm/runtime/os.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/runtime/os.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,6 +80,8 @@ julong os::free_bytes = 0; // # of bytes freed #endif +static juint cur_malloc_words = 0; // current size for MallocMaxTestWords + void os_init_globals() { // Called from init_globals(). // See Threads::create_vm() in thread.cpp, and init.cpp. @@ -570,6 +572,26 @@ } #endif +// +// This function supports testing of the malloc out of memory +// condition without really running the system out of memory. +// +static u_char* testMalloc(size_t alloc_size) { + assert(MallocMaxTestWords > 0, "sanity check"); + + if ((cur_malloc_words + (alloc_size / BytesPerWord)) > MallocMaxTestWords) { + return NULL; + } + + u_char* ptr = (u_char*)::malloc(alloc_size); + + if (ptr != NULL) { + Atomic::add(((jint) (alloc_size / BytesPerWord)), + (volatile jint *) &cur_malloc_words); + } + return ptr; +} + void* os::malloc(size_t size, MEMFLAGS memflags, address caller) { NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1)); NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size)); @@ -579,11 +601,22 @@ // if NULL is returned the calling functions assume out of memory. size = 1; } - if (size > size + space_before + space_after) { // Check for rollover. + + const size_t alloc_size = size + space_before + space_after; + + if (size > alloc_size) { // Check for rollover. return NULL; } + NOT_PRODUCT(if (MallocVerifyInterval > 0) check_heap()); - u_char* ptr = (u_char*)::malloc(size + space_before + space_after); + + u_char* ptr; + + if (MallocMaxTestWords > 0) { + ptr = testMalloc(alloc_size); + } else { + ptr = (u_char*)::malloc(alloc_size); + } #ifdef ASSERT if (ptr == NULL) return NULL; diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/runtime/os.hpp --- a/src/share/vm/runtime/os.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/runtime/os.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -180,11 +180,11 @@ // Interface for detecting multiprocessor system static inline bool is_MP() { assert(_processor_count > 0, "invalid processor count"); - return _processor_count > 1; + return _processor_count > 1 || AssumeMP; } static julong available_memory(); static julong physical_memory(); - static julong allocatable_physical_memory(julong size); + static bool has_allocatable_memory_limit(julong* limit); static bool is_server_class_machine(); // number of CPUs diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/runtime/safepoint.cpp --- a/src/share/vm/runtime/safepoint.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/runtime/safepoint.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -735,6 +735,9 @@ // Exception handlers #ifndef PRODUCT + +#ifdef SPARC + #ifdef _LP64 #define PTR_PAD "" #else @@ -755,7 +758,6 @@ newptr, is_oop?"oop":" ", (wasoop && !is_oop) ? "STALE" : ((wasoop==false&&is_oop==false&&oldptr !=newptr)?"STOMP":" ")); } -#ifdef SPARC static void print_me(intptr_t *new_sp, intptr_t *old_sp, bool *was_oops) { #ifdef _LP64 tty->print_cr("--------+------address-----+------before-----------+-------after----------+"); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/runtime/stubCodeGenerator.cpp --- a/src/share/vm/runtime/stubCodeGenerator.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/runtime/stubCodeGenerator.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -87,7 +87,7 @@ CodeBuffer* cbuf = _masm->code(); CodeBlob* blob = CodeCache::find_blob_unsafe(cbuf->insts()->start()); if (blob != NULL) { - blob->set_comments(cbuf->comments()); + blob->set_strings(cbuf->strings()); } bool saw_first = false; StubCodeDesc* toprint[1000]; diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/runtime/synchronizer.cpp --- a/src/share/vm/runtime/synchronizer.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/runtime/synchronizer.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -449,8 +449,6 @@ // and explicit fences (barriers) to control for architectural reordering performed // by the CPU(s) or platform. -static int MBFence (int x) { OrderAccess::fence(); return x; } - struct SharedGlobals { // These are highly shared mostly-read variables. // To avoid false-sharing they need to be the sole occupants of a $ line. @@ -1639,11 +1637,6 @@ #ifndef PRODUCT -void ObjectSynchronizer::trace_locking(Handle locking_obj, bool is_compiled, - bool is_method, bool is_locking) { - // Don't know what to do here -} - // Verify all monitors in the monitor cache, the verification is weak. void ObjectSynchronizer::verify() { ObjectMonitor* block = gBlockList; diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/runtime/synchronizer.hpp --- a/src/share/vm/runtime/synchronizer.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/runtime/synchronizer.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -121,7 +121,6 @@ static void oops_do(OopClosure* f); // debugging - static void trace_locking(Handle obj, bool is_compiled, bool is_method, bool is_locking) PRODUCT_RETURN; static void verify() PRODUCT_RETURN; static int verify_objmon_isinpool(ObjectMonitor *addr) PRODUCT_RETURN0; diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/runtime/thread.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -3423,12 +3423,6 @@ // real raw monitor. VM is setup enough here for raw monitor enter. JvmtiExport::transition_pending_onload_raw_monitors(); - if (VerifyBeforeGC && - Universe::heap()->total_collections() >= VerifyGCStartAt) { - Universe::heap()->prepare_for_verify(); - Universe::verify(); // make sure we're starting with a clean slate - } - // Fully start NMT MemTracker::start(); @@ -3452,6 +3446,11 @@ } assert (Universe::is_fully_initialized(), "not initialized"); + if (VerifyBeforeGC && VerifyGCStartAt == 0) { + Universe::heap()->prepare_for_verify(); + Universe::verify(); // make sure we're starting with a clean slate + } + EXCEPTION_MARK; // At this point, the Universe is initialized, but we have not executed @@ -4061,6 +4060,7 @@ if (version == JNI_VERSION_1_2) return JNI_TRUE; if (version == JNI_VERSION_1_4) return JNI_TRUE; if (version == JNI_VERSION_1_6) return JNI_TRUE; + if (version == JNI_VERSION_1_8) return JNI_TRUE; return JNI_FALSE; } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/runtime/vframe.cpp --- a/src/share/vm/runtime/vframe.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/runtime/vframe.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -391,40 +391,27 @@ // Step back n frames, skip any pseudo frames in between. // This function is used in Class.forName, Class.newInstance, Method.Invoke, // AccessController.doPrivileged. -// -// NOTE that in JDK 1.4 this has been exposed to Java as -// sun.reflect.Reflection.getCallerClass(), which can be inlined. -// Inlined versions must match this routine's logic. -// Native method prefixing logic does not need to match since -// the method names don't match and inlining will not occur. -// See, for example, -// Parse::inline_native_Reflection_getCallerClass in -// opto/library_call.cpp. void vframeStreamCommon::security_get_caller_frame(int depth) { - bool use_new_reflection = JDK_Version::is_gte_jdk14x_version() && UseNewReflection; + assert(depth >= 0, err_msg("invalid depth: %d", depth)); + for (int n = 0; !at_end(); security_next()) { + if (!method()->is_ignored_by_security_stack_walk()) { + if (n == depth) { + // We have reached the desired depth; return. + return; + } + n++; // this is a non-skipped frame; count it against the depth + } + } + // NOTE: At this point there were not enough frames on the stack + // to walk to depth. Callers of this method have to check for at_end. +} - while (!at_end()) { - if (Universe::reflect_invoke_cache()->is_same_method(method())) { - // This is Method.invoke() -- skip it - } else if (use_new_reflection && - method()->method_holder() - ->is_subclass_of(SystemDictionary::reflect_MethodAccessorImpl_klass())) { - // This is an auxilary frame -- skip it - } else if (method()->is_method_handle_intrinsic() || - method()->is_compiled_lambda_form()) { - // This is an internal adapter frame for method handles -- skip it - } else { - // This is non-excluded frame, we need to count it against the depth - if (depth-- <= 0) { - // we have reached the desired depth, we are done - break; - } - } - if (method()->is_prefixed_native()) { - skip_prefixed_method_and_wrappers(); - } else { - next(); - } + +void vframeStreamCommon::security_next() { + if (method()->is_prefixed_native()) { + skip_prefixed_method_and_wrappers(); // calls next() + } else { + next(); } } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/runtime/vframe.hpp --- a/src/share/vm/runtime/vframe.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/runtime/vframe.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -336,6 +336,7 @@ _frame = _frame.sender(&_reg_map); } while (!fill_from_frame()); } + void security_next(); bool at_end() const { return _mode == at_end_mode; } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/runtime/vm_version.cpp --- a/src/share/vm/runtime/vm_version.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/runtime/vm_version.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -211,6 +211,10 @@ #define HOTSPOT_BUILD_COMPILER "MS VC++ 8.0 (VS2005)" #elif _MSC_VER == 1500 #define HOTSPOT_BUILD_COMPILER "MS VC++ 9.0 (VS2008)" + #elif _MSC_VER == 1600 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 10.0 (VS2010)" + #elif _MSC_VER == 1700 + #define HOTSPOT_BUILD_COMPILER "MS VC++ 11.0 (VS2012)" #else #define HOTSPOT_BUILD_COMPILER "unknown MS VC++:" XSTR(_MSC_VER) #endif diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/services/memTracker.cpp --- a/src/share/vm/services/memTracker.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/services/memTracker.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -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 @@ -68,6 +68,7 @@ volatile jint MemTracker::_pooled_recorder_count = 0; volatile unsigned long MemTracker::_processing_generation = 0; volatile bool MemTracker::_worker_thread_idle = false; +volatile bool MemTracker::_slowdown_calling_thread = false; debug_only(intx MemTracker::_main_thread_tid = 0;) NOT_PRODUCT(volatile jint MemTracker::_pending_recorder_count = 0;) @@ -126,12 +127,15 @@ assert(_state == NMT_bootstrapping_multi_thread, "wrong state"); _snapshot = new (std::nothrow)MemSnapshot(); - if (_snapshot != NULL && !_snapshot->out_of_memory()) { - if (start_worker()) { + if (_snapshot != NULL) { + if (!_snapshot->out_of_memory() && start_worker()) { _state = NMT_started; NMT_track_callsite = (_tracking_level == NMT_detail && can_walk_stack()); return; } + + delete _snapshot; + _snapshot = NULL; } // fail to start native memory tracking, shut it down @@ -364,6 +368,12 @@ } if (thread != NULL) { + // slow down all calling threads except NMT worker thread, so it + // can catch up. + if (_slowdown_calling_thread && thread != _worker_thread) { + os::yield_all(); + } + if (thread->is_Java_thread() && ((JavaThread*)thread)->is_safepoint_visible()) { JavaThread* java_thread = (JavaThread*)thread; JavaThreadState state = java_thread->thread_state(); @@ -442,6 +452,7 @@ #define MAX_SAFEPOINTS_TO_SKIP 128 #define SAFE_SEQUENCE_THRESHOLD 30 #define HIGH_GENERATION_THRESHOLD 60 +#define MAX_RECORDER_THREAD_RATIO 30 void MemTracker::sync() { assert(_tracking_level > NMT_off, "NMT is not enabled"); @@ -487,6 +498,13 @@ pending_recorders = _global_recorder; _global_recorder = NULL; } + + // see if NMT has too many outstanding recorder instances, it usually + // means that worker thread is lagging behind in processing them. + if (!AutoShutdownNMT) { + _slowdown_calling_thread = (MemRecorder::_instance_count > MAX_RECORDER_THREAD_RATIO * _thread_count); + } + // check _worker_thread with lock to avoid racing condition if (_worker_thread != NULL) { _worker_thread->at_sync_point(pending_recorders, InstanceKlass::number_of_instance_classes()); @@ -529,7 +547,10 @@ assert(_worker_thread == NULL, "Just Check"); _worker_thread = new (std::nothrow) MemTrackWorker(); if (_worker_thread == NULL || _worker_thread->has_error()) { - shutdown(NMT_initialization); + if (_worker_thread != NULL) { + delete _worker_thread; + _worker_thread = NULL; + } return false; } _worker_thread->start(); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/services/memTracker.hpp --- a/src/share/vm/services/memTracker.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/services/memTracker.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -84,14 +84,15 @@ static inline bool baseline() { return false; } static inline bool has_baseline() { return false; } + static inline void set_autoShutdown(bool value) { } static void shutdown(ShutdownReason reason) { } - static inline bool shutdown_in_progress() { } + static inline bool shutdown_in_progress() { return false; } static bool print_memory_usage(BaselineOutputer& out, size_t unit, - bool summary_only = true) { } + bool summary_only = true) { return false; } static bool compare_memory_usage(BaselineOutputer& out, size_t unit, - bool summary_only = true) { } + bool summary_only = true) { return false; } - static bool wbtest_wait_for_data_merge() { } + static bool wbtest_wait_for_data_merge() { return false; } static inline void sync() { } static inline void thread_exiting(JavaThread* thread) { } @@ -238,6 +239,16 @@ // if native memory tracking tracks callsite static inline bool track_callsite() { return _tracking_level == NMT_detail; } + // NMT automatically shuts itself down under extreme situation by default. + // When the value is set to false, NMT will try its best to stay alive, + // even it has to slow down VM. + static inline void set_autoShutdown(bool value) { + AutoShutdownNMT = value; + if (AutoShutdownNMT && _slowdown_calling_thread) { + _slowdown_calling_thread = false; + } + } + // shutdown native memory tracking capability. Native memory tracking // can be shutdown by VM when it encounters low memory scenarios. // Memory tracker should gracefully shutdown itself, and preserve the @@ -507,6 +518,10 @@ // although NMT is still procesing current generation, but // there is not more recorder to process, set idle state static volatile bool _worker_thread_idle; + + // if NMT should slow down calling thread to allow + // worker thread to catch up + static volatile bool _slowdown_calling_thread; }; #endif // !INCLUDE_NMT diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/services/memoryManager.cpp diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/services/memoryManager.hpp diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/services/memoryPool.cpp diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/services/memoryPool.hpp diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/services/memoryService.cpp --- a/src/share/vm/services/memoryService.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/services/memoryService.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -240,6 +240,7 @@ void MemoryService::add_generation_memory_pool(Generation* gen, MemoryManager* major_mgr, MemoryManager* minor_mgr) { + guarantee(gen != NULL, "No generation for memory pool"); Generation::Name kind = gen->kind(); int index = _pools_list->length(); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/services/memoryService.hpp diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/services/nmtDCmd.cpp --- a/src/share/vm/services/nmtDCmd.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/services/nmtDCmd.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -49,6 +49,9 @@ _shutdown("shutdown", "request runtime to shutdown itself and free the " \ "memory used by runtime.", "BOOLEAN", false, "false"), + _auto_shutdown("autoShutdown", "automatically shutdown itself under " \ + "stress situation", + "BOOLEAN", true, "true"), #ifndef PRODUCT _debug("debug", "print tracker statistics. Debug only, not thread safe", \ "BOOLEAN", false, "false"), @@ -61,6 +64,7 @@ _dcmdparser.add_dcmd_option(&_summary_diff); _dcmdparser.add_dcmd_option(&_detail_diff); _dcmdparser.add_dcmd_option(&_shutdown); + _dcmdparser.add_dcmd_option(&_auto_shutdown); #ifndef PRODUCT _dcmdparser.add_dcmd_option(&_debug); #endif @@ -84,17 +88,19 @@ } int nopt = 0; - if(_summary.is_set() && _summary.value()) { ++nopt; } - if(_detail.is_set() && _detail.value()) { ++nopt; } - if(_baseline.is_set() && _baseline.value()) { ++nopt; } - if(_summary_diff.is_set() && _summary_diff.value()) { ++nopt; } - if(_detail_diff.is_set() && _detail_diff.value()) { ++nopt; } - if(_shutdown.is_set() && _shutdown.value()) { ++nopt; } + if (_summary.is_set() && _summary.value()) { ++nopt; } + if (_detail.is_set() && _detail.value()) { ++nopt; } + if (_baseline.is_set() && _baseline.value()) { ++nopt; } + if (_summary_diff.is_set() && _summary_diff.value()) { ++nopt; } + if (_detail_diff.is_set() && _detail_diff.value()) { ++nopt; } + if (_shutdown.is_set() && _shutdown.value()) { ++nopt; } + if (_auto_shutdown.is_set()) { ++nopt; } + #ifndef PRODUCT - if(_debug.is_set() && _debug.value()) { ++nopt; } + if (_debug.is_set() && _debug.value()) { ++nopt; } #endif - if(nopt > 1) { + if (nopt > 1) { output()->print_cr("At most one of the following option can be specified: " \ "summary, detail, baseline, summary.diff, detail.diff, shutdown" #ifndef PRODUCT @@ -156,6 +162,8 @@ MemTracker::shutdown(MemTracker::NMT_shutdown_user); output()->print_cr("Shutdown is in progress, it will take a few moments to " \ "completely shutdown"); + } else if (_auto_shutdown.is_set()) { + MemTracker::set_autoShutdown(_auto_shutdown.value()); } else { ShouldNotReachHere(); output()->print_cr("Unknown command"); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/services/nmtDCmd.hpp --- a/src/share/vm/services/nmtDCmd.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/services/nmtDCmd.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -39,6 +39,7 @@ DCmdArgument _summary_diff; DCmdArgument _detail_diff; DCmdArgument _shutdown; + DCmdArgument _auto_shutdown; #ifndef PRODUCT DCmdArgument _debug; #endif diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/utilities/debug.cpp --- a/src/share/vm/utilities/debug.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/utilities/debug.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -248,10 +248,6 @@ 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()"); } @@ -612,18 +608,6 @@ return CodeCache::find_nmethod((address)addr); } -static address same_page(address x, address y) { - intptr_t page_bits = -os::vm_page_size(); - if ((intptr_t(x) & page_bits) == (intptr_t(y) & page_bits)) { - return x; - } else if (x > y) { - return (address)(intptr_t(y) | ~page_bits) + 1; - } else { - return (address)(intptr_t(y) & page_bits); - } -} - - // Another interface that isn't ambiguous in dbx. // Can we someday rename the other find to hsfind? extern "C" void hsfind(intptr_t x) { diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/utilities/debug.hpp --- a/src/share/vm/utilities/debug.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/utilities/debug.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -192,12 +192,6 @@ 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 @@ const char* message); void report_should_not_call(const char* file, int line); void report_should_not_reach_here(const char* file, int line); -void report_should_not_reach_here2(const char* file, int line, const char* message); void report_unimplemented(const char* file, int line); void report_untested(const char* file, int line, const char* message); diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/utilities/globalDefinitions.cpp --- a/src/share/vm/utilities/globalDefinitions.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/utilities/globalDefinitions.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -355,3 +355,33 @@ return size_t(result); } + +#ifndef PRODUCT + +void GlobalDefinitions::test_globals() { + intptr_t page_sizes[] = { os::vm_page_size(), 4096, 8192, 65536, 2*1024*1024 }; + const int num_page_sizes = sizeof(page_sizes) / sizeof(page_sizes[0]); + + for (int i = 0; i < num_page_sizes; i++) { + intptr_t page_size = page_sizes[i]; + + address a_page = (address)(10*page_size); + + // Check that address within page is returned as is + assert(clamp_address_in_page(a_page, a_page, page_size) == a_page, "incorrect"); + assert(clamp_address_in_page(a_page + 128, a_page, page_size) == a_page + 128, "incorrect"); + assert(clamp_address_in_page(a_page + page_size - 1, a_page, page_size) == a_page + page_size - 1, "incorrect"); + + // Check that address above page returns start of next page + assert(clamp_address_in_page(a_page + page_size, a_page, page_size) == a_page + page_size, "incorrect"); + assert(clamp_address_in_page(a_page + page_size + 1, a_page, page_size) == a_page + page_size, "incorrect"); + assert(clamp_address_in_page(a_page + page_size*5 + 1, a_page, page_size) == a_page + page_size, "incorrect"); + + // Check that address below page returns start of page + assert(clamp_address_in_page(a_page - 1, a_page, page_size) == a_page, "incorrect"); + assert(clamp_address_in_page(a_page - 2*page_size - 1, a_page, page_size) == a_page, "incorrect"); + assert(clamp_address_in_page(a_page - 5*page_size - 1, a_page, page_size) == a_page, "incorrect"); + } +} + +#endif // PRODUCT diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/utilities/globalDefinitions.hpp --- a/src/share/vm/utilities/globalDefinitions.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/utilities/globalDefinitions.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -419,6 +419,24 @@ return align_size_up(offset, HeapWordsPerLong); } +// Clamp an address to be within a specific page +// 1. If addr is on the page it is returned as is +// 2. If addr is above the page_address the start of the *next* page will be returned +// 3. Otherwise, if addr is below the page_address the start of the page will be returned +inline address clamp_address_in_page(address addr, address page_address, intptr_t page_size) { + if (align_size_down(intptr_t(addr), page_size) == align_size_down(intptr_t(page_address), page_size)) { + // address is in the specified page, just return it as is + return addr; + } else if (addr > page_address) { + // address is above specified page, return start of next page + return (address)align_size_down(intptr_t(page_address), page_size) + page_size; + } else { + // address is below specified page, return start of page + return (address)align_size_down(intptr_t(page_address), page_size); + } +} + + // The expected size in bytes of a cache line, used to pad data structures. #define DEFAULT_CACHE_LINE_SIZE 64 @@ -1296,4 +1314,15 @@ return *(void**)addr; } + +#ifndef PRODUCT + +// For unit testing only +class GlobalDefinitions { +public: + static void test_globals(); +}; + +#endif // PRODUCT + #endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_HPP diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/utilities/utf8.cpp --- a/src/share/vm/utilities/utf8.cpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/utilities/utf8.cpp Fri Apr 12 10:14:42 2013 +0100 @@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -180,11 +180,12 @@ } // converts a utf8 string to quoted ascii -void UTF8::as_quoted_ascii(const char* utf8_str, char* buf, int buflen) { +void UTF8::as_quoted_ascii(const char* utf8_str, int utf8_length, char* buf, int buflen) { const char *ptr = utf8_str; + const char *utf8_end = ptr + utf8_length; char* p = buf; char* end = buf + buflen; - while (*ptr != '\0') { + while (ptr < utf8_end) { jchar c; ptr = UTF8::next(ptr, &c); if (c >= 32 && c < 127) { @@ -196,6 +197,7 @@ p += 6; } } + assert(p < end, "sanity"); *p = '\0'; } diff -r 3d641132f83b -r 124ca22437b1 src/share/vm/utilities/utf8.hpp --- a/src/share/vm/utilities/utf8.hpp Tue Feb 26 16:16:54 2013 -0800 +++ b/src/share/vm/utilities/utf8.hpp Fri Apr 12 10:14:42 2013 +0100 @@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,7 @@ static int quoted_ascii_length(const char* utf8_str, int utf8_length); // converts a utf8 string to quoted ascii - static void as_quoted_ascii(const char* utf8_str, char* buf, int buflen); + static void as_quoted_ascii(const char* utf8_str, int utf8_length, char* buf, int buflen); // converts a quoted ascii string to utf8 string. returns the original // string unchanged if nothing needs to be done. diff -r 3d641132f83b -r 124ca22437b1 test/compiler/5091921/Test6890943.sh --- a/test/compiler/5091921/Test6890943.sh Tue Feb 26 16:16:54 2013 -0800 +++ b/test/compiler/5091921/Test6890943.sh Fri Apr 12 10:14:42 2013 +0100 @@ -22,26 +22,16 @@ # questions. # # - +## some tests require path to find test source dir if [ "${TESTSRC}" = "" ] then - echo "TESTSRC not set. Test cannot execute. Failed." - exit 1 + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" fi echo "TESTSRC=${TESTSRC}" -if [ "${TESTJAVA}" = "" ] -then - echo "TESTJAVA not set. Test cannot execute. Failed." - exit 1 -fi -echo "TESTJAVA=${TESTJAVA}" -if [ "${TESTCLASSES}" = "" ] -then - echo "TESTCLASSES not set. Test cannot execute. Failed." - exit 1 -fi -echo "TESTCLASSES=${TESTCLASSES}" -echo "CLASSPATH=${CLASSPATH}" +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh + set -x @@ -50,7 +40,7 @@ cp ${TESTSRC}/output6890943.txt . cp ${TESTSRC}/Test6890943.sh . -${TESTJAVA}/bin/javac -d . Test6890943.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} -d . Test6890943.java ${TESTJAVA}/bin/java -XX:-PrintVMOptions -XX:+IgnoreUnrecognizedVMOptions ${TESTVMOPTS} Test6890943 < input6890943.txt > pretest.out 2>&1 diff -r 3d641132f83b -r 124ca22437b1 test/compiler/5091921/Test7005594.sh --- a/test/compiler/5091921/Test7005594.sh Tue Feb 26 16:16:54 2013 -0800 +++ b/test/compiler/5091921/Test7005594.sh Fri Apr 12 10:14:42 2013 +0100 @@ -22,26 +22,15 @@ # questions. # # - +## some tests require path to find test source dir if [ "${TESTSRC}" = "" ] then - echo "TESTSRC not set. Test cannot execute. Failed." - exit 1 + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" fi echo "TESTSRC=${TESTSRC}" -if [ "${TESTJAVA}" = "" ] -then - echo "TESTJAVA not set. Test cannot execute. Failed." - exit 1 -fi -echo "TESTJAVA=${TESTJAVA}" -if [ "${TESTCLASSES}" = "" ] -then - echo "TESTCLASSES not set. Test cannot execute. Failed." - exit 1 -fi -echo "TESTCLASSES=${TESTCLASSES}" -echo "CLASSPATH=${CLASSPATH}" +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh # Amount of physical memory in megabytes MEM=0 @@ -87,7 +76,7 @@ cp ${TESTSRC}/Test7005594.java . cp ${TESTSRC}/Test7005594.sh . -${TESTJAVA}/bin/javac -d . Test7005594.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} -d . Test7005594.java ${TESTJAVA}/bin/java ${TESTVMOPTS} -Xms1600m -XX:+IgnoreUnrecognizedVMOptions -XX:-ZapUnusedHeapArea -Xcomp -XX:CompileOnly=Test7005594.test Test7005594 > test.out 2>&1 diff -r 3d641132f83b -r 124ca22437b1 test/compiler/6857159/Test6857159.sh --- a/test/compiler/6857159/Test6857159.sh Tue Feb 26 16:16:54 2013 -0800 +++ b/test/compiler/6857159/Test6857159.sh Fri Apr 12 10:14:42 2013 +0100 @@ -22,33 +22,22 @@ # questions. # # - +## some tests require path to find test source dir if [ "${TESTSRC}" = "" ] then - echo "TESTSRC not set. Test cannot execute. Failed." - exit 1 + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" fi echo "TESTSRC=${TESTSRC}" -if [ "${TESTJAVA}" = "" ] -then - echo "TESTJAVA not set. Test cannot execute. Failed." - exit 1 -fi -echo "TESTJAVA=${TESTJAVA}" -if [ "${TESTCLASSES}" = "" ] -then - echo "TESTCLASSES not set. Test cannot execute. Failed." - exit 1 -fi -echo "TESTCLASSES=${TESTCLASSES}" -echo "CLASSPATH=${CLASSPATH}" +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh set -x cp ${TESTSRC}/Test6857159.java . cp ${TESTSRC}/Test6857159.sh . -${TESTJAVA}/bin/javac -d . Test6857159.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} -d . Test6857159.java ${TESTJAVA}/bin/java ${TESTVMOPTS} -Xbatch -XX:+PrintCompilation -XX:CompileOnly=Test6857159\$ct.run Test6857159 > test.out 2>&1 diff -r 3d641132f83b -r 124ca22437b1 test/compiler/7068051/Test7068051.sh --- a/test/compiler/7068051/Test7068051.sh Tue Feb 26 16:16:54 2013 -0800 +++ b/test/compiler/7068051/Test7068051.sh Fri Apr 12 10:14:42 2013 +0100 @@ -22,28 +22,24 @@ # questions. # # - +## some tests require path to find test source dir if [ "${TESTSRC}" = "" ] then - echo "TESTSRC not set. Test cannot execute. Failed." - exit 1 + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" fi echo "TESTSRC=${TESTSRC}" -if [ "${TESTJAVA}" = "" ] -then - echo "TESTJAVA not set. Test cannot execute. Failed." - exit 1 -fi -echo "TESTJAVA=${TESTJAVA}" +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh set -x -${TESTJAVA}/bin/jar xf ${TESTJAVA}/jre/lib/javaws.jar -${TESTJAVA}/bin/jar cf foo.jar * +${COMPILEJAVA}/bin/jar xf ${COMPILEJAVA}/jre/lib/javaws.jar +${COMPILEJAVA}/bin/jar cf foo.jar * cp ${TESTSRC}/Test7068051.java ./ -${TESTJAVA}/bin/jar -uf0 foo.jar Test7068051.java +${COMPILEJAVA}/bin/jar -uf0 foo.jar Test7068051.java -${TESTJAVA}/bin/javac -d . Test7068051.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} -d . Test7068051.java ${TESTJAVA}/bin/java ${TESTVMOPTS} -showversion -Xbatch Test7068051 foo.jar diff -r 3d641132f83b -r 124ca22437b1 test/compiler/7070134/Test7070134.sh --- a/test/compiler/7070134/Test7070134.sh Tue Feb 26 16:16:54 2013 -0800 +++ b/test/compiler/7070134/Test7070134.sh Fri Apr 12 10:14:42 2013 +0100 @@ -22,33 +22,22 @@ # questions. # # - +## some tests require path to find test source dir if [ "${TESTSRC}" = "" ] then - echo "TESTSRC not set. Test cannot execute. Failed." - exit 1 + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" fi echo "TESTSRC=${TESTSRC}" -if [ "${TESTJAVA}" = "" ] -then - echo "TESTJAVA not set. Test cannot execute. Failed." - exit 1 -fi -echo "TESTJAVA=${TESTJAVA}" -if [ "${TESTCLASSES}" = "" ] -then - echo "TESTCLASSES not set. Test cannot execute. Failed." - exit 1 -fi -echo "TESTCLASSES=${TESTCLASSES}" -echo "CLASSPATH=${CLASSPATH}" +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh set -x cp ${TESTSRC}/Stemmer.java . cp ${TESTSRC}/words . -${TESTJAVA}/bin/javac -d . Stemmer.java +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} -d . Stemmer.java ${TESTJAVA}/bin/java ${TESTVMOPTS} -Xbatch Stemmer words > test.out 2>&1 diff -r 3d641132f83b -r 124ca22437b1 test/compiler/7200264/Test7200264.sh --- a/test/compiler/7200264/Test7200264.sh Tue Feb 26 16:16:54 2013 -0800 +++ b/test/compiler/7200264/Test7200264.sh Fri Apr 12 10:14:42 2013 +0100 @@ -23,50 +23,15 @@ # # +## some tests require path to find test source dir if [ "${TESTSRC}" = "" ] then - echo "TESTSRC not set. Test cannot execute. Failed." - exit 1 + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" fi echo "TESTSRC=${TESTSRC}" -if [ "${TESTJAVA}" = "" ] -then - echo "TESTJAVA not set. Test cannot execute. Failed." - exit 1 -fi -echo "TESTJAVA=${TESTJAVA}" -if [ "${TESTCLASSES}" = "" ] -then - echo "TESTCLASSES not set. Test cannot execute. Failed." - exit 1 -fi -echo "TESTCLASSES=${TESTCLASSES}" -echo "CLASSPATH=${CLASSPATH}" - -# set platform-dependent variables -OS=`uname -s` -case "$OS" in - SunOS | Linux | Darwin ) - NULL=/dev/null - PS=":" - FS="/" - ;; - Windows_* ) - NULL=NUL - PS=";" - FS="\\" - ;; - CYGWIN_* ) - NULL=/dev/null - PS=";" - FS="/" - ;; - * ) - echo "Unrecognized system!" - exit 1; - ;; -esac - +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Xinternalversion | sed 's/amd64/x86/' | grep "x86" | grep "Server VM" | grep "debug" @@ -88,7 +53,7 @@ fi cp ${TESTSRC}${FS}TestIntVect.java . -${TESTJAVA}${FS}bin${FS}javac -d . TestIntVect.java +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} -d . TestIntVect.java ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 -XX:+PrintCompilation -XX:+TraceNewVectors TestIntVect > test.out 2>&1 diff -r 3d641132f83b -r 124ca22437b1 test/compiler/8009761/Test8009761.java --- a/test/compiler/8009761/Test8009761.java Tue Feb 26 16:16:54 2013 -0800 +++ b/test/compiler/8009761/Test8009761.java Fri Apr 12 10:14:42 2013 +0100 @@ -25,7 +25,7 @@ * @test * @bug 8009761 * @summary Deoptimization on sparc doesn't set Llast_SP correctly in the interpreter frames it creates - * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation Test8009761 + * @run main/othervm -Xmixed -XX:-UseOnStackReplacement -XX:-BackgroundCompilation Test8009761 * */ diff -r 3d641132f83b -r 124ca22437b1 test/compiler/whitebox/CompilerWhiteBoxTest.java --- a/test/compiler/whitebox/CompilerWhiteBoxTest.java Tue Feb 26 16:16:54 2013 -0800 +++ b/test/compiler/whitebox/CompilerWhiteBoxTest.java Fri Apr 12 10:14:42 2013 +0100 @@ -35,6 +35,8 @@ 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 @@ } } - 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 @@ } 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 @@ 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 @@ protected final int compile() { int result = 0; - for (int i = 0; i < COMPILE_THRESHOLD; ++i) { + int count = Math.max(COMPILE_THRESHOLD, 150000); + for (int i = 0; i < count; ++i) { result += method(); } + System.out.println("method was invoked " + count + " times"); return result; } - protected int method() { return 42; } diff -r 3d641132f83b -r 124ca22437b1 test/compiler/whitebox/DeoptimizeAllTest.java --- a/test/compiler/whitebox/DeoptimizeAllTest.java Tue Feb 26 16:16:54 2013 -0800 +++ b/test/compiler/whitebox/DeoptimizeAllTest.java Fri Apr 12 10:14:42 2013 +0100 @@ -32,12 +32,12 @@ public class DeoptimizeAllTest extends CompilerWhiteBoxTest { public static void main(String[] args) throws Exception { + // to prevent inlining #method into #compile() + WHITE_BOX.setDontInlineMethod(METHOD, true); new DeoptimizeAllTest().runTest(); } protected void test() throws Exception { - // to prevent inlining #method into #compile() - WHITE_BOX.setDontInlineMethod(METHOD, true); compile(); checkCompiled(METHOD); WHITE_BOX.deoptimizeAll(); diff -r 3d641132f83b -r 124ca22437b1 test/compiler/whitebox/DeoptimizeMethodTest.java --- a/test/compiler/whitebox/DeoptimizeMethodTest.java Tue Feb 26 16:16:54 2013 -0800 +++ b/test/compiler/whitebox/DeoptimizeMethodTest.java Fri Apr 12 10:14:42 2013 +0100 @@ -32,12 +32,12 @@ public class DeoptimizeMethodTest extends CompilerWhiteBoxTest { public static void main(String[] args) throws Exception { + // to prevent inlining #method into #compile() + WHITE_BOX.setDontInlineMethod(METHOD, true); new DeoptimizeMethodTest().runTest(); } protected void test() throws Exception { - // to prevent inlining #method into #compile() - WHITE_BOX.setDontInlineMethod(METHOD, true); compile(); checkCompiled(METHOD); WHITE_BOX.deoptimizeMethod(METHOD); diff -r 3d641132f83b -r 124ca22437b1 test/compiler/whitebox/IsMethodCompilableTest.java --- a/test/compiler/whitebox/IsMethodCompilableTest.java Tue Feb 26 16:16:54 2013 -0800 +++ b/test/compiler/whitebox/IsMethodCompilableTest.java Fri Apr 12 10:14:42 2013 +0100 @@ -44,6 +44,8 @@ } 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 @@ "Warning: test is not applicable if PerMethodRecompilationCutoff == Inf"); return; } - // to prevent inlining #method into #compile() - WHITE_BOX.setDontInlineMethod(METHOD, true); boolean madeNotCompilable = false; for (long i = 0; i < PER_METHOD_RECOMPILATION_CUTOFF; ++i) { diff -r 3d641132f83b -r 124ca22437b1 test/compiler/whitebox/MakeMethodNotCompilableTest.java --- a/test/compiler/whitebox/MakeMethodNotCompilableTest.java Tue Feb 26 16:16:54 2013 -0800 +++ b/test/compiler/whitebox/MakeMethodNotCompilableTest.java Fri Apr 12 10:14:42 2013 +0100 @@ -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(); } diff -r 3d641132f83b -r 124ca22437b1 test/gc/6941923/test6941923.sh --- a/test/gc/6941923/test6941923.sh Tue Feb 26 16:16:54 2013 -0800 +++ b/test/gc/6941923/test6941923.sh Fri Apr 12 10:14:42 2013 +0100 @@ -5,38 +5,25 @@ ## @author yqi ## @run shell test6941923.sh ## +## some tests require path to find test source dir +if [ "${TESTSRC}" = "" ] +then + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" +fi +echo "TESTSRC=${TESTSRC}" +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh ## skip on windows OS=`uname -s` case "$OS" in - SunOS | Linux | Darwin ) - NULL=/dev/null - PS=":" - FS="/" - ;; Windows_* | CYGWIN_* ) echo "Test skipped for Windows" exit 0 ;; - * ) - echo "Unrecognized system!" - exit 1; - ;; esac -if [ "${JAVA_HOME}" = "" ] -then - echo "JAVA_HOME not set" - exit 0 -fi - -$JAVA_HOME/bin/java ${TESTVMOPTS} -version > $NULL 2>&1 - -if [ $? != 0 ]; then - echo "Wrong JAVA_HOME? JAVA_HOME: $JAVA_HOME" - exit $? -fi - # create a small test case testname="Test" if [ -e ${testname}.java ]; then @@ -96,10 +83,10 @@ msgfail="failed" gclogsize="16K" filesize=$((16*1024)) -$JAVA_HOME/bin/javac ${testname}.java > $NULL 2>&1 +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${testname}.java > $NULL 2>&1 if [ $? != 0 ]; then - echo "$JAVA_HOME/bin/javac ${testname}.java $fail" + echo "${COMPILEJAVA}/bin/javac ${testname}.java $fail" exit -1 fi @@ -119,7 +106,7 @@ options="-Xloggc:$logfile -XX:+UseConcMarkSweepGC -XX:+PrintGC -XX:+PrintGCDetails -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=1 -XX:GCLogFileSize=$gclogsize" echo "Test gc log rotation in same file, wait for $tts minutes ...." -$JAVA_HOME/bin/java ${TESTVMOPTS} $options $testname $tts +${TESTJAVA}/bin/java $options $testname $tts if [ $? != 0 ]; then echo "$msgfail" exit -1 @@ -148,7 +135,7 @@ numoffiles=3 options="-Xloggc:$logfile -XX:+UseConcMarkSweepGC -XX:+PrintGC -XX:+PrintGCDetails -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=$numoffiles -XX:GCLogFileSize=$gclogsize" echo "Test gc log rotation in $numoffiles files, wait for $tts minutes ...." -$JAVA_HOME/bin/java ${TESTVMOPTS} $options $testname $tts +${TESTJAVA}/bin/java $options $testname $tts if [ $? != 0 ]; then echo "$msgfail" exit -1 diff -r 3d641132f83b -r 124ca22437b1 test/gc/TestVerifyBeforeGCDuringStartup.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/TestVerifyBeforeGCDuringStartup.java Fri Apr 12 10:14:42 2013 +0100 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 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 + * 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. + */ + +/* @test TestVerifyBeforeGCDuringStartup.java + * @key gc + * @bug 8010463 + * @summary Simple test run with -XX:+VerifyBeforeGC -XX:-UseTLAB to verify 8010463 + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +public class TestVerifyBeforeGCDuringStartup { + public static void main(String args[]) throws Exception { + ProcessBuilder pb = + ProcessTools.createJavaProcessBuilder(System.getProperty("test.vm.opts"), + "-XX:-UseTLAB", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+VerifyBeforeGC", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("[Verifying"); + output.shouldHaveExitValue(0); + } +} diff -r 3d641132f83b -r 124ca22437b1 test/gc/metaspace/ClassMetaspaceSizeInJmapHeap.java --- a/test/gc/metaspace/ClassMetaspaceSizeInJmapHeap.java Tue Feb 26 16:16:54 2013 -0800 +++ b/test/gc/metaspace/ClassMetaspaceSizeInJmapHeap.java Fri Apr 12 10:14:42 2013 +0100 @@ -39,8 +39,10 @@ public static void main(String[] args) throws Exception { String pid = Integer.toString(ProcessTools.getProcessId()); - ProcessBuilder pb = new ProcessBuilder(); - pb.command(JDKToolFinder.getJDKTool("jmap"), "-heap", pid); + JDKToolLauncher jmap = JDKToolLauncher.create("jmap") + .addToolArg("-heap") + .addToolArg(pid); + ProcessBuilder pb = new ProcessBuilder(jmap.getCommand()); File out = new File("ClassMetaspaceSizeInJmapHeap.stdout.txt"); pb.redirectOutput(out); diff -r 3d641132f83b -r 124ca22437b1 test/runtime/6626217/Test6626217.sh --- a/test/runtime/6626217/Test6626217.sh Tue Feb 26 16:16:54 2013 -0800 +++ b/test/runtime/6626217/Test6626217.sh Fri Apr 12 10:14:42 2013 +0100 @@ -27,78 +27,29 @@ # @summary Loader-constraint table allows arrays instead of only the base-classes # @run shell Test6626217.sh # - +## some tests require path to find test source dir if [ "${TESTSRC}" = "" ] - then TESTSRC=. -fi - -if [ "${TESTJAVA}" = "" ] then - PARENT=`dirname \`which java\`` - TESTJAVA=`dirname ${PARENT}` - echo "TESTJAVA not set, selecting " ${TESTJAVA} - echo "If this is incorrect, try setting the variable manually." -fi - -if [ "${TESTCLASSES}" = "" ] -then - echo "TESTCLASSES not set. Test cannot execute. Failed." - exit 1 + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" fi - -# set platform-dependent variables -OS=`uname -s` -case "$OS" in - SunOS | Linux | Darwin ) - NULL=/dev/null - PS=":" - FS="/" - RM=/bin/rm - CP=/bin/cp - MV=/bin/mv - ;; - Windows_* ) - NULL=NUL - PS=";" - FS="\\" - RM=rm - CP=cp - MV=mv - ;; - CYGWIN_* ) - NULL=/dev/null - PS=";" - FS="/" - RM=rm - CP=cp - MV=mv - ;; - * ) - echo "Unrecognized system!" - exit 1; - ;; -esac - -JEMMYPATH=${CPAPPEND} -CLASSPATH=.${PS}${TESTCLASSES}${PS}${JEMMYPATH} ; export CLASSPATH - -THIS_DIR=`pwd` +echo "TESTSRC=${TESTSRC}" +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh JAVA=${TESTJAVA}${FS}bin${FS}java -JAVAC=${TESTJAVA}${FS}bin${FS}javac - -${JAVA} ${TESTVMOPTS} -version +JAVAC=${COMPILEJAVA}${FS}bin${FS}javac # Current directory is scratch directory, copy all the test source there # (for the subsequent moves to work). -${CP} ${TESTSRC}${FS}* ${THIS_DIR} +${CP} ${TESTSRC}${FS}* ${THIS_DIR} # A Clean Compile: this line will probably fail within jtreg as have a clean dir: ${RM} -f *.class *.impl many_loader.java # Compile all the usual suspects, including the default 'many_loader' ${CP} many_loader1.java.foo many_loader.java -${JAVAC} -source 1.4 -target 1.4 -Xlint *.java +${JAVAC} ${TESTJAVACOPTS} -source 1.4 -target 1.4 -Xlint *.java # Rename the class files, so the custom loader (and not the system loader) will find it ${MV} from_loader2.class from_loader2.impl2 @@ -106,7 +57,7 @@ # Compile the next version of 'many_loader' ${MV} many_loader.class many_loader.impl1 ${CP} many_loader2.java.foo many_loader.java -${JAVAC} -source 1.4 -target 1.4 -Xlint many_loader.java +${JAVAC} ${TESTJAVACOPTS} -source 1.4 -target 1.4 -Xlint many_loader.java # Rename the class file, so the custom loader (and not the system loader) will find it ${MV} many_loader.class many_loader.impl2 diff -r 3d641132f83b -r 124ca22437b1 test/runtime/6878713/Test6878713.sh --- a/test/runtime/6878713/Test6878713.sh Tue Feb 26 16:16:54 2013 -0800 +++ b/test/runtime/6878713/Test6878713.sh Fri Apr 12 10:14:42 2013 +0100 @@ -1,71 +1,137 @@ #!/bin/sh +# +# Copyright (c) 2011, 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 +# 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. +# + + + ## ## @test ## @bug 6878713 +## @bug 7030610 +## @bug 7037122 +## @bug 7123945 ## @summary Verifier heap corruption, relating to backward jsrs -## @run shell/timeout=120 Test6878713.sh +## @run shell Test6878713.sh ## - +## some tests require path to find test source dir if [ "${TESTSRC}" = "" ] -then TESTSRC=. -fi - -if [ "${TESTJAVA}" = "" ] then - PARENT=`dirname \`which java\`` - TESTJAVA=`dirname ${PARENT}` - echo "TESTJAVA not set, selecting " ${TESTJAVA} - echo "If this is incorrect, try setting the variable manually." + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" fi +echo "TESTSRC=${TESTSRC}" +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh -if [ "${TESTCLASSES}" = "" ] -then - echo "TESTCLASSES not set. Test cannot execute. Failed." - exit 1 +TARGET_CLASS=OOMCrashClass1960_2 + +echo "INFO: extracting the target class." +${COMPILEJAVA}${FS}bin${FS}jar xvf \ + ${TESTSRC}${FS}testcase.jar ${TARGET_CLASS}.class + +# remove any hs_err_pid that might exist here +rm -f hs_err_pid*.log + +echo "INFO: checking for 32-bit versus 64-bit VM." +${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -version 2>&1 \ + | grep "64-Bit [^ ][^ ]* VM" > /dev/null 2>&1 +status="$?" +if [ "$status" = 0 ]; then + echo "INFO: testing a 64-bit VM." + is_64_bit=true +else + echo "INFO: testing a 32-bit VM." fi -# set platform-dependent variables -OS=`uname -s` -case "$OS" in - SunOS | Linux | Darwin ) - NULL=/dev/null - PS=":" - FS="/" - ;; - Windows_* ) - NULL=NUL - PS=";" - FS="\\" - ;; - CYGWIN_* ) - NULL=/dev/null - PS=";" - FS="/" - ;; - * ) - echo "Unrecognized system!" - exit 1; - ;; -esac +if [ "$is_64_bit" = true ]; then + # limit is 768MB in 8-byte words (1024 * 1024 * 768 / 8) == 100663296 + MALLOC_MAX=100663296 +else + # limit is 768MB in 4-byte words (1024 * 1024 * 768 / 4) == 201326592 + MALLOC_MAX=201326592 +fi +echo "INFO: MALLOC_MAX=$MALLOC_MAX" + +echo "INFO: executing the target class." +# -XX:+PrintCommandLineFlags for debugging purposes +# -XX:+IgnoreUnrecognizedVMOptions so test will run on a VM without +# the new -XX:MallocMaxTestWords option +# -XX:+UnlockDiagnosticVMOptions so we can use -XX:MallocMaxTestWords +# -XX:MallocMaxTestWords limits malloc to $MALLOC_MAX +${TESTJAVA}${FS}bin${FS}java \ + -XX:+PrintCommandLineFlags \ + -XX:+IgnoreUnrecognizedVMOptions \ + -XX:+UnlockDiagnosticVMOptions \ + -XX:MallocMaxTestWords=$MALLOC_MAX \ + ${TESTVMOPTS} ${TARGET_CLASS} > test.out 2>&1 + +echo "INFO: begin contents of test.out:" +cat test.out +echo "INFO: end contents of test.out." -JEMMYPATH=${CPAPPEND} -CLASSPATH=.${PS}${TESTCLASSES}${PS}${JEMMYPATH} ; export CLASSPATH - -THIS_DIR=`pwd` - -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -version - -${TESTJAVA}${FS}bin${FS}jar xvf ${TESTSRC}${FS}testcase.jar +echo "INFO: checking for memory allocation error message." +# We are looking for this specific memory allocation failure mesg so +# we know we exercised the right allocation path with the test class: +MESG1="Native memory allocation (malloc) failed to allocate 25696531[0-9][0-9] bytes" +grep "$MESG1" test.out +status="$?" +if [ "$status" = 0 ]; then + echo "INFO: found expected memory allocation error message." +else + echo "INFO: did not find expected memory allocation error message." -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} OOMCrashClass1960_2 > test.out 2>&1 + # If we didn't find MESG1 above, then there are several scenarios: + # 1) -XX:MallocMaxTestWords is not supported by the current VM and we + # didn't fail TARGET_CLASS's memory allocation attempt; instead + # we failed to find TARGET_CLASS's main() method. The TARGET_CLASS + # is designed to provoke a memory allocation failure during class + # loading; we actually don't care about running the class which is + # why it doesn't have a main() method. + # 2) we failed a memory allocation, but not the one we were looking + # so it might be that TARGET_CLASS no longer tickles the same + # memory allocation code path + # 3) TARGET_CLASS reproduces the failure mode (SIGSEGV) fixed by + # 6878713 because the test is running on a pre-fix VM. + echo "INFO: checking for no main() method message." + MESG2="Error: Main method not found in class" + grep "$MESG2" test.out + status="$?" + if [ "$status" = 0 ]; then + echo "INFO: found no main() method message." + else + echo "FAIL: did not find no main() method message." + # status is non-zero for exit below -if [ -s core -o -s "hs_*.log" ] -then - cat hs*.log - echo "Test Failed" - exit 1 -else - echo "Test Passed" - exit 0 + if [ -s hs_err_pid*.log ]; then + echo "INFO: begin contents of hs_err_pid file:" + cat hs_err_pid*.log + echo "INFO: end contents of hs_err_pid file." + fi + fi fi + +if [ "$status" = 0 ]; then + echo "PASS: test found one of the expected messages." +fi +exit "$status" diff -r 3d641132f83b -r 124ca22437b1 test/runtime/6929067/Test6929067.sh --- a/test/runtime/6929067/Test6929067.sh Tue Feb 26 16:16:54 2013 -0800 +++ b/test/runtime/6929067/Test6929067.sh Fri Apr 12 10:14:42 2013 +0100 @@ -7,18 +7,15 @@ ## @compile T.java ## @run shell Test6929067.sh ## - +set -x if [ "${TESTSRC}" = "" ] -then TESTSRC=. +then + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" fi - -if [ "${TESTJAVA}" = "" ] -then - PARENT=`dirname \`which java\`` - TESTJAVA=`dirname ${PARENT}` - echo "TESTJAVA not set, selecting " ${TESTJAVA} - echo "If this is incorrect, try setting the variable manually." -fi +echo "TESTSRC=${TESTSRC}" +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh # set platform-dependent variables OS=`uname -s` @@ -107,7 +104,7 @@ fi -LD_LIBRARY_PATH=.:${TESTJAVA}/jre/lib/${ARCH}/${VMTYPE}:/usr/lib:$LD_LIBRARY_PATH +LD_LIBRARY_PATH=.:${COMPILEJAVA}/jre/lib/${ARCH}/${VMTYPE}:/usr/lib:$LD_LIBRARY_PATH export LD_LIBRARY_PATH cp ${TESTSRC}${FS}invoke.c . @@ -115,15 +112,16 @@ # Copy the result of our @compile action: cp ${TESTCLASSES}${FS}T.class . -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -fullversion - echo "Architecture: ${ARCH}" echo "Compilation flag: ${COMP_FLAG}" echo "VM type: ${VMTYPE}" +# Note pthread may not be found thus invoke creation will fail to be created. +# Check to ensure you have a /usr/lib/libpthread.so if you don't please look +# for /usr/lib/`uname -m`-linux-gnu version ensure to add that path to below compilation. gcc -DLINUX ${COMP_FLAG} -o invoke \ - -I${TESTJAVA}/include -I${TESTJAVA}/include/linux \ - -L${TESTJAVA}/jre/lib/${ARCH}/${VMTYPE} \ + -I${COMPILEJAVA}/include -I${COMPILEJAVA}/include/linux \ + -L${COMPILEJAVA}/jre/lib/${ARCH}/${VMTYPE} \ -ljvm -lpthread invoke.c ./invoke diff -r 3d641132f83b -r 124ca22437b1 test/runtime/7020373/Test7020373.sh --- a/test/runtime/7020373/Test7020373.sh Tue Feb 26 16:16:54 2013 -0800 +++ b/test/runtime/7020373/Test7020373.sh Fri Apr 12 10:14:42 2013 +0100 @@ -10,55 +10,15 @@ ## if [ "${TESTSRC}" = "" ] -then TESTSRC=. +then + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" fi - -if [ "${TESTJAVA}" = "" ] -then - PARENT=`dirname \`which java\`` - TESTJAVA=`dirname ${PARENT}` - echo "TESTJAVA not set, selecting " ${TESTJAVA} - echo "If this is incorrect, try setting the variable manually." -fi - -if [ "${TESTCLASSES}" = "" ] -then - echo "TESTCLASSES not set. Test cannot execute. Failed." - exit 1 -fi +echo "TESTSRC=${TESTSRC}" +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh -# set platform-dependent variables -OS=`uname -s` -case "$OS" in - SunOS | Linux | Darwin ) - NULL=/dev/null - PS=":" - FS="/" - ;; - Windows_* ) - NULL=NUL - PS=";" - FS="\\" - ;; - CYGWIN_* ) - NULL=/dev/null - PS=";" - FS="/" - ;; - * ) - echo "Unrecognized system!" - exit 1; - ;; -esac - -JEMMYPATH=${CPAPPEND} -CLASSPATH=.${PS}${TESTCLASSES}${PS}${JEMMYPATH} ; export CLASSPATH - -THIS_DIR=`pwd` - -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -version - -${TESTJAVA}${FS}bin${FS}jar xvf ${TESTSRC}${FS}testcase.jar +${COMPILEJAVA}${FS}bin${FS}jar xvf ${TESTSRC}${FS}testcase.jar ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} OOMCrashClass4000_1 > test.out 2>&1 diff -r 3d641132f83b -r 124ca22437b1 test/runtime/7051189/Xchecksig.sh --- a/test/runtime/7051189/Xchecksig.sh Tue Feb 26 16:16:54 2013 -0800 +++ b/test/runtime/7051189/Xchecksig.sh Fri Apr 12 10:14:42 2013 +0100 @@ -29,34 +29,22 @@ # if [ "${TESTSRC}" = "" ] - then TESTSRC=. +then + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" fi - -if [ "${TESTJAVA}" = "" ] -then - PARENT=`dirname \`which java\`` - TESTJAVA=`dirname ${PARENT}` - printf "TESTJAVA not set, selecting " ${TESTJAVA} - printf " If this is incorrect, try setting the variable manually.\n" -fi - +echo "TESTSRC=${TESTSRC}" +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh OS=`uname -s` case "$OS" in - SunOS | Linux | Darwin ) - FS="/" - ;; Windows_* | CYGWIN_* ) printf "Not testing libjsig.so on Windows. PASSED.\n " exit 0 ;; - * ) - printf "Not testing libjsig.so on unrecognised system. PASSED.\n " - exit 0 - ;; esac - JAVA=${TESTJAVA}${FS}bin${FS}java # LD_PRELOAD arch needs to match the binary we run, so run the java @@ -97,7 +85,7 @@ ;; esac -LIBJSIG=${TESTJAVA}${FS}jre${FS}lib${FS}${ARCH}${FS}libjsig.so +LIBJSIG=${COMPILEJAVA}${FS}jre${FS}lib${FS}${ARCH}${FS}libjsig.so # If libjsig and binary do not match, skip test. diff -r 3d641132f83b -r 124ca22437b1 test/runtime/7107135/Test7107135.sh --- a/test/runtime/7107135/Test7107135.sh Tue Feb 26 16:16:54 2013 -0800 +++ b/test/runtime/7107135/Test7107135.sh Fri Apr 12 10:14:42 2013 +0100 @@ -32,26 +32,19 @@ ## if [ "${TESTSRC}" = "" ] -then TESTSRC=. +then + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" fi - -if [ "${TESTJAVA}" = "" ] -then - PARENT=`dirname \`which java\`` - TESTJAVA=`dirname ${PARENT}` - echo "TESTJAVA not set, selecting " ${TESTJAVA} - echo "If this is incorrect, try setting the variable manually." -fi - -BIT_FLAG="" +echo "TESTSRC=${TESTSRC}" +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh # set platform-dependent variables OS=`uname -s` case "$OS" in Linux) - NULL=/dev/null - PS=":" - FS="/" + echo "Testing on Linux" ;; *) NULL=NUL @@ -64,7 +57,7 @@ ARCH=`uname -m` -THIS_DIR=`pwd` +THIS_DIR=. cp ${TESTSRC}${FS}*.java ${THIS_DIR} ${TESTJAVA}${FS}bin${FS}javac *.java diff -r 3d641132f83b -r 124ca22437b1 test/runtime/7110720/Test7110720.sh --- a/test/runtime/7110720/Test7110720.sh Tue Feb 26 16:16:54 2013 -0800 +++ b/test/runtime/7110720/Test7110720.sh Fri Apr 12 10:14:42 2013 +0100 @@ -12,22 +12,13 @@ # if [ "${TESTSRC}" = "" ] - then TESTSRC=. +then + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" fi - -if [ "${TESTJAVA}" = "" ] -then - PARENT=`dirname \`which java\`` - TESTJAVA=`dirname ${PARENT}` - echo "TESTJAVA not set, selecting " ${TESTJAVA} - echo "If this is incorrect, try setting the variable manually." -fi - -if [ "${TESTCLASSES}" = "" ] -then - echo "TESTCLASSES not set. Test cannot execute. Failed." - exit 1 -fi +echo "TESTSRC=${TESTSRC}" +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh # Jtreg sets TESTVMOPTS which may include -d64 which is # required to test a 64-bit JVM on some platforms. diff -r 3d641132f83b -r 124ca22437b1 test/runtime/7116786/Test7116786.java --- a/test/runtime/7116786/Test7116786.java Tue Feb 26 16:16:54 2013 -0800 +++ b/test/runtime/7116786/Test7116786.java Fri Apr 12 10:14:42 2013 +0100 @@ -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 @@ -338,9 +338,12 @@ "invalid constant pool index in ldc", "Invalid index in ldc"), - new Case("case58", "verifier.cpp", true, "verify_switch", + /* No longer a valid test case for bytecode version >= 51. Nonzero + * padding bytes are permitted with lookupswitch and tableswitch + * bytecodes as of JVMS 3d edition */ + new Case("case58", "verifier.cpp", false, "verify_switch", "bad switch padding", - "Nonzero padding byte in lookswitch or tableswitch"), + "Nonzero padding byte in lookupswitch or tableswitch"), new Case("case59", "verifier.cpp", true, "verify_switch", "tableswitch low is greater than high", diff -r 3d641132f83b -r 124ca22437b1 test/runtime/7158804/Test7158804.sh --- a/test/runtime/7158804/Test7158804.sh Tue Feb 26 16:16:54 2013 -0800 +++ b/test/runtime/7158804/Test7158804.sh Fri Apr 12 10:14:42 2013 +0100 @@ -10,13 +10,14 @@ ## @summary Improve config file parsing ## @run shell Test7158804.sh ## - -if [ "${TESTJAVA}" = "" ] +if [ "${TESTSRC}" = "" ] then - echo "TESTJAVA not set. Test cannot execute. Failed." - exit 1 + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" fi -echo "TESTJAVA=${TESTJAVA}" +echo "TESTSRC=${TESTSRC}" +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh rm -f .hotspotrc echo -XX:+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >.hotspotrc diff -r 3d641132f83b -r 124ca22437b1 test/runtime/7162488/Test7162488.sh --- a/test/runtime/7162488/Test7162488.sh Tue Feb 26 16:16:54 2013 -0800 +++ b/test/runtime/7162488/Test7162488.sh Fri Apr 12 10:14:42 2013 +0100 @@ -29,27 +29,13 @@ # if [ "${TESTSRC}" = "" ] - then TESTSRC=. -fi - -if [ "${TESTJAVA}" = "" ] then - PARENT=`dirname \`which java\`` - TESTJAVA=`dirname ${PARENT}` - printf "TESTJAVA not set, selecting " ${TESTJAVA} - printf " If this is incorrect, try setting the variable manually.\n" + TESTSRC=${PWD} + echo "TESTSRC not set. Using "${TESTSRC}" as default" fi - -# set platform-dependent variables -OS=`uname -s` -case "$OS" in - Windows_* ) - FS="\\" - ;; - * ) - FS="/" - ;; -esac +echo "TESTSRC=${TESTSRC}" +## Adding common setup Variables for running shell tests. +. ${TESTSRC}/../../test_env.sh JAVA=${TESTJAVA}${FS}bin${FS}java diff -r 3d641132f83b -r 124ca22437b1 test/runtime/8007736/TestStaticIF.java --- a/test/runtime/8007736/TestStaticIF.java Tue Feb 26 16:16:54 2013 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * Copyright (c) 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 - * 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. - * - */ - -/* - * @test - * @bug 8007736 - * @summary Test static interface method. - * @run main/othervm -Xverify:all TestStaticIF - */ - -public class TestStaticIF implements StaticMethodInInterface { - - public static void main(String[] args) { - System.out.printf("main: %s%n", StaticMethodInInterface.get()); - } -} - -interface StaticMethodInInterface { - - public static String get() { - return "Hello from StaticMethodInInterface.get()"; - } -} diff -r 3d641132f83b -r 124ca22437b1 test/runtime/8010389/VMThreadDlopen.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/8010389/VMThreadDlopen.java Fri Apr 12 10:14:42 2013 +0100 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 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 + * 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.io.File; + +/* + * @test + * @key regression + * @bug 8010389 + * @run main/othervm -Djava.library.path=. VMThreadDlopen + */ + +public class VMThreadDlopen { + public static void main(String[] args) throws Exception { + File file = new File("libbroken.so"); + file.createNewFile(); + try { + System.loadLibrary("broken"); + } catch (UnsatisfiedLinkError e) { + e.printStackTrace(); + // expected + } + } +} diff -r 3d641132f83b -r 124ca22437b1 test/runtime/CommandLine/BooleanFlagWithInvalidValue.java --- a/test/runtime/CommandLine/BooleanFlagWithInvalidValue.java Tue Feb 26 16:16:54 2013 -0800 +++ b/test/runtime/CommandLine/BooleanFlagWithInvalidValue.java Fri Apr 12 10:14:42 2013 +0100 @@ -33,17 +33,17 @@ public class BooleanFlagWithInvalidValue { public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-XX:+UseLargePages=8", "-version"); + "-XX:+PrintWarnings=8", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("Improperly specified VM option 'UseLargePages=8'"); + output.shouldContain("Improperly specified VM option 'PrintWarnings=8'"); output.shouldHaveExitValue(1); pb = ProcessTools.createJavaProcessBuilder( - "-XX:-UseLargePages=8", "-version"); + "-XX:-PrintWarnings=8", "-version"); output = new OutputAnalyzer(pb.start()); - output.shouldContain("Improperly specified VM option 'UseLargePages=8'"); + output.shouldContain("Improperly specified VM option 'PrintWarnings=8'"); output.shouldHaveExitValue(1); } } diff -r 3d641132f83b -r 124ca22437b1 test/runtime/CommandLine/FlagWithInvalidValue.java --- a/test/runtime/CommandLine/FlagWithInvalidValue.java Tue Feb 26 16:16:54 2013 -0800 +++ b/test/runtime/CommandLine/FlagWithInvalidValue.java Fri Apr 12 10:14:42 2013 +0100 @@ -33,10 +33,10 @@ public class FlagWithInvalidValue { public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-XX:ObjectAlignmentInBytes=v", "-version"); + "-XX:MaxRAMFraction=v", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("Improperly specified VM option 'ObjectAlignmentInBytes=v'"); + output.shouldContain("Improperly specified VM option 'MaxRAMFraction=v'"); output.shouldHaveExitValue(1); } } diff -r 3d641132f83b -r 124ca22437b1 test/runtime/CommandLine/NonBooleanFlagWithInvalidBooleanPrefix.java --- a/test/runtime/CommandLine/NonBooleanFlagWithInvalidBooleanPrefix.java Tue Feb 26 16:16:54 2013 -0800 +++ b/test/runtime/CommandLine/NonBooleanFlagWithInvalidBooleanPrefix.java Fri Apr 12 10:14:42 2013 +0100 @@ -33,17 +33,17 @@ public class NonBooleanFlagWithInvalidBooleanPrefix { public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-XX:-ObjectAlignmentInBytes=16", "-version"); + "-XX:-MaxRAMFraction=16", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("Unexpected +/- setting in VM option 'ObjectAlignmentInBytes=16'"); + output.shouldContain("Unexpected +/- setting in VM option 'MaxRAMFraction=16'"); output.shouldHaveExitValue(1); pb = ProcessTools.createJavaProcessBuilder( - "-XX:+ObjectAlignmentInBytes=16", "-version"); + "-XX:+MaxRAMFraction=16", "-version"); output = new OutputAnalyzer(pb.start()); - output.shouldContain("Unexpected +/- setting in VM option 'ObjectAlignmentInBytes=16'"); + output.shouldContain("Unexpected +/- setting in VM option 'MaxRAMFraction=16'"); output.shouldHaveExitValue(1); } diff -r 3d641132f83b -r 124ca22437b1 test/runtime/NMT/AllocTestType.java --- a/test/runtime/NMT/AllocTestType.java Tue Feb 26 16:16:54 2013 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 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 - * 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. - */ - -/* - * @test - * @summary Test consistency of NMT by leaking a few select allocations of the Test type and then verify visibility with jcmd - * @key nmt jcmd - * @library /testlibrary /testlibrary/whitebox - * @build AllocTestType - * @run main ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail AllocTestType - */ - -import com.oracle.java.testlibrary.*; -import sun.hotspot.WhiteBox; - -public class AllocTestType { - - public static void main(String args[]) throws Exception { - OutputAnalyzer output; - - // Grab my own PID - String pid = Integer.toString(ProcessTools.getProcessId()); - ProcessBuilder pb = new ProcessBuilder(); - - // Use WB API to alloc with the mtTest type - if (!WhiteBox.getWhiteBox().NMTAllocTest()) { - throw new Exception("Call to WB API NMTAllocTest() failed"); - } - - // Use WB API to ensure that all data has been merged before we continue - if (!WhiteBox.getWhiteBox().NMTWaitForDataMerge()) { - throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); - } - - // Run 'jcmd VM.native_memory summary' - pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary"}); - output = new OutputAnalyzer(pb.start()); - output.shouldContain("Test (reserved=512KB, committed=512KB)"); - - // Free the memory allocated by NMTAllocTest - if (!WhiteBox.getWhiteBox().NMTFreeTestMemory()) { - throw new Exception("Call to WB API NMTFreeTestMemory() failed"); - } - - // Use WB API to ensure that all data has been merged before we continue - if (!WhiteBox.getWhiteBox().NMTWaitForDataMerge()) { - throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); - } - output = new OutputAnalyzer(pb.start()); - output.shouldNotContain("Test (reserved="); - } -} diff -r 3d641132f83b -r 124ca22437b1 test/runtime/NMT/BaselineWithParameter.java --- a/test/runtime/NMT/BaselineWithParameter.java Tue Feb 26 16:16:54 2013 -0800 +++ b/test/runtime/NMT/BaselineWithParameter.java Fri Apr 12 10:14:42 2013 +0100 @@ -43,7 +43,7 @@ // Run 'jcmd VM.native_memory baseline=false' pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "baseline=false"}); - pb.start(); + pb.start().waitFor(); // Run 'jcmd VM.native_memory summary=false' pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary=false"}); diff -r 3d641132f83b -r 124ca22437b1 test/runtime/NMT/MallocTestType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/MallocTestType.java Fri Apr 12 10:14:42 2013 +0100 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 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 + * 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. + */ + +/* + * @test + * @summary Test consistency of NMT by leaking a few select allocations of the Test type and then verify visibility with jcmd + * @key nmt jcmd + * @library /testlibrary /testlibrary/whitebox + * @build MallocTestType + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail MallocTestType + */ + +import com.oracle.java.testlibrary.*; +import sun.hotspot.WhiteBox; + +public class MallocTestType { + + public static void main(String args[]) throws Exception { + OutputAnalyzer output; + WhiteBox wb = WhiteBox.getWhiteBox(); + + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + + // Use WB API to alloc and free with the mtTest type + long memAlloc3 = wb.NMTMalloc(128 * 1024); + long memAlloc2 = wb.NMTMalloc(256 * 1024); + wb.NMTFree(memAlloc3); + long memAlloc1 = wb.NMTMalloc(512 * 1024); + wb.NMTFree(memAlloc2); + + // Use WB API to ensure that all data has been merged before we continue + if (!wb.NMTWaitForDataMerge()) { + throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); + } + + // Run 'jcmd VM.native_memory summary' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=512KB, committed=512KB)"); + + // Free the memory allocated by NMTAllocTest + wb.NMTFree(memAlloc1); + + // Use WB API to ensure that all data has been merged before we continue + if (!wb.NMTWaitForDataMerge()) { + throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); + } + output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Test (reserved="); + } +} diff -r 3d641132f83b -r 124ca22437b1 test/runtime/NMT/PrintNMTStatistics.java --- a/test/runtime/NMT/PrintNMTStatistics.java Tue Feb 26 16:16:54 2013 -0800 +++ b/test/runtime/NMT/PrintNMTStatistics.java Fri Apr 12 10:14:42 2013 +0100 @@ -27,7 +27,9 @@ * @bug 8005936 * @summary Make sure PrintNMTStatistics works on normal JVM exit * @library /testlibrary /testlibrary/whitebox - * @run compile PrintNMTStatistics.java + * @build PrintNMTStatistics + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main PrintNMTStatistics */ import com.oracle.java.testlibrary.*; @@ -52,13 +54,15 @@ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", + "-Xbootclasspath/a:.", + "-XX:+WhiteBoxAPI", "-XX:NativeMemoryTracking=summary", - "+XX:+PrintNMTStatistics", + "-XX:+PrintNMTStatistics", "PrintNMTStatistics", "test"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("Java Heap (reserved="); + output.shouldContain("Java Heap (reserved="); output.shouldNotContain("error"); output.shouldNotContain("warning"); output.shouldHaveExitValue(0); diff -r 3d641132f83b -r 124ca22437b1 test/runtime/NMT/ThreadedMallocTestType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/ThreadedMallocTestType.java Fri Apr 12 10:14:42 2013 +0100 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 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 + * 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. + */ + +/* + * @test + * @key nmt jcmd + * @library /testlibrary /testlibrary/whitebox + * @build ThreadedMallocTestType + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail ThreadedMallocTestType + */ + +import com.oracle.java.testlibrary.*; +import sun.hotspot.WhiteBox; + +public class ThreadedMallocTestType { + public static long memAlloc1; + public static long memAlloc2; + public static long memAlloc3; + + public static void main(String args[]) throws Exception { + OutputAnalyzer output; + final WhiteBox wb = WhiteBox.getWhiteBox(); + + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + + Thread allocThread = new Thread() { + public void run() { + // Alloc memory using the WB api + memAlloc1 = wb.NMTMalloc(128 * 1024); + memAlloc2 = wb.NMTMalloc(256 * 1024); + memAlloc3 = wb.NMTMalloc(512 * 1024); + } + }; + + allocThread.start(); + allocThread.join(); + + // Use WB API to ensure that all data has been merged before we continue + if (!wb.NMTWaitForDataMerge()) { + throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); + } + + // Run 'jcmd VM.native_memory summary' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=896KB, committed=896KB)"); + + Thread freeThread = new Thread() { + public void run() { + // Free the memory allocated by NMTMalloc + wb.NMTFree(memAlloc1); + wb.NMTFree(memAlloc2); + wb.NMTFree(memAlloc3); + } + }; + + freeThread.start(); + freeThread.join(); + + // Use WB API to ensure that all data has been merged before we continue + if (!wb.NMTWaitForDataMerge()) { + throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); + } + + output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Test (reserved="); + } +} diff -r 3d641132f83b -r 124ca22437b1 test/runtime/NMT/ThreadedVirtualAllocTestType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/ThreadedVirtualAllocTestType.java Fri Apr 12 10:14:42 2013 +0100 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 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 + * 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. + */ + +/* + * @test + * @key nmt jcmd + * @library /testlibrary /testlibrary/whitebox + * @build ThreadedVirtualAllocTestType + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail ThreadedVirtualAllocTestType + */ + +import com.oracle.java.testlibrary.*; +import sun.hotspot.WhiteBox; + +public class ThreadedVirtualAllocTestType { + public static long addr; + public static final WhiteBox wb = WhiteBox.getWhiteBox(); + public static final long commitSize = 128 * 1024; + public static final long reserveSize = 512 * 1024; + + public static void main(String args[]) throws Exception { + OutputAnalyzer output; + + String pid = Integer.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + + Thread reserveThread = new Thread() { + public void run() { + addr = wb.NMTReserveMemory(reserveSize); + } + }; + reserveThread.start(); + reserveThread.join(); + + mergeData(); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=512KB, committed=0KB)"); + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved 512KB for Test"); + + Thread commitThread = new Thread() { + public void run() { + wb.NMTCommitMemory(addr, commitSize); + } + }; + commitThread.start(); + commitThread.join(); + + mergeData(); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=512KB, committed=128KB)"); + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed 128KB"); + + Thread uncommitThread = new Thread() { + public void run() { + wb.NMTUncommitMemory(addr, commitSize); + } + }; + uncommitThread.start(); + uncommitThread.join(); + + mergeData(); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=512KB, committed=0KB)"); + output.shouldNotMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed"); + + Thread releaseThread = new Thread() { + public void run() { + wb.NMTReleaseMemory(addr, reserveSize); + } + }; + releaseThread.start(); + releaseThread.join(); + + mergeData(); + + output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Test (reserved="); + output.shouldNotContain("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved"); + } + + public static void mergeData() throws Exception { + // Use WB API to ensure that all data has been merged before we continue + if (!wb.NMTWaitForDataMerge()) { + throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); + } + } +} diff -r 3d641132f83b -r 124ca22437b1 test/runtime/NMT/VirtualAllocTestType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/VirtualAllocTestType.java Fri Apr 12 10:14:42 2013 +0100 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 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 + * 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. + */ + +/* + * @test + * @summary Test Reserve/Commit/Uncommit/Release of virtual memory and that we track it correctly + * @key nmt jcmd + * @library /testlibrary /testlibrary/whitebox + * @build VirtualAllocTestType + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail VirtualAllocTestType + */ + +import com.oracle.java.testlibrary.*; +import sun.hotspot.WhiteBox; + +public class VirtualAllocTestType { + + public static WhiteBox wb = WhiteBox.getWhiteBox(); + public static void main(String args[]) throws Exception { + OutputAnalyzer output; + long commitSize = 128 * 1024; + long reserveSize = 256 * 1024; + long addr; + + String pid = Integer.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + + addr = wb.NMTReserveMemory(reserveSize); + mergeData(); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=256KB, committed=0KB)"); + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved 256KB for Test"); + + wb.NMTCommitMemory(addr, commitSize); + + mergeData(); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=256KB, committed=128KB)"); + output.shouldMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed 128KB"); + + wb.NMTUncommitMemory(addr, commitSize); + + mergeData(); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=256KB, committed=0KB)"); + output.shouldNotMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + commitSize) + "\\] committed"); + + wb.NMTReleaseMemory(addr, reserveSize); + + mergeData(); + + output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Test (reserved="); + output.shouldNotMatch("\\[0x[0]*" + Long.toHexString(addr) + " - 0x[0]*" + Long.toHexString(addr + reserveSize) + "\\] reserved"); + } + + public static void mergeData() throws Exception { + // Use WB API to ensure that all data has been merged before we continue + if (!wb.NMTWaitForDataMerge()) { + throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); + } + } +} diff -r 3d641132f83b -r 124ca22437b1 test/runtime/interned/SanityTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/interned/SanityTest.java Fri Apr 12 10:14:42 2013 +0100 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 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 + * 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. + */ + +/* + * @test SanityTest + * @summary Sanity check of String.intern() & GC + * @library /testlibrary /testlibrary/whitebox + * @build SanityTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SanityTest + */ + +import java.util.*; +import sun.hotspot.WhiteBox; + + +public class SanityTest { + public static Object tmp; + public static void main(String... args) { + + WhiteBox wb = WhiteBox.getWhiteBox(); + StringBuilder sb = new StringBuilder(); + sb.append("1234x"); sb.append("x56789"); + String str = sb.toString(); + + if (wb.isInStringTable(str)) { + throw new RuntimeException("String " + str + " is already interned"); + } + str.intern(); + if (!wb.isInStringTable(str)) { + throw new RuntimeException("String " + str + " is not interned"); + } + str = sb.toString(); + wb.fullGC(); + if (wb.isInStringTable(str)) { + throw new RuntimeException("String " + str + " is in StringTable even after GC"); + } + } +} diff -r 3d641132f83b -r 124ca22437b1 test/test_env.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/test_env.sh Fri Apr 12 10:14:42 2013 +0100 @@ -0,0 +1,193 @@ +#!/bin/sh +# +# Copyright (c) 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 +# 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. +# + +# +# This Environment script was written to capture typically used environment +# setup for a given shell test. +# + +# TESTJAVA can be a JDK or JRE. If JRE you need to set COMPILEJAVA +if [ "${TESTJAVA}" = "" ] +then + echo "TESTJAVA not set. Test cannot execute. Failed." + exit 1 +fi +echo "TESTJAVA=${TESTJAVA}" + +# COMPILEJAVA requires a JDK, some shell test use javac,jar,etc +if [ "${COMPILEJAVA}" = "" ] +then + echo "COMPILEJAVA not set. Using TESTJAVA as default" + COMPILEJAVA=${TESTJAVA} +fi +echo "COMPILEJAVA=${COMPILEJAVA}" + +if [ "${TESTCLASSES}" = "" ] +then + echo "TESTCLASES not set. Using "." as default" + TESTCLASSES=. +fi +echo "TESTCLASSES=${TESTCLASSES}" + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + SunOS | Linux | Darwin ) + NULL=/dev/null + PS=":" + FS="/" + RM=/bin/rm + CP=/bin/cp + MV=/bin/mv + ;; + Windows_* ) + NULL=NUL + PS=";" + FS="\\" + RM=rm + CP=cp + MV=mv + ;; + CYGWIN_* ) + NULL=/dev/null + PS=";" + FS="/" + RM=rm + CP=cp + MV=mv + ;; + * ) + echo "Unrecognized system!" + exit 1; + ;; +esac + +export NULL PS FS RM CP MV +echo "NULL =${NULL}" +echo "PS =${PS}" +echo "FS =${FS}" +echo "RM =${RM}" +echo "CP =${CP}" +echo "MV =${MV}" + +# jtreg -classpathappend: +JEMMYPATH=${CPAPPEND} +CLASSPATH=.${PS}${TESTCLASSES}${PS}${JEMMYPATH} ; export CLASSPATH +echo "CLASSPATH =${CLASSPATH}" + +# Current directory is scratch directory +THIS_DIR=. +echo "THIS_DIR=${THIS_DIR}" + +# Check to ensure the java defined actually works +${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -version +if [ $? != 0 ]; then + echo "Wrong TESTJAVA or TESTVMOPTS:" + echo $TESTJAVA TESTVMOPTS + exit 1 +fi + +${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Xinternalversion > vm_version.out 2>&1 + +VM_TYPE="unknown" +grep "Server" vm_version.out > ${NULL} +if [ $? = 0 ] +then + VM_TYPE="server" +fi +grep "Client" vm_version.out > ${NULL} +if [ $? = 0 ] +then + VM_TYPE="client" +fi + +VM_BITS="32" +grep "64-Bit" vm_version.out > ${NULL} +if [ $? = 0 ] +then + VM_BITS="64" +fi + +VM_OS="unknown" +grep "solaris" vm_version.out > ${NULL} +if [ $? = 0 ] +then + VM_OS="solaris" +fi +grep "linux" vm_version.out > ${NULL} +if [ $? = 0 ] +then + VM_OS="linux" +fi +grep "windows" vm_version.out > ${NULL} +if [ $? = 0 ] +then + VM_OS="windows" +fi +grep "bsd" vm_version.out > ${NULL} +if [ $? = 0 ] +then + VM_OS="bsd" +fi + +VM_CPU="unknown" +grep "sparc" vm_version.out > ${NULL} +if [ $? = 0 ] +then + VM_CPU="sparc" + if [ $VM_BITS = "64" ] + then + VM_CPU="sparcv9" + fi +fi +grep "x86" vm_version.out > ${NULL} +if [ $? = 0 ] +then + VM_CPU="i386" +fi +grep "amd64" vm_version.out > ${NULL} +if [ $? = 0 ] +then + VM_CPU="amd64" +fi +grep "arm" vm_version.out > ${NULL} +if [ $? = 0 ] +then + VM_CPU="arm" +fi +grep "ppc" vm_version.out > ${NULL} +if [ $? = 0 ] +then + VM_CPU="ppc" +fi +grep "ia64" vm_version.out > ${NULL} +if [ $? = 0 ] +then + VM_CPU="ia64" +fi +export VM_TYPE VM_BITS VM_OS VM_CPU +echo "VM_TYPE=${VM_TYPE}" +echo "VM_BITS=${VM_BITS}" +echo "VM_OS=${VM_OS}" +echo "VM_CPU=${VM_CPU}" diff -r 3d641132f83b -r 124ca22437b1 test/testlibrary/OutputAnalyzerTest.java --- a/test/testlibrary/OutputAnalyzerTest.java Tue Feb 26 16:16:54 2013 -0800 +++ b/test/testlibrary/OutputAnalyzerTest.java Fri Apr 12 10:14:42 2013 +0100 @@ -36,6 +36,11 @@ String stdout = "aaaaaa"; String stderr = "bbbbbb"; + // Regexps used for testing pattern matching of the test input + String stdoutPattern = "[a]"; + String stderrPattern = "[b]"; + String nonExistingPattern = "[c]"; + OutputAnalyzer output = new OutputAnalyzer(stdout, stderr); if (!stdout.equals(output.getStdout())) { @@ -99,10 +104,73 @@ } try { - output.stderrShouldNotContain(stderr); - throw new Exception("shouldContain() failed to throw exception"); + output.stderrShouldNotContain(stderr); + throw new Exception("shouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + // Should match + try { + output.shouldMatch(stdoutPattern); + output.stdoutShouldMatch(stdoutPattern); + output.shouldMatch(stderrPattern); + output.stderrShouldMatch(stderrPattern); + } catch (RuntimeException e) { + throw new Exception("shouldMatch() failed", e); + } + + try { + output.shouldMatch(nonExistingPattern); + throw new Exception("shouldMatch() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stdoutShouldMatch(stderrPattern); + throw new Exception( + "stdoutShouldMatch() failed to throw exception"); } catch (RuntimeException e) { - // expected + // expected + } + + try { + output.stderrShouldMatch(stdoutPattern); + throw new Exception( + "stderrShouldMatch() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + // Should not match + try { + output.shouldNotMatch(nonExistingPattern); + output.stdoutShouldNotMatch(nonExistingPattern); + output.stderrShouldNotMatch(nonExistingPattern); + } catch (RuntimeException e) { + throw new Exception("shouldNotMatch() failed", e); + } + + try { + output.shouldNotMatch(stdoutPattern); + throw new Exception("shouldNotMatch() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stdoutShouldNotMatch(stdoutPattern); + throw new Exception("shouldNotMatch() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stderrShouldNotMatch(stderrPattern); + throw new Exception("shouldNotMatch() failed to throw exception"); + } catch (RuntimeException e) { + // expected } } } diff -r 3d641132f83b -r 124ca22437b1 test/testlibrary/com/oracle/java/testlibrary/JDKToolLauncher.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary/com/oracle/java/testlibrary/JDKToolLauncher.java Fri Apr 12 10:14:42 2013 +0100 @@ -0,0 +1,114 @@ +/* + * Copyright (c) 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 + * 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. + */ + +package com.oracle.java.testlibrary; + +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +import com.oracle.java.testlibrary.JDKToolFinder; +import com.oracle.java.testlibrary.ProcessTools; + +/** + * A utility for constructing command lines for starting JDK tool processes. + * + * The JDKToolLauncher can in particular be combined with a + * java.lang.ProcessBuilder to easily run a JDK tool. For example, the + * following code run {@code jmap -heap} against a process with GC logging + * turned on for the {@code jmap} process: + * + *

+ * {@code
+ * JDKToolLauncher jmap = JDKToolLauncher.create("jmap")
+ *                                       .addVMArg("-XX:+PrintGC");
+ *                                       .addVMArg("-XX:+PrintGCDetails")
+ *                                       .addToolArg("-heap")
+ *                                       .addToolArg(pid);
+ * ProcessBuilder pb = new ProcessBuilder(jmap.getCommand());
+ * Process p = pb.start();
+ * }
+ * 
+ */ +public class JDKToolLauncher { + private final String executable; + private final List vmArgs = new ArrayList(); + private final List toolArgs = new ArrayList(); + + private JDKToolLauncher(String tool) { + executable = JDKToolFinder.getJDKTool(tool); + vmArgs.addAll(Arrays.asList(ProcessTools.getPlatformSpecificVMArgs())); + } + + /** + * Creates a new JDKToolLauncher for the specified tool. + * + * @param tool The name of the tool + * @return A new JDKToolLauncher + */ + public static JDKToolLauncher create(String tool) { + return new JDKToolLauncher(tool); + } + + /** + * Adds an argument to the JVM running the tool. + * + * The JVM arguments are passed to the underlying JVM running the tool. + * Arguments will automatically be prepended with "-J". + * + * Any platform specific arguments required for running the tool are + * automatically added. + * + * + * @param arg The argument to VM running the tool + * @return The JDKToolLauncher instance + */ + public JDKToolLauncher addVMArg(String arg) { + vmArgs.add("-J" + arg); + return this; + } + + /** + * Adds an argument to the tool. + * + * @param arg The argument to the tool + * @return The JDKToolLauncher instance + */ + public JDKToolLauncher addToolArg(String arg) { + toolArgs.add(arg); + return this; + } + + /** + * Returns the command that can be used for running the tool. + * + * @return An array whose elements are the arguments of the command. + */ + public String[] getCommand() { + List command = new ArrayList(); + command.add(executable); + command.addAll(vmArgs); + command.addAll(toolArgs); + return command.toArray(new String[command.size()]); + } +} diff -r 3d641132f83b -r 124ca22437b1 test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java --- a/test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java Tue Feb 26 16:16:54 2013 -0800 +++ b/test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java Fri Apr 12 10:14:42 2013 +0100 @@ -24,6 +24,8 @@ package com.oracle.java.testlibrary; import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public final class OutputAnalyzer { @@ -142,15 +144,112 @@ } /** + * Verify that the stdout and stderr contents of output buffer matches + * the pattern + * + * @param pattern + * @throws RuntimeException If the pattern was not found + */ + public void shouldMatch(String pattern) { + Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (!stdoutMatcher.find() && !stderrMatcher.find()) { + throw new RuntimeException("'" + pattern + + "' missing from stdout/stderr: [" + stdout + stderr + + "]\n"); + } + } + + /** + * Verify that the stdout contents of output buffer matches the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was not found + */ + public void stdoutShouldMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (!matcher.find()) { + throw new RuntimeException("'" + pattern + + "' missing from stdout: [" + stdout + "]\n"); + } + } + + /** + * Verify that the stderr contents of output buffer matches the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was not found + */ + public void stderrShouldMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (!matcher.find()) { + throw new RuntimeException("'" + pattern + + "' missing from stderr: [" + stderr + "]\n"); + } + } + + /** + * Verify that the stdout and stderr contents of output buffer does not + * match the pattern + * + * @param pattern + * @throws RuntimeException If the pattern was found + */ + public void shouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (matcher.find()) { + throw new RuntimeException("'" + pattern + + "' found in stdout: [" + stdout + "]\n"); + } + matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (matcher.find()) { + throw new RuntimeException("'" + pattern + + "' found in stderr: [" + stderr + "]\n"); + } + } + + /** + * Verify that the stdout contents of output buffer does not match the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was found + */ + public void stdoutShouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (matcher.find()) { + throw new RuntimeException("'" + pattern + + "' found in stdout: [" + stdout + "]\n"); + } + } + + /** + * Verify that the stderr contents of output buffer does not match the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was found + */ + public void stderrShouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (matcher.find()) { + throw new RuntimeException("'" + pattern + + "' found in stderr: [" + stderr + "]\n"); + } + } + + /** * Verifiy the exit value of the process * * @param expectedExitValue Expected exit value from process * @throws RuntimeException If the exit value from the process did not match the expected value */ public void shouldHaveExitValue(int expectedExitValue) { - if (getExitValue() != expectedExitValue) { - throw new RuntimeException("Exit value " + getExitValue() + " , expected to get " + expectedExitValue); - } + if (getExitValue() != expectedExitValue) { + throw new RuntimeException("Exit value " + getExitValue() + " , expected to get " + expectedExitValue); + } } /** diff -r 3d641132f83b -r 124ca22437b1 test/testlibrary/whitebox/sun/hotspot/WhiteBox.java --- a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Tue Feb 26 16:16:54 2013 -0800 +++ b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Fri Apr 12 10:14:42 2013 +0100 @@ -80,8 +80,12 @@ public native Object[] parseCommandLine(String commandline, DiagnosticCommand[] args); // NMT - public native boolean NMTAllocTest(); - public native boolean NMTFreeTestMemory(); + public native long NMTMalloc(long size); + public native void NMTFree(long mem); + public native long NMTReserveMemory(long size); + public native void NMTCommitMemory(long addr, long size); + public native void NMTUncommitMemory(long addr, long size); + public native void NMTReleaseMemory(long addr, long size); public native boolean NMTWaitForDataMerge(); // Compiler @@ -94,4 +98,10 @@ public native int getMethodCompilationLevel(Method method); public native boolean setDontInlineMethod(Method method, boolean value); public native int getCompileQueuesSize(); + + //Intered strings + public native boolean isInStringTable(String str); + + // force Full GC + public native void fullGC(); }