# HG changeset patch # User Christian Haeubl # Date 1366008679 -7200 # Node ID 79b098d44d2029cf064875fb23ba0fb7a03f7b8e # Parent 01958088b87db156dc53bf812231413e17f43ea5# Parent 0298d8a0caf5e511cef383675dc2b4edbdcbec41 Merge. diff -r 0298d8a0caf5 -r 79b098d44d20 .hgignore --- a/.hgignore Thu Apr 04 11:57:04 2013 +0200 +++ b/.hgignore Mon Apr 15 08:51:19 2013 +0200 @@ -4,6 +4,7 @@ ^mx/ecj.jar ^mx/includes ^build/ +^build-nograal/ ^dist/ ^java/ ^lib/ @@ -30,6 +31,7 @@ \.dot$ \.pyc$ \.hprof$ +\javafilelist.txt$ \.hprof\.txt$ ^graal/.*/build.xml ^graal/.*/nbproject/ diff -r 0298d8a0caf5 -r 79b098d44d20 .hgtags --- a/.hgtags Thu Apr 04 11:57:04 2013 +0200 +++ b/.hgtags Mon Apr 15 08:51:19 2013 +0200 @@ -320,3 +320,16 @@ 555ec35a250783110aa070dbc8a8603f6cabe41f hs25-b20 6691814929b606fe0e7954fd6e485dd876505c83 jdk8-b79 df5396524152118535c36da5801d828b560d19a2 hs25-b21 +4a198b201f3ce84433fa94a3ca65d061473e7c4c jdk8-b80 +dd6350b4abc4a6c19c89dd982cc0e4f3d119885c hs25-b22 +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 +6d88a566d369f6a1f86912cad7d0912686b2fda1 hs25-b28 diff -r 0298d8a0caf5 -r 79b098d44d20 agent/src/os/bsd/MacosxDebuggerLocal.m --- a/agent/src/os/bsd/MacosxDebuggerLocal.m Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/os/bsd/MacosxDebuggerLocal.m Mon Apr 15 08:51:19 2013 +0200 @@ -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,18 +273,21 @@ 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); unsigned long alignedAddress; - unsigned long alignedLength; + unsigned long alignedLength = 0; kern_return_t result; vm_offset_t *pages; int *mapped; @@ -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); - } - 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 0298d8a0caf5 -r 79b098d44d20 agent/src/os/bsd/Makefile --- a/agent/src/os/bsd/Makefile Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/os/bsd/Makefile Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/os/bsd/libproc.h --- a/agent/src/os/bsd/libproc.h Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/os/bsd/libproc.h Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/os/bsd/libproc_impl.c --- a/agent/src/os/bsd/libproc_impl.c Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/os/bsd/libproc_impl.c Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/os/bsd/libproc_impl.h --- a/agent/src/os/bsd/libproc_impl.h Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/os/bsd/libproc_impl.h Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/os/bsd/ps_core.c --- a/agent/src/os/bsd/ps_core.c Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/os/bsd/ps_core.c Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/os/bsd/symtab.c --- a/agent/src/os/bsd/symtab.c Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/os/bsd/symtab.c Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/os/bsd/symtab.h --- a/agent/src/os/bsd/symtab.h Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/os/bsd/symtab.h Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/os/linux/LinuxDebuggerLocal.c --- a/agent/src/os/linux/LinuxDebuggerLocal.c Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/os/linux/LinuxDebuggerLocal.c Mon Apr 15 08:51:19 2013 +0200 @@ -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 @@ -25,6 +25,13 @@ #include #include "libproc.h" +#include +#include +#include +#include +#include +#include + #if defined(x86_64) && !defined(amd64) #define amd64 1 #endif @@ -154,6 +161,39 @@ } } + +/* + * Verify that a named ELF binary file (core or executable) has the same + * bitness as ourselves. + * Throw an exception if there is a mismatch or other problem. + * + * If we proceed using a mismatched debugger/debuggee, the best to hope + * for is a missing symbol, the worst is a crash searching for debug symbols. + */ +void verifyBitness(JNIEnv *env, const char *binaryName) { + int fd = open(binaryName, O_RDONLY); + if (fd < 0) { + THROW_NEW_DEBUGGER_EXCEPTION("cannot open binary file"); + } + unsigned char elf_ident[EI_NIDENT]; + int i = read(fd, &elf_ident, sizeof(elf_ident)); + close(fd); + + if (i < 0) { + THROW_NEW_DEBUGGER_EXCEPTION("cannot read binary file"); + } +#ifndef _LP64 + if (elf_ident[EI_CLASS] == ELFCLASS64) { + THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 64 bit, use 64-bit java for debugger"); + } +#else + if (elf_ident[EI_CLASS] != ELFCLASS64) { + THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 32 bit, use 32 bit java for debugger"); + } +#endif +} + + /* * Class: sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal * Method: attach0 @@ -162,6 +202,12 @@ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_attach0__I (JNIEnv *env, jobject this_obj, jint jpid) { + // For bitness checking, locate binary at /proc/jpid/exe + char buf[PATH_MAX]; + snprintf((char *) &buf, PATH_MAX, "/proc/%d/exe", jpid); + verifyBitness(env, (char *) &buf); + CHECK_EXCEPTION; + struct ps_prochandle* ph; if ( (ph = Pgrab(jpid)) == NULL) { THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process"); @@ -187,6 +233,9 @@ coreName_cstr = (*env)->GetStringUTFChars(env, coreName, &isCopy); CHECK_EXCEPTION; + verifyBitness(env, execName_cstr); + CHECK_EXCEPTION; + if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) { (*env)->ReleaseStringUTFChars(env, execName, execName_cstr); (*env)->ReleaseStringUTFChars(env, coreName, coreName_cstr); diff -r 0298d8a0caf5 -r 79b098d44d20 agent/src/os/linux/ps_core.c --- a/agent/src/os/linux/ps_core.c Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/os/linux/ps_core.c Mon Apr 15 08:51:19 2013 +0200 @@ -132,12 +132,12 @@ } // Part of the class sharing workaround -static map_info* add_class_share_map_info(struct ps_prochandle* ph, off_t offset, +static void 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; + return; } map->next = ph->core->class_share_maps; diff -r 0298d8a0caf5 -r 79b098d44d20 agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java --- a/agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/BsdVtblAccess.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java --- a/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java --- a/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/amd64/LinuxAMD64CFrame.java Mon Apr 15 08:51:19 2013 +0200 @@ -60,8 +60,13 @@ return null; } + // Check alignment of rbp + if ( dbg.getAddressValue(rbp) % ADDRESS_SIZE != 0) { + return null; + } + Address nextRBP = rbp.getAddressAt( 0 * ADDRESS_SIZE); - if (nextRBP == null) { + if (nextRBP == null || nextRBP.lessThanOrEqual(rbp)) { return null; } Address nextPC = rbp.getAddressAt( 1 * ADDRESS_SIZE); diff -r 0298d8a0caf5 -r 79b098d44d20 agent/src/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86CFrame.java --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86CFrame.java Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/x86/LinuxX86CFrame.java Mon Apr 15 08:51:19 2013 +0200 @@ -61,8 +61,13 @@ return null; } + // Check alignment of ebp + if ( dbg.getAddressValue(ebp) % ADDRESS_SIZE != 0) { + return null; + } + Address nextEBP = ebp.getAddressAt( 0 * ADDRESS_SIZE); - if (nextEBP == null) { + if (nextEBP == null || nextEBP.lessThanOrEqual(ebp)) { return null; } Address nextPC = ebp.getAddressAt( 1 * ADDRESS_SIZE); diff -r 0298d8a0caf5 -r 79b098d44d20 agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java --- a/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Oop.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java --- a/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java --- a/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 agent/src/share/native/sadis.c --- a/agent/src/share/native/sadis.c Thu Apr 04 11:57:04 2013 +0200 +++ b/agent/src/share/native/sadis.c Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java Mon Apr 15 08:51:19 2013 +0200 @@ -25,6 +25,7 @@ import static com.oracle.graal.api.meta.MetaUtil.*; import java.io.*; +import java.lang.invoke.*; import java.util.*; import com.oracle.graal.api.meta.*; @@ -44,6 +45,40 @@ private static final long serialVersionUID = -1936652569665112915L; } + public static final class NoFinalizableSubclass extends Assumption { + + private static final long serialVersionUID = 6451169735564055081L; + + private ResolvedJavaType receiverType; + + public NoFinalizableSubclass(ResolvedJavaType receiverType) { + this.receiverType = receiverType; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + receiverType.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof NoFinalizableSubclass) { + NoFinalizableSubclass other = (NoFinalizableSubclass) obj; + return other.receiverType == receiverType; + } + return false; + } + + @Override + public String toString() { + return "NoFinalizableSubclass[receiverType=" + toJavaName(receiverType) + "]"; + } + + } + /** * An assumption about a unique subtype of a given type. */ @@ -182,6 +217,45 @@ } /** + * Assumption that a call site's method handle did not change. + */ + public static final class CallSiteTargetValue extends Assumption { + + private static final long serialVersionUID = 1732459941784550371L; + + public final CallSite callSite; + public final MethodHandle methodHandle; + + public CallSiteTargetValue(CallSite callSite, MethodHandle methodHandle) { + this.callSite = callSite; + this.methodHandle = methodHandle; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + callSite.hashCode(); + result = prime * result + methodHandle.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof CallSiteTargetValue) { + CallSiteTargetValue other = (CallSiteTargetValue) obj; + return other.callSite == callSite && other.methodHandle == methodHandle; + } + return false; + } + + @Override + public String toString() { + return "CallSiteTargetValue[callSite=" + callSite + ", methodHandle=" + methodHandle + "]"; + } + } + + /** * Array with the assumptions. This field is directly accessed from C++ code in the * Graal/HotSpot implementation. */ @@ -233,12 +307,10 @@ * Records an assumption that the specified type has no finalizable subclasses. * * @param receiverType the type that is assumed to have no finalizable subclasses - * @return {@code true} if the assumption was recorded and can be assumed; {@code false} - * otherwise */ - public boolean recordNoFinalizableSubclassAssumption(ResolvedJavaType receiverType) { + public void recordNoFinalizableSubclassAssumption(ResolvedJavaType receiverType) { assert useOptimisticAssumptions; - return false; + record(new NoFinalizableSubclass(receiverType)); } /** diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java Mon Apr 15 08:51:19 2013 +0200 @@ -60,13 +60,6 @@ RegisterConfig lookupRegisterConfig(); /** - * Custom area on the stack of each compiled method that the VM can use for its own purposes. - * - * @return the size of the custom area in bytes - */ - int getCustomStackAreaSize(); - - /** * Minimum size of the stack area reserved for outgoing parameters. This area is reserved in all * cases, even when the compiled method has no regular call instructions. * diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -52,42 +52,45 @@ } /** - * Represents a safepoint with associated debug info. + * Represents an infopoint with associated debug info. Note that safepoints are also infopoints. */ - public static class Safepoint extends Site implements Comparable { + public static class Infopoint extends Site implements Comparable { private static final long serialVersionUID = 2479806696381720162L; public final DebugInfo debugInfo; - public Safepoint(int pcOffset, DebugInfo debugInfo) { + public final InfopointReason reason; + + public Infopoint(int pcOffset, DebugInfo debugInfo, InfopointReason reason) { super(pcOffset); this.debugInfo = debugInfo; + this.reason = reason; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(pcOffset); - sb.append("[]"); + sb.append("[]"); appendDebugInfo(sb, debugInfo); return sb.toString(); } @Override - public int compareTo(Safepoint o) { + public int compareTo(Infopoint o) { if (pcOffset < o.pcOffset) { return -1; } else if (pcOffset > o.pcOffset) { return 1; } - return 0; + return this.reason.compareTo(o.reason); } } /** * Represents a call in the code. */ - public static final class Call extends Safepoint { + public static final class Call extends Infopoint { private static final long serialVersionUID = 1440741241631046954L; @@ -109,7 +112,7 @@ public final boolean direct; public Call(InvokeTarget target, int pcOffset, int size, boolean direct, DebugInfo debugInfo) { - super(pcOffset, debugInfo); + super(pcOffset, debugInfo, InfopointReason.CALL); this.size = size; this.target = target; this.direct = direct; @@ -284,7 +287,7 @@ } } - private final List safepoints = new ArrayList<>(); + private final List infopoints = new ArrayList<>(); private final List dataReferences = new ArrayList<>(); private final List exceptionHandlers = new ArrayList<>(); private final List marks = new ArrayList<>(); @@ -377,7 +380,7 @@ */ public void recordCall(int codePos, int size, InvokeTarget target, DebugInfo debugInfo, boolean direct) { final Call call = new Call(target, codePos, size, direct, debugInfo); - addSafepoint(call); + addInfopoint(call); } /** @@ -391,22 +394,22 @@ } /** - * Records a safepoint in the code array. + * Records an infopoint in the code array. * - * @param codePos the position of the safepoint in the code array - * @param debugInfo the debug info for the safepoint + * @param codePos the position of the infopoint in the code array + * @param debugInfo the debug info for the infopoint */ - public void recordSafepoint(int codePos, DebugInfo debugInfo) { - addSafepoint(new Safepoint(codePos, debugInfo)); + public void recordInfopoint(int codePos, DebugInfo debugInfo, InfopointReason reason) { + addInfopoint(new Infopoint(codePos, debugInfo, reason)); } - private void addSafepoint(Safepoint safepoint) { - // The safepoints list must always be sorted - if (!getSafepoints().isEmpty() && getSafepoints().get(getSafepoints().size() - 1).pcOffset >= safepoint.pcOffset) { + private void addInfopoint(Infopoint infopoint) { + // The infopoints list must always be sorted + if (!getInfopoints().isEmpty() && getInfopoints().get(getInfopoints().size() - 1).pcOffset >= infopoint.pcOffset) { // This re-sorting should be very rare - Collections.sort(getSafepoints()); + Collections.sort(getInfopoints()); } - getSafepoints().add(safepoint); + getInfopoints().add(infopoint); } /** @@ -522,10 +525,10 @@ } /** - * @return the list of safepoints, sorted by {@link Site#pcOffset} + * @return the list of infopoints, sorted by {@link Site#pcOffset} */ - public List getSafepoints() { - return safepoints; + public List getInfopoints() { + return infopoints; } /** diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InfopointReason.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InfopointReason.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,32 @@ +/* + * 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.graal.api.code; + +/** + * A reason for infopoint insertion. + */ +public enum InfopointReason { + + UNKNOWN, SAFEPOINT, CALL, IMPLICIT_EXCEPTION, METHOD_START, METHOD_END, LINE_NUMBER; + +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InstalledCode.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InstalledCode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InstalledCode.java Mon Apr 15 08:51:19 2013 +0200 @@ -31,14 +31,6 @@ public interface InstalledCode { /** - * Exception thrown by the runtime in case an invalidated machine code is called. - */ - public abstract class MethodInvalidatedException extends RuntimeException { - - private static final long serialVersionUID = -3540232440794244844L; - } - - /** * Returns the method (if any) to which the installed code belongs. */ ResolvedJavaMethod getMethod(); @@ -61,6 +53,12 @@ boolean isValid(); /** + * Invalidates this installed code such that any subsequent invocation will throw an + * {@link InvalidInstalledCodeException}. + */ + void invalidate(); + + /** * Executes the installed code with three object arguments. * * @param arg1 the first argument @@ -68,7 +66,7 @@ * @param arg3 the third argument * @return the value returned by the executed code */ - Object execute(Object arg1, Object arg2, Object arg3); + Object execute(Object arg1, Object arg2, Object arg3) throws InvalidInstalledCodeException; /** * Executes the installed code with a variable number of arguments. @@ -76,5 +74,5 @@ * @param args the array of object arguments * @return the value returned by the executed code */ - Object executeVarargs(Object... args); + Object executeVarargs(Object... args) throws InvalidInstalledCodeException; } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InvalidInstalledCodeException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InvalidInstalledCodeException.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,31 @@ +/* + * 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.graal.api.code; + +/** + * Exception thrown by the runtime in case an invalidated machine code is called. + */ +public final class InvalidInstalledCodeException extends Exception { + + private static final long serialVersionUID = -3540232440794244844L; +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCallTarget.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCallTarget.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCallTarget.java Mon Apr 15 08:51:19 2013 +0200 @@ -114,4 +114,6 @@ long getMaxCallTargetOffset(); Descriptor getDescriptor(); + + boolean preservesRegisters(); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java Mon Apr 15 08:51:19 2013 +0200 @@ -36,10 +36,31 @@ */ public class TypeCheckHints { - private static final ResolvedJavaType[] NO_TYPES = {}; + /** + * A receiver type profiled in a type check instruction. + */ + public static class Hint { + + /** + * A type seen while profiling a type check instruction. + */ + public final ResolvedJavaType type; + + /** + * Specifies if {@link #type} was a sub-type of the checked type. + */ + public final boolean positive; + + Hint(ResolvedJavaType type, boolean positive) { + this.type = type; + this.positive = positive; + } + } + + private static final Hint[] NO_HINTS = {}; /** - * If true, then {@link #types} contains the only possible type that could pass the type check + * If true, then {@link #hints} contains the only possible type that could pass the type check * because the target of the type check is a final class or has been speculated to be a final * class. */ @@ -48,63 +69,63 @@ /** * The most likely types that the type check instruction will see. */ - public final ResolvedJavaType[] types; + public final Hint[] hints; /** * Derives hint information for use when generating the code for a type check instruction. * - * @param type the target type of the type check + * @param targetType the target type of the type check * @param profile the profiling information available for the instruction (if any) * @param assumptions the object in which speculations are recorded. This is null if * speculations are not supported. - * @param minHintHitProbability if the probability that the type check will hit one the profiled - * types (up to {@code maxHints}) is below this value, then {@link #types} will be - * null - * @param maxHints the maximum length of {@link #types} + * @param minHintHitProbability if the probability that the type check will hit one of the + * profiled types (up to {@code maxHints}) is below this value, then {@link #hints} + * will be null + * @param maxHints the maximum length of {@link #hints} */ - public TypeCheckHints(ResolvedJavaType type, JavaTypeProfile profile, Assumptions assumptions, double minHintHitProbability, int maxHints) { - if (type != null && canHaveSubtype(type)) { - types = new ResolvedJavaType[]{type}; + public TypeCheckHints(ResolvedJavaType targetType, JavaTypeProfile profile, Assumptions assumptions, double minHintHitProbability, int maxHints) { + if (targetType != null && !canHaveSubtype(targetType)) { + hints = new Hint[]{new Hint(targetType, true)}; exact = true; } else { - ResolvedJavaType uniqueSubtype = type == null ? null : type.findUniqueConcreteSubtype(); + ResolvedJavaType uniqueSubtype = targetType == null ? null : targetType.findUniqueConcreteSubtype(); if (uniqueSubtype != null) { - types = new ResolvedJavaType[]{uniqueSubtype}; + hints = new Hint[]{new Hint(uniqueSubtype, true)}; if (assumptions.useOptimisticAssumptions()) { - assumptions.recordConcreteSubtype(type, uniqueSubtype); + assumptions.recordConcreteSubtype(targetType, uniqueSubtype); exact = true; } else { exact = false; } } else { exact = false; - ResolvedJavaType[] hintTypes = NO_TYPES; + Hint[] hintsBuf = NO_HINTS; JavaTypeProfile typeProfile = profile; if (typeProfile != null) { double notRecordedTypes = typeProfile.getNotRecordedProbability(); ProfiledType[] ptypes = typeProfile.getTypes(); if (notRecordedTypes < (1D - minHintHitProbability) && ptypes != null && ptypes.length > 0) { - hintTypes = new ResolvedJavaType[ptypes.length]; + hintsBuf = new Hint[ptypes.length]; int hintCount = 0; double totalHintProbability = 0.0d; for (ProfiledType ptype : ptypes) { - ResolvedJavaType hint = ptype.getType(); - if (type != null && type.isAssignableFrom(hint)) { - hintTypes[hintCount++] = hint; + if (targetType != null) { + ResolvedJavaType hintType = ptype.getType(); + hintsBuf[hintCount++] = new Hint(hintType, targetType.isAssignableFrom(hintType)); totalHintProbability += ptype.getProbability(); } } if (totalHintProbability >= minHintHitProbability) { - if (hintTypes.length != hintCount || hintCount > maxHints) { - hintTypes = Arrays.copyOf(hintTypes, Math.min(maxHints, hintCount)); + if (hintsBuf.length != hintCount || hintCount > maxHints) { + hintsBuf = Arrays.copyOf(hintsBuf, Math.min(maxHints, hintCount)); } } else { - hintTypes = NO_TYPES; + hintsBuf = NO_HINTS; } } } - this.types = hintTypes; + this.hints = hintsBuf; } } } @@ -113,9 +134,9 @@ * Determines if a given type can have subtypes other than itself. This analysis is purely * static; no assumptions are made. * - * @return true if {@code type} has no subtype(s) + * @return true if {@code type} can have subtypes */ public static boolean canHaveSubtype(ResolvedJavaType type) { - return isFinal(getElementalType(type).getModifiers()); + return !isFinal(getElementalType(type).getModifiers()); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java Mon Apr 15 08:51:19 2013 +0200 @@ -89,13 +89,19 @@ } public static Register asIntReg(Value value) { - assert value.getKind() == Kind.Int; - return asRegister(value); + if (value.getKind() != Kind.Int) { + throw new InternalError("needed Int got: " + value.getKind()); + } else { + return asRegister(value); + } } public static Register asLongReg(Value value) { - assert value.getKind() == Kind.Long : value.getKind(); - return asRegister(value); + if (value.getKind() != Kind.Long) { + throw new InternalError("needed Long got: " + value.getKind()); + } else { + return asRegister(value); + } } public static Register asObjectReg(Value value) { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java --- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java Mon Apr 15 08:51:19 2013 +0200 @@ -402,7 +402,7 @@ if (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers())) { Method overridden = vtable.methods.put(new NameAndSignature(m), m); if (overridden != null) { - // System.out.println(m + " overrides " + overridden); + // println(m + " overrides " + overridden); } } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantPool.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantPool.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantPool.java Mon Apr 15 08:51:19 2013 +0200 @@ -30,6 +30,13 @@ public interface ConstantPool { /** + * Returns the number of entries the constant pool. + * + * @return number of entries in the constant pool + */ + int length(); + + /** * Ensures that the type referenced by the specified constant pool entry is loaded and * initialized. This can be used to compile time resolve a type. It works for field, method, or * type constant pool entries. @@ -93,4 +100,14 @@ * entry */ Object lookupConstant(int cpi); + + /** + * Looks up the appendix at the specified index. + * + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed or + * {@code -1} + * @return the appendix if it exists and is resolved or {@code null} + */ + Object lookupAppendix(int cpi, int opcode); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/JavaTypeProfile.java Mon Apr 15 08:51:19 2013 +0200 @@ -24,6 +24,8 @@ import java.io.*; +import com.oracle.graal.api.meta.ProfilingInfo.*; + /** * This profile object represents the type profile at a specific BCI. The precision of the supplied * values may vary, but a runtime that provides this information should be aware that it will be @@ -78,6 +80,7 @@ } } + private final TriState nullSeen; private final double notRecordedProbability; private final ProfiledType[] ptypes; @@ -94,7 +97,8 @@ return true; } - public JavaTypeProfile(double notRecordedProbability, ProfiledType... ptypes) { + public JavaTypeProfile(TriState nullSeen, double notRecordedProbability, ProfiledType... ptypes) { + this.nullSeen = nullSeen; this.ptypes = ptypes; this.notRecordedProbability = notRecordedProbability; assert isSorted(ptypes); @@ -111,7 +115,16 @@ } /** - * A list of types for which the runtime has recorded probability information. + * Returns whether a null value was at the type check. + */ + public TriState getNullSeen() { + return nullSeen; + } + + /** + * A list of types for which the runtime has recorded probability information. Note that this + * includes both positive and negative types where a positive type is a subtype of the checked + * type and a negative type is not. */ public ProfiledType[] getTypes() { return ptypes; diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java Mon Apr 15 08:51:19 2013 +0200 @@ -47,6 +47,17 @@ } /** + * Calls {@link JavaType#resolve(ResolvedJavaType)} on an array of types. + */ + public static ResolvedJavaType[] resolveJavaTypes(JavaType[] types, ResolvedJavaType accessingClass) { + ResolvedJavaType[] result = new ResolvedJavaType[types.length]; + for (int i = 0; i < result.length; i++) { + result[i] = types[i].resolve(accessingClass); + } + return result; + } + + /** * Calls {@link MetaAccessProvider#lookupJavaType(Class)} on an array of classes. */ public static ResolvedJavaType[] lookupJavaTypes(MetaAccessProvider metaAccess, Class[] classes) { @@ -58,54 +69,6 @@ } /** - * Gets the {@link Class} mirror for a given resolved type. - * - * @param type the type for which the Java mirror is requested - * @param loader class loader from which the class must be loaded (null means use the class - * loader of the {@link MetaUtil} class) - * @return the mirror for {@code type} - * @throws NoClassDefFoundError if the mirror is not available - */ - public static Class getMirrorOrFail(ResolvedJavaType type, ClassLoader loader) throws NoClassDefFoundError { - ResolvedJavaType elementalType = getElementalType(type); - Class elementalClass; - if (elementalType.isPrimitive()) { - elementalClass = elementalType.getKind().toJavaClass(); - } else { - try { - elementalClass = Class.forName(toJavaName(elementalType), true, loader); - } catch (ClassNotFoundException e) { - throw (NoClassDefFoundError) new NoClassDefFoundError().initCause(e); - } - } - if (type.isArray()) { - ResolvedJavaType t = type; - while (t.getComponentType() != null) { - elementalClass = Array.newInstance(elementalClass, 0).getClass(); - t = t.getComponentType(); - } - } - assert elementalClass != null : toJavaName(type); - return elementalClass; - } - - /** - * Gets the {@link Class} mirror for a given resolved type. - * - * @param type the type for which the Java mirror is requested - * @param loader class loader from which the class must be loaded (null means use the class - * loader of the {@link MetaUtil} class) - * @return the mirror for {@code type} or null if it is not available - */ - public static Class getMirror(ResolvedJavaType type, ClassLoader loader) { - try { - return getMirrorOrFail(type, loader); - } catch (NoClassDefFoundError e) { - return null; - } - } - - /** * Gets the elemental type for a given type. The elemental type of an array type is the * corresponding zero dimensional (e.g., the elemental type of {@code int[][][]} is {@code int} * ). A non-array type is its own elemental type. diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java Mon Apr 15 08:51:19 2013 +0200 @@ -180,4 +180,26 @@ * Returns the localvariable table of this method. */ LocalVariableTable getLocalVariableTable(); + + /** + * Invokes the underlying method represented by this object, on the specified object with the + * specified parameters. This method is similar to a reflective method invocation by + * {@link Method#invoke}. + * + * @param receiver The receiver for the invocation, or {@code null} if it is a static method. + * @param arguments The arguments for the invocation. + * @return The value returned by the method invocation, or {@code null} if the return type is + * {@code void}. + */ + Constant invoke(Constant receiver, Constant[] arguments); + + /** + * Uses the constructor represented by this object to create and initialize a new instance of + * the constructor's declaring class, with the specified initialization parameters. This method + * is similar to a reflective instantiation by {@link Constructor#newInstance}. + * + * @param arguments The arguments for the constructor. + * @return The newly created and initialized object. + */ + Constant newInstance(Constant[] arguments); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java Mon Apr 15 08:51:19 2013 +0200 @@ -274,4 +274,22 @@ * Returns the enclosing type of this type, if it exists, or {@code null}. */ ResolvedJavaType getEnclosingType(); + + /** + * Returns an array reflecting all the constructors declared by this type. This method is + * similar to {@link Class#getDeclaredConstructors()} in terms of returned constructors. + */ + ResolvedJavaMethod[] getDeclaredConstructors(); + + /** + * Returns an array reflecting all the methods declared by this type. This method is similar to + * {@link Class#getDeclaredMethods()} in terms of returned methods. + */ + ResolvedJavaMethod[] getDeclaredMethods(); + + /** + * Creates a new array with this type as the component type and the specified length. This + * method is similar to {@link Array#newInstance(Class, int)}. + */ + Constant newArray(int length); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodSubstitution.java --- a/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodSubstitution.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodSubstitution.java Mon Apr 15 08:51:19 2013 +0200 @@ -54,4 +54,20 @@ * is the same as the substitute method. */ String signature() default ""; + + /** + * Determines if this method should be substituted in all cases, even if inlining thinks it is + * not important. + * + * Not that this is still depending on whether inlining sees the correct call target, so it's + * only a hard guarantee for static and special invocations. + */ + boolean forced() default false; + + /** + * Determines if the substitution is for a method that may not be part of the runtime. For + * example, a method introduced in a later JDK version. Substitutions for such methods are + * omitted if the original method cannot be found. + */ + boolean optional() default false; } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/ServiceProvider.java --- a/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/ServiceProvider.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.api.runtime/src/com/oracle/graal/api/runtime/ServiceProvider.java Mon Apr 15 08:51:19 2013 +0200 @@ -24,7 +24,7 @@ import java.lang.annotation.*; -@Retention(RetentionPolicy.SOURCE) +@Retention(RetentionPolicy.CLASS) @Target(ElementType.TYPE) public @interface ServiceProvider { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java --- a/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java Mon Apr 15 08:51:19 2013 +0200 @@ -26,8 +26,7 @@ public class PTXAssembler extends AbstractPTXAssembler { - @SuppressWarnings("unused") - public PTXAssembler(TargetDescription target, RegisterConfig registerConfig) { + public PTXAssembler(TargetDescription target, @SuppressWarnings("unused") RegisterConfig registerConfig) { super(target); } @@ -35,6 +34,18 @@ emitString("@%p" + " " + ""); } + public final void atq() { + emitString("@%q" + " " + ""); + } + + public final void add_f32(Register d, Register a, Register b) { + emitString("add.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void add_f64(Register d, Register a, Register b) { + emitString("add.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + public final void add_s16(Register d, Register a, Register b) { emitString("add.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); } @@ -59,6 +70,14 @@ emitString("add.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s64 + ";" + ""); } + public final void add_f32(Register d, Register a, float f32) { + emitString("add.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + f32 + ";" + ""); + } + + public final void add_f64(Register d, Register a, double f64) { + emitString("add.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + f64 + ";" + ""); + } + public final void add_u16(Register d, Register a, Register b) { emitString("add.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); } @@ -123,7 +142,63 @@ emitString("bra.uni" + " " + tgt + ";" + ""); } - public final void div_s16(Register d, Register a, Register b) { + public final void cvt_s32_f32(Register d, Register a) { + emitString("cvt.s32.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void cvt_s64_f32(Register d, Register a) { + emitString("cvt.s64.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void cvt_f64_f32(Register d, Register a) { + emitString("cvt.f64.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void cvt_f32_f64(Register d, Register a) { + emitString("cvt.f32.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void cvt_s32_f64(Register d, Register a) { + emitString("cvt.s32.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void cvt_s64_f64(Register d, Register a) { + emitString("cvt.s64.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void cvt_f32_s32(Register d, Register a) { + emitString("cvt.f32.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void cvt_f64_s32(Register d, Register a) { + emitString("cvt.f64.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void cvt_s8_s32(Register d, Register a) { + emitString("cvt.s8.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void cvt_b16_s32(Register d, Register a) { + emitString("cvt.b16.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void cvt_s64_s32(Register d, Register a) { + emitString("cvt.s64.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void cvt_s32_s64(Register d, Register a) { + emitString("cvt.s32.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void div_f32(Register d, Register a, Register b) { + emitString("div.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void div_f64(Register d, Register a, Register b) { + emitString("div.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void div_s16(Register d, Register a, Register b) { emitString("div.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); } @@ -143,10 +218,30 @@ emitString("div.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s32 + ";" + ""); } + public final void div_s32(Register d, int s32, Register b) { + emitString("div.s32" + " " + "%r" + d.encoding() + ", " + s32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void div_f32(Register d, float f32, Register b) { + emitString("div.f32" + " " + "%r" + d.encoding() + ", " + f32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void div_f64(Register d, double f64, Register b) { + emitString("div.f64" + " " + "%r" + d.encoding() + ", " + f64 + ", %r" + b.encoding() + ";" + ""); + } + public final void div_s64(Register d, Register a, long s64) { emitString("div.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s64 + ";" + ""); } + public final void div_f32(Register d, Register a, float f32) { + emitString("div.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + f32 + ";" + ""); + } + + public final void div_f64(Register d, Register a, double f64) { + emitString("div.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + f64 + ";" + ""); + } + public final void div_u16(Register d, Register a, Register b) { emitString("div.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); } @@ -255,6 +350,11 @@ emitString("mov.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); } + public final void mov_u64(@SuppressWarnings("unused") Register d, + @SuppressWarnings("unused") AbstractAddress a) { + // emitString("mov.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + public final void mov_s16(Register d, Register a) { emitString("mov.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); } @@ -319,6 +419,14 @@ emitString("mov.f64" + " " + "%r" + d.encoding() + ", " + f64 + ";" + ""); } + public final void mul_f32(Register d, Register a, Register b) { + emitString("mul.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void mul_f64(Register d, Register a, Register b) { + emitString("smul.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + public final void mul_s16(Register d, Register a, Register b) { emitString("mul.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); } @@ -343,6 +451,14 @@ emitString("mul.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s64 + ";" + ""); } + public final void mul_f32(Register d, Register a, float f32) { + emitString("mul.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + f32 + ";" + ""); + } + + public final void mul_f64(Register d, Register a, double f64) { + emitString("mul.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + f64 + ";" + ""); + } + public final void mul_u16(Register d, Register a, Register b) { emitString("mul.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); } @@ -367,6 +483,14 @@ emitString("mul.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u64 + ";" + ""); } + public final void neg_f32(Register d, Register a) { + emitString("neg.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void neg_f64(Register d, Register a) { + emitString("neg.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + public final void neg_s16(Register d, Register a) { emitString("neg.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); } @@ -379,6 +503,42 @@ emitString("neg.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); } + public final void not_s16(Register d, Register a) { + emitString("not.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void not_s32(Register d, Register a) { + emitString("not.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void not_s64(Register d, Register a) { + emitString("not.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void or_b16(Register d, Register a, Register b) { + emitString("or.b16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void or_b32(Register d, Register a, Register b) { + emitString("or.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void or_b64(Register d, Register a, Register b) { + emitString("or.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void or_b16(Register d, Register a, short b16) { + emitString("or.b16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b16 + ";" + ""); + } + + public final void or_b32(Register d, Register a, int b32) { + emitString("or.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b32 + ";" + ""); + } + + public final void or_b64(Register d, Register a, long b64) { + emitString("or.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b64 + ";" + ""); + } + public final void popc_b32(Register d, Register a) { emitString("popc.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); } @@ -443,6 +603,86 @@ emitString("ret.uni;" + " " + ""); } + public final void setp_eq_f32(Register a, Register b) { + emitString("setp.eq.f32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_ne_f32(Register a, Register b) { + emitString("setp.ne.f32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_lt_f32(Register a, Register b) { + emitString("setp.lt.f32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_le_f32(Register a, Register b) { + emitString("setp.le.f32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_gt_f32(Register a, Register b) { + emitString("setp.gt.f32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_ge_f32(Register a, Register b) { + emitString("setp.ge.f32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_eq_f32(float f32, Register b) { + emitString("setp.eq.f32" + " " + "%p" + ", " + f32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_ne_f32(float f32, Register b) { + emitString("setp.ne.f32" + " " + "%p" + ", " + f32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_lt_f32(float f32, Register b) { + emitString("setp.lt.f32" + " " + "%p" + ", " + f32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_le_f32(float f32, Register b) { + emitString("setp.le.f32" + " " + "%p" + ", " + f32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_gt_f32(float f32, Register b) { + emitString("setp.gt.f32" + " " + "%p" + ", " + f32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_ge_f32(float f32, Register b) { + emitString("setp.ge.f32" + " " + "%p" + ", " + f32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_eq_f64(double f64, Register b) { + emitString("setp.eq.f64" + " " + "%p" + ", " + f64 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_ne_f64(double f64, Register b) { + emitString("setp.ne.f64" + " " + "%p" + ", " + f64 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_lt_f64(double f64, Register b) { + emitString("setp.lt.f64" + " " + "%p" + ", " + f64 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_le_f64(double f64, Register b) { + emitString("setp.le.f64" + " " + "%p" + ", " + f64 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_gt_f64(double f64, Register b) { + emitString("setp.gt.f64" + " " + "%p" + ", " + f64 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_ge_f64(double f64, Register b) { + emitString("setp.ge.f64" + " " + "%p" + ", " + f64 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_eq_s64(Register a, Register b) { + emitString("setp.eq.s64" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_eq_s64(long s64, Register b) { + emitString("setp.eq.s64" + " " + "%p" + ", " + s64 + ", %r" + b.encoding() + ";" + ""); + } + public final void setp_eq_s32(Register a, Register b) { emitString("setp.eq.s32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); } @@ -587,6 +827,54 @@ emitString("setp.ge.u32" + " " + "%p" + ", " + u32 + ", %r" + b.encoding() + ";" + ""); } + public final void shl_s16(Register d, Register a, Register b) { + emitString("shl.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void shl_s32(Register d, Register a, Register b) { + emitString("shl.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void shl_s64(Register d, Register a, Register b) { + emitString("shl.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void shl_s16(Register d, Register a, int u32) { + emitString("shl.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void shl_s32(Register d, Register a, int u32) { + emitString("shl.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void shl_s64(Register d, Register a, int u32) { + emitString("shl.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void shl_u16(Register d, Register a, Register b) { + emitString("shl.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void shl_u32(Register d, Register a, Register b) { + emitString("shl.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void shl_u64(Register d, Register a, Register b) { + emitString("shl.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void shl_u16(Register d, Register a, int u32) { + emitString("shl.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void shl_u32(Register d, Register a, int u32) { + emitString("shl.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void shl_u64(Register d, Register a, int u32) { + emitString("shl.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + public final void shr_s16(Register d, Register a, Register b) { emitString("shr.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); } @@ -631,8 +919,8 @@ emitString("shr.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + ""); } - public final void shr_u64(Register d, Register a, int u32) { - emitString("shr.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + public final void shr_u64(Register d, Register a, long u64) { + emitString("shr.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u64 + ";" + ""); } public final void st_global_b8(Register a, long immOff, Register b) { @@ -691,6 +979,14 @@ emitString("st.global.f64" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + ""); } + public final void sub_f32(Register d, Register a, Register b) { + emitString("sub.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void sub_f64(Register d, Register a, Register b) { + emitString("sub.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + public final void sub_s16(Register d, Register a, Register b) { emitString("sub.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); } @@ -711,10 +1007,22 @@ emitString("sub.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s32 + ";" + ""); } + public final void sub_s64(Register d, Register a, int s32) { + emitString("sub.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s32 + ";" + ""); + } + public final void sub_s64(Register d, Register a, long s64) { emitString("sub.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s64 + ";" + ""); } + public final void sub_f32(Register d, Register a, float f32) { + emitString("sub.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + f32 + ";" + ""); + } + + public final void sub_f64(Register d, Register a, double f64) { + emitString("sub.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + f64 + ";" + ""); + } + public final void sub_s16(Register d, short s16, Register b) { emitString("sub.s16" + " " + "%r" + d.encoding() + ", " + s16 + ", %r" + b.encoding() + ";" + ""); } @@ -727,6 +1035,14 @@ emitString("sub.s64" + " " + "%r" + d.encoding() + ", " + s64 + ", %r" + b.encoding() + ";" + ""); } + public final void sub_f32(Register d, float f32, Register b) { + emitString("sub.f32" + " " + "%r" + d.encoding() + ", %r" + b.encoding() + ", " + f32 + ";" + ""); + } + + public final void sub_f64(Register d, double f64, Register b) { + emitString("sub.f64" + " " + "%r" + d.encoding() + ", %r" + b.encoding() + ", " + f64 + ";" + ""); + } + public final void sub_sat_s32(Register d, Register a, Register b) { emitString("sub.sat.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); } @@ -739,6 +1055,30 @@ emitString("sub.sat.s32" + " " + "%r" + d.encoding() + ", " + s32 + ", %r" + b.encoding() + ";" + ""); } + public final void xor_b16(Register d, Register a, Register b) { + emitString("xor.b16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void xor_b32(Register d, Register a, Register b) { + emitString("xor.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void xor_b64(Register d, Register a, Register b) { + emitString("xor.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void xor_b16(Register d, Register a, short b16) { + emitString("xor.b16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b16 + ";" + ""); + } + + public final void xor_b32(Register d, Register a, int b32) { + emitString("xor.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b32 + ";" + ""); + } + + public final void xor_b64(Register d, Register a, long b64) { + emitString("xor.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b64 + ";" + ""); + } + @Override public PTXAddress makeAddress(Register base, int displacement) { return new PTXAddress(base, displacement); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java --- a/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -67,7 +67,11 @@ protected Object runTest(String methodName, CodeGenTest test, Object... args) { Method method = getMethod(methodName); InstalledCode code = assembleMethod(method, test); - return code.executeVarargs(args); + try { + return code.executeVarargs(args); + } catch (InvalidInstalledCodeException e) { + throw new RuntimeException(e); + } } protected void assertReturn(String methodName, CodeGenTest test, Object expected, Object... args) { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeStream.java --- a/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeStream.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeStream.java Mon Apr 15 08:51:19 2013 +0200 @@ -168,6 +168,16 @@ } /** + * Reads a constant pool index for an invokedynamic instruction. + * + * @return the constant pool index + */ + public int readCPI4() { + assert opcode == Bytecodes.INVOKEDYNAMIC; + return Bytes.beS4(code, curBCI + 1); + } + + /** * Reads a signed, 1-byte value for the current instruction (e.g. BIPUSH). * * @return the byte diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Mon Apr 15 08:51:19 2013 +0200 @@ -212,17 +212,17 @@ } @Override - public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap) { + public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, DeoptimizingNode deopting) { AMD64AddressValue loadAddress = prepareAddress(kind, base, displacement, index, scale); Variable result = newVariable(loadAddress.getKind()); - append(new LoadOp(result, loadAddress, canTrap ? state() : null)); + append(new LoadOp(result, loadAddress, deopting != null ? state(deopting) : null)); return result; } @Override - public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, boolean canTrap) { + public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, DeoptimizingNode deopting) { AMD64AddressValue storeAddress = prepareAddress(kind, base, displacement, index, scale); - LIRFrameState state = canTrap ? state() : null; + LIRFrameState state = deopting != null ? state(deopting) : null; if (isConstant(inputVal)) { Constant c = asConstant(inputVal); @@ -369,11 +369,11 @@ } @Override - public void emitNullCheck(ValueNode v) { + public void emitNullCheck(ValueNode v, DeoptimizingNode deoping) { assert v.kind() == Kind.Object; Variable obj = newVariable(Kind.Object); emitMove(obj, operand(v)); - append(new AMD64Move.NullCheckOp(obj, state())); + append(new AMD64Move.NullCheckOp(obj, state(deoping))); } @Override @@ -509,7 +509,7 @@ if (((fixedWithNextNode instanceof IntegerDivNode) || (fixedWithNextNode instanceof IntegerRemNode)) && fixedWithNextNode.getClass() != divRem.getClass()) { FixedBinaryNode otherDivRem = (FixedBinaryNode) fixedWithNextNode; if (otherDivRem.x() == divRem.x() && otherDivRem.y() == divRem.y() && operand(otherDivRem) == null) { - Value[] results = emitIntegerDivRem(operand(divRem.x()), operand(divRem.y())); + Value[] results = emitIntegerDivRem(operand(divRem.x()), operand(divRem.y()), (DeoptimizingNode) valueNode); if (divRem instanceof IntegerDivNode) { setResult(divRem, results[0]); setResult(otherDivRem, results[1]); @@ -526,19 +526,20 @@ return false; } - private void emitDivRem(AMD64Arithmetic op, Value a, Value b) { + private void emitDivRem(AMD64Arithmetic op, Value a, Value b, LIRFrameState state) { AllocatableValue rax = AMD64.rax.asValue(a.getKind()); emitMove(rax, a); - append(new DivRemOp(op, rax, asAllocatable(b), state())); + append(new DivRemOp(op, rax, asAllocatable(b), state)); } - public Value[] emitIntegerDivRem(Value a, Value b) { + public Value[] emitIntegerDivRem(Value a, Value b, DeoptimizingNode deopting) { + LIRFrameState state = state(deopting); switch (a.getKind()) { case Int: - emitDivRem(IDIVREM, a, b); + emitDivRem(IDIVREM, a, b, state); return new Value[]{emitMove(RAX_I), emitMove(RDX_I)}; case Long: - emitDivRem(LDIVREM, a, b); + emitDivRem(LDIVREM, a, b, state); return new Value[]{emitMove(RAX_L), emitMove(RDX_L)}; default: throw GraalInternalError.shouldNotReachHere(); @@ -546,13 +547,13 @@ } @Override - public Value emitDiv(Value a, Value b) { + public Value emitDiv(Value a, Value b, DeoptimizingNode deopting) { switch (a.getKind()) { case Int: - emitDivRem(IDIV, a, b); + emitDivRem(IDIV, a, b, state(deopting)); return emitMove(RAX_I); case Long: - emitDivRem(LDIV, a, b); + emitDivRem(LDIV, a, b, state(deopting)); return emitMove(RAX_L); case Float: { Variable result = newVariable(a.getKind()); @@ -570,21 +571,21 @@ } @Override - public Value emitRem(Value a, Value b) { + public Value emitRem(Value a, Value b, DeoptimizingNode deopting) { switch (a.getKind()) { case Int: - emitDivRem(IREM, a, b); + emitDivRem(IREM, a, b, state(deopting)); return emitMove(RDX_I); case Long: - emitDivRem(LREM, a, b); + emitDivRem(LREM, a, b, state(deopting)); return emitMove(RDX_L); case Float: { RuntimeCallTarget stub = runtime.lookupRuntimeCall(ARITHMETIC_FREM); - return emitCall(stub, stub.getCallingConvention(), false, a, b); + return emitCall(stub, stub.getCallingConvention(), null, a, b); } case Double: { RuntimeCallTarget stub = runtime.lookupRuntimeCall(ARITHMETIC_DREM); - return emitCall(stub, stub.getCallingConvention(), false, a, b); + return emitCall(stub, stub.getCallingConvention(), null, a, b); } default: throw GraalInternalError.shouldNotReachHere(); @@ -592,13 +593,14 @@ } @Override - public Variable emitUDiv(Value a, Value b) { + public Variable emitUDiv(Value a, Value b, DeoptimizingNode deopting) { + LIRFrameState state = state(deopting); switch (a.getKind()) { case Int: - emitDivRem(IUDIV, a, b); + emitDivRem(IUDIV, a, b, state); return emitMove(RAX_I); case Long: - emitDivRem(LUDIV, a, b); + emitDivRem(LUDIV, a, b, state); return emitMove(RAX_L); default: throw GraalInternalError.shouldNotReachHere(); @@ -606,13 +608,14 @@ } @Override - public Variable emitURem(Value a, Value b) { + public Variable emitURem(Value a, Value b, DeoptimizingNode deopting) { + LIRFrameState state = state(deopting); switch (a.getKind()) { case Int: - emitDivRem(IUREM, a, b); + emitDivRem(IUREM, a, b, state); return emitMove(RDX_I); case Long: - emitDivRem(LUREM, a, b); + emitDivRem(LUREM, a, b, state); return emitMove(RDX_L); default: throw GraalInternalError.shouldNotReachHere(); @@ -923,4 +926,9 @@ Value[] parameters = visitInvokeArguments(cc, node.arguments); append(new AMD64BreakpointOp(parameters)); } + + @Override + public void visitInfopointNode(InfopointNode i) { + append(new InfopointOp(stateFor(i.stateAfter(), DeoptimizationReason.None), i.reason)); + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ArrayTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ArrayTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,116 @@ +/* + * 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.graal.compiler.ptx.test; + +import java.lang.reflect.Method; + +import org.junit.Test; + +public class ArrayTest extends PTXTestBase { + + @Test + public void testArray() { + compile("testArray1I"); + compile("testArray1J"); + compile("testArray1B"); + compile("testArray1S"); + compile("testArray1C"); + compile("testArray1F"); + compile("testArray1D"); + compile("testArray1L"); + compile("testStoreArray1I"); + compile("testStoreArray1J"); + compile("testStoreArray1B"); + compile("testStoreArray1S"); + compile("testStoreArray1F"); + compile("testStoreArray1D"); + } + + public static int testArray1I(int[] array, int i) { + return array[i]; + } + + public static long testArray1J(long[] array, int i) { + return array[i]; + } + + public static byte testArray1B(byte[] array, int i) { + return array[i]; + } + + public static short testArray1S(short[] array, int i) { + return array[i]; + } + + public static char testArray1C(char[] array, int i) { + return array[i]; + } + + public static float testArray1F(float[] array, int i) { + return array[i]; + } + + public static double testArray1D(double[] array, int i) { + return array[i]; + } + + public static Object testArray1L(Object[] array, int i) { + return array[i]; + } + + public static void testStoreArray1I(int[] array, int i, int val) { + array[i] = val; + } + + public static void testStoreArray1B(byte[] array, int i, byte val) { + array[i] = val; + } + + public static void testStoreArray1S(short[] array, int i, short val) { + array[i] = val; + } + + public static void testStoreArray1J(long[] array, int i, long val) { + array[i] = val; + } + + public static void testStoreArray1F(float[] array, int i, float val) { + array[i] = val; + } + + public static void testStoreArray1D(double[] array, int i, double val) { + array[i] = val; + } + + public static void main(String[] args) { + ArrayTest test = new ArrayTest(); + for (Method m : ArrayTest.class.getMethods()) { + String name = m.getName(); + if (m.getAnnotation(Test.class) == null && name.startsWith("test")) { + // CheckStyle: stop system..print check + System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode())); + // CheckStyle: resume system..print check + } + } + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java --- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -22,81 +22,33 @@ */ package com.oracle.graal.compiler.ptx.test; -import java.lang.reflect.*; - -import org.junit.*; +import java.lang.reflect.Method; -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.runtime.*; -import com.oracle.graal.compiler.*; -import com.oracle.graal.compiler.ptx.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.java.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.PhasePlan.PhasePosition; -import com.oracle.graal.ptx.*; +import org.junit.Test; /** * Test class for small Java methods compiled to PTX kernels. */ -public class BasicPTXTest extends GraalCompilerTest { +public class BasicPTXTest extends PTXTestBase { @Test public void testAdd() { - test("testAddSnippet"); + compile("testAddConst1I"); } - public static int testAddSnippet(int a) { + public static int testAddConst1I(int a) { return a + 1; } - @Test - public void testArray() { - test("testArraySnippet"); - } - - public static int testArraySnippet(int[] array) { - return array[0]; - } - - private CompilationResult test(String snippet) { - StructuredGraph graph = parse(snippet); - Debug.dump(graph, "Graph"); - TargetDescription target = new TargetDescription(new PTX(), true, 1, 0, true); - PTXBackend ptxBackend = new PTXBackend(Graal.getRequiredCapability(CodeCacheProvider.class), target); - PhasePlan phasePlan = new PhasePlan(); - GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.NONE); - phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase); - phasePlan.addPhase(PhasePosition.AFTER_PARSING, new PTXPhase()); - new PTXPhase().apply(graph); - CompilationResult result = GraalCompiler.compileMethod(runtime, ptxBackend, target, graph.method(), graph, null, phasePlan, OptimisticOptimizations.NONE, new SpeculationLog()); - return result; - } - - private static class PTXPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - for (LocalNode local : graph.getNodes(LocalNode.class)) { - if (local.kind() == Kind.Object) { - local.setStamp(StampFactory.declaredNonNull(local.objectStamp().type())); - } - } - } - - } - public static void main(String[] args) { - BasicPTXTest basicPTXTest = new BasicPTXTest(); + BasicPTXTest test = new BasicPTXTest(); Method[] methods = BasicPTXTest.class.getMethods(); for (Method m : methods) { - if (m.getAnnotation(Test.class) != null) { - String name = m.getName() + "Snippet"; - System.out.println(name + ": \n" + new String(basicPTXTest.test(name).getTargetCode())); + String name = m.getName(); + if (m.getAnnotation(Test.class) == null && name.startsWith("test")) { + // CheckStyle: stop system..print check + System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode())); + // CheckStyle: resume system..print check } } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ControlTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ControlTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,95 @@ +/* + * 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.graal.compiler.ptx.test; + +import org.junit.Test; + +import java.lang.reflect.Method; + +public class ControlTest extends PTXTestBase { + + @Test + public void testControl() { + compile("testSwitch1I"); + compile("testStatic"); + compile("testCall"); + compile("testLookupSwitch1I"); + } + + public static int testSwitch1I(int a) { + switch (a) { + case 1: + return 2; + case 2: + return 3; + default: + return 4; + } + } + + public static int testLookupSwitch1I(int a) { + switch (a) { + case 0: return 1; + case 1: return 2; + case 2: return 3; + case 3: return 1; + case 4: return 2; + case 5: return 3; + case 6: return 1; + case 7: return 2; + case 8: return 3; + case 9: return 1; + case 10: return 2; + case 11: return 3; + default: return -1; + } + } + + @SuppressWarnings("unused") + private static Object foo = null; + + public static boolean testStatic(Object o) { + foo = o; + return true; + } + + private static int method(int a, int b) { + return a + b; + } + + public static int testCall(@SuppressWarnings("unused") Object o, int a, int b) { + return method(a, b); + } + + public static void main(String[] args) { + ControlTest test = new ControlTest(); + for (Method m : ControlTest.class.getMethods()) { + String name = m.getName(); + if (m.getAnnotation(Test.class) == null && name.startsWith("test")) { + // CheckStyle: stop system..print check + System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode())); + // CheckStyle: resume system..print check + } + } + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/FloatPTXTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/FloatPTXTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,245 @@ +/* + * 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.graal.compiler.ptx.test; + +import java.lang.reflect.Method; + +import org.junit.*; + + +/* PTX ISA 3.1 - 8.7.3 Floating-Point Instructions */ +public class FloatPTXTest extends PTXTestBase { + + @Test + public void testAdd() { + compile("testAdd2F"); + compile("testAdd2D"); + compile("testAddFConst"); + compile("testAddConstF"); + compile("testAddDConst"); + compile("testAddConstD"); + } + + public static float testAdd2F(float a, float b) { + return a + b; + } + + public static double testAdd2D(double a, double b) { + return a + b; + } + + public static float testAddFConst(float a) { + return a + 32.0F; + } + + public static float testAddConstF(float a) { + return 32.0F + a; + } + + public static double testAddDConst(double a) { + return a + 32.0; + } + + public static double testAddConstD(double a) { + return 32.0 + a; + } + + @Test + public void testSub() { + compile("testSub2F"); + compile("testSub2D"); + compile("testSubFConst"); + compile("testSubConstF"); + compile("testSubDConst"); + compile("testSubConstD"); + } + + public static float testSub2F(float a, float b) { + return a - b; + } + + public static double testSub2D(double a, double b) { + return a - b; + } + + public static float testSubFConst(float a) { + return a - 32.0F; + } + + public static float testSubConstF(float a) { + return 32.0F - a; + } + + public static double testSubDConst(double a) { + return a - 32.0; + } + + public static double testSubConstD(double a) { + return 32.0 - a; + } + + @Test + public void testMul() { + compile("testMul2F"); + compile("testMul2D"); + compile("testMulFConst"); + compile("testMulConstF"); + compile("testMulDConst"); + compile("testMulConstD"); + } + + public static float testMul2F(float a, float b) { + return a * b; + } + + public static double testMul2D(double a, double b) { + return a * b; + } + + public static float testMulFConst(float a) { + return a * 32.0F; + } + + public static float testMulConstF(float a) { + return 32.0F * a; + } + + public static double testMulDConst(double a) { + return a * 32.0; + } + + public static double testMulConstD(double a) { + return 32.0 * a; + } + + @Test + public void testDiv() { + compile("testDiv2F"); + compile("testDiv2D"); + compile("testDivFConst"); + compile("testDivConstF"); + compile("testDivDConst"); + compile("testDivConstD"); + } + + public static float testDiv2F(float a, float b) { + return a / b; + } + + public static double testDiv2D(double a, double b) { + return a / b; + } + + public static float testDivFConst(float a) { + return a / 32.0F; + } + + public static float testDivConstF(float a) { + return 32.0F / a; + } + + public static double testDivDConst(double a) { + return a / 32.0; + } + + public static double testDivConstD(double a) { + return 32.0 / a; + } + + @Test + public void testNeg() { + compile("testNeg2F"); + compile("testNeg2D"); + } + + public static float testNeg2F(float a) { + return -a; + } + + public static double testNeg2D(double a) { + return -a; + } + + @Test + public void testRem() { + // need linkage to PTX remainder() + // compile("testRem2F"); + // compile("testRem2D"); + } + + public static float testRem2F(float a, float b) { + return a % b; + } + + public static double testRem2D(double a, double b) { + return a % b; + } + + @Test + public void testFloatConversion() { + compile("testF2I"); + compile("testF2L"); + compile("testF2D"); + compile("testD2I"); + compile("testD2L"); + compile("testD2F"); + } + + public static int testF2I(float a) { + return (int) a; + } + + public static long testF2L(float a) { + return (long) a; + } + + public static double testF2D(float a) { + return a; + } + + public static int testD2I(double a) { + return (int) a; + } + + public static long testD2L(double a) { + return (long) a; + } + + public static float testD2F(double a) { + return (float) a; + } + + public static void main(String[] args) { + FloatPTXTest test = new FloatPTXTest(); + for (Method m : FloatPTXTest.class.getMethods()) { + String name = m.getName(); + if (m.getAnnotation(Test.class) == null && + name.startsWith("test") && + name.startsWith("testRem") == false) { + // CheckStyle: stop system..print check + System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode())); + // CheckStyle: resume system..print check + } + } + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/IntegerPTXTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/IntegerPTXTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,192 @@ +/* + * 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.graal.compiler.ptx.test; + +import org.junit.Test; + +import java.lang.reflect.Method; + + +public class IntegerPTXTest extends PTXTestBase { + + @Test + public void testAdd() { + compile("testAdd2I"); + compile("testAdd2L"); + compile("testAdd2B"); + compile("testAddIConst"); + compile("testAddConstI"); + } + + public static int testAdd2I(int a, int b) { + return a + b; + } + + public static long testAdd2L(long a, long b) { + return a + b; + } + + public static int testAdd2B(byte a, byte b) { + return a + b; + } + + public static int testAddIConst(int a) { + return a + 32; + } + + public static int testAddConstI(int a) { + return 32 + a; + } + + @Test + public void testSub() { + compile("testSub2I"); + compile("testSub2L"); + compile("testSubIConst"); + compile("testSubConstI"); + } + + public static int testSub2I(int a, int b) { + return a - b; + } + + public static long testSub2L(long a, long b) { + return a - b; + } + + public static int testSubIConst(int a) { + return a - 32; + } + + public static int testSubConstI(int a) { + return 32 - a; + } + + @Test + public void testMul() { + compile("testMul2I"); + compile("testMul2L"); + compile("testMulIConst"); + compile("testMulConstI"); + } + + public static int testMul2I(int a, int b) { + return a * b; + } + + public static long testMul2L(long a, long b) { + return a * b; + } + + public static int testMulIConst(int a) { + return a * 32; + } + + public static int testMulConstI(int a) { + return 32 * a; + } + + @Test + public void testDiv() { + compile("testDiv2I"); + compile("testDiv2L"); + compile("testDivIConst"); + compile("testDivConstI"); + } + + public static int testDiv2I(int a, int b) { + return a / b; + } + + public static long testDiv2L(long a, long b) { + return a / b; + } + + public static int testDivIConst(int a) { + return a / 32; + } + + public static int testDivConstI(int a) { + return 32 / a; + } + + @Test + public void testRem() { + compile("testRem2I"); + compile("testRem2L"); + } + + public static int testRem2I(int a, int b) { + return a % b; + } + + public static long testRem2L(long a, long b) { + return a % b; + } + + @Test + public void testIntConversion() { + compile("testI2L"); + compile("testL2I"); + compile("testI2C"); + compile("testI2B"); + compile("testI2F"); + compile("testI2D"); + } + + public static long testI2L(int a) { + return a; + } + + public static char testI2C(int a) { + return (char) a; + } + + public static byte testI2B(int a) { + return (byte) a; + } + + public static float testI2F(int a) { + return a; + } + + public static double testI2D(int a) { + return a; + } + + public static int testL2I(long a) { + return (int) a; + } + + public static void main(String[] args) { + IntegerPTXTest test = new IntegerPTXTest(); + for (Method m : IntegerPTXTest.class.getMethods()) { + String name = m.getName(); + if (m.getAnnotation(Test.class) == null && name.startsWith("test")) { + // CheckStyle: stop system..print check + System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode())); + // CheckStyle: resume system..print check + } + } + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/LogicPTXTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/LogicPTXTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,138 @@ +/* + * 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.graal.compiler.ptx.test; + +import java.lang.reflect.Method; + +import org.junit.Test; + + +/* PTX ISA 3.1 - 8.7.5 Logic and Shift Instructions */ +public class LogicPTXTest extends PTXTestBase { + + @Test + public void testAnd() { + compile("testAnd2I"); + compile("testAnd2L"); + } + + public static int testAnd2I(int a, int b) { + return a & b; + } + + public static long testAnd2L(long a, long b) { + return a & b; + } + + @Test + public void testOr() { + compile("testOr2I"); + compile("testOr2L"); + } + + public static int testOr2I(int a, int b) { + return a | b; + } + + public static long testOr2L(long a, long b) { + return a | b; + } + + @Test + public void testXor() { + compile("testXor2I"); + compile("testXor2L"); + } + + public static int testXor2I(int a, int b) { + return a ^ b; + } + + public static long testXor2L(long a, long b) { + return a ^ b; + } + + @Test + public void testNot() { + compile("testNot1I"); + compile("testNot1L"); + } + + public static int testNot1I(int a) { + return ~a; + } + + public static long testNot1L(long a) { + return ~a; + } + + @Test + public void testShiftLeft() { + compile("testShiftLeft2I"); + compile("testShiftLeft2L"); + } + + public static int testShiftLeft2I(int a, int b) { + return a << b; + } + + public static long testShiftLeft2L(long a, int b) { + return a << b; + } + + @Test + public void testShiftRight() { + compile("testShiftRight2I"); + compile("testShiftRight2L"); + compile("testUnsignedShiftRight2I"); + compile("testUnsignedShiftRight2L"); + } + + public static int testShiftRight2I(int a, int b) { + return a >> b; + } + + public static long testShiftRight2L(long a, int b) { + return a >> b; + } + + public static int testUnsignedShiftRight2I(int a, int b) { + return a >>> b; + } + + public static long testUnsignedShiftRight2L(long a, long b) { + return a >>> b; + } + + public static void main(String[] args) { + LogicPTXTest test = new LogicPTXTest(); + for (Method m : LogicPTXTest.class.getMethods()) { + String name = m.getName(); + if (m.getAnnotation(Test.class) == null && name.startsWith("test")) { + // CheckStyle: stop system..print check + System.out.println(name + ": \n" + new String(test.compile(name).getTargetCode())); + // CheckStyle: resume system..print check + } + } + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -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. + */ +package com.oracle.graal.compiler.ptx.test; + +import com.oracle.graal.api.meta.Kind; +import com.oracle.graal.nodes.LocalNode; +import com.oracle.graal.nodes.StructuredGraph; +import com.oracle.graal.nodes.type.StampFactory; +import com.oracle.graal.phases.Phase; + + +public class PTXPhase extends Phase { + @Override + protected void run(StructuredGraph graph) { + /* + * Assume that null checks would be done on the CPU caller side prior + * to copying data onto the GPU. + */ + for (LocalNode local : graph.getNodes(LocalNode.class)) { + if (local.kind() == Kind.Object) { + local.setStamp(StampFactory.declaredNonNull(local.objectStamp().type())); + } + } + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/PTXTestBase.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,62 @@ +/* + * 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.graal.compiler.ptx.test; + +import com.oracle.graal.api.code.CodeCacheProvider; +import com.oracle.graal.api.code.CompilationResult; +import com.oracle.graal.api.code.SpeculationLog; +import com.oracle.graal.api.code.TargetDescription; +import com.oracle.graal.api.runtime.Graal; +import com.oracle.graal.compiler.GraalCompiler; +import com.oracle.graal.compiler.ptx.PTXBackend; +import com.oracle.graal.compiler.test.GraalCompilerTest; +import com.oracle.graal.debug.Debug; +import com.oracle.graal.java.GraphBuilderConfiguration; +import com.oracle.graal.java.GraphBuilderPhase; +import com.oracle.graal.hotspot.HotSpotGraalRuntime; +import com.oracle.graal.nodes.StructuredGraph; +import com.oracle.graal.phases.OptimisticOptimizations; +import com.oracle.graal.phases.PhasePlan; +import com.oracle.graal.phases.PhasePlan.PhasePosition; +import com.oracle.graal.ptx.PTX; + +public abstract class PTXTestBase extends GraalCompilerTest { + + protected CompilationResult compile(String test) { + StructuredGraph graph = parse(test); + Debug.dump(graph, "Graph"); + TargetDescription target = new TargetDescription(new PTX(), true, 1, 0, true); + PTXBackend ptxBackend = new PTXBackend(Graal.getRequiredCapability(CodeCacheProvider.class), target); + PhasePlan phasePlan = new PhasePlan(); + GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), + OptimisticOptimizations.NONE); + phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase); + phasePlan.addPhase(PhasePosition.AFTER_PARSING, new PTXPhase()); + new PTXPhase().apply(graph); + CompilationResult result = GraalCompiler.compileMethod(runtime, HotSpotGraalRuntime.getInstance().getReplacements(), + ptxBackend, target, graph.method(), graph, null, phasePlan, + OptimisticOptimizations.NONE, new SpeculationLog()); + return result; + } + +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXBackend.java --- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXBackend.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXBackend.java Mon Apr 15 08:51:19 2013 +0200 @@ -94,7 +94,7 @@ codeBuffer.emitString(""); // XXX For now declare one predicate and all registers - codeBuffer.emitString(" .reg .pred %p;"); + codeBuffer.emitString(" .reg .pred %p,%q;"); codeBuffer.emitString(" .reg .u32 %r<16>;"); // Emit code for the LIR diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java --- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Mon Apr 15 08:51:19 2013 +0200 @@ -28,35 +28,59 @@ import static com.oracle.graal.lir.ptx.PTXBitManipulationOp.IntrinsicOpcode.*; import static com.oracle.graal.lir.ptx.PTXCompare.*; -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.*; -import com.oracle.graal.compiler.gen.*; -import com.oracle.graal.compiler.target.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.lir.*; +import com.oracle.graal.api.code.AllocatableValue; +import com.oracle.graal.api.code.CodeCacheProvider; +import com.oracle.graal.api.code.DeoptimizationAction; +import com.oracle.graal.api.code.RuntimeCallTarget; +import com.oracle.graal.api.code.StackSlot; +import com.oracle.graal.api.code.TargetDescription; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.Constant; +import com.oracle.graal.api.meta.Kind; +import com.oracle.graal.api.meta.ResolvedJavaMethod; +import com.oracle.graal.api.meta.Value; +import com.oracle.graal.asm.NumUtil; +import com.oracle.graal.compiler.gen.LIRGenerator; +import com.oracle.graal.compiler.target.LIRGenLowerable; +import com.oracle.graal.graph.GraalInternalError; +import com.oracle.graal.lir.FrameMap; +import com.oracle.graal.lir.LIR; +import com.oracle.graal.lir.LIRFrameState; +import com.oracle.graal.lir.LIRInstruction; +import com.oracle.graal.lir.LIRValueUtil; +import com.oracle.graal.lir.LabelRef; import com.oracle.graal.lir.StandardOp.JumpOp; -import com.oracle.graal.lir.ptx.*; +import com.oracle.graal.lir.Variable; +import com.oracle.graal.lir.ptx.PTXAddressValue; import com.oracle.graal.lir.ptx.PTXArithmetic.Op1Stack; import com.oracle.graal.lir.ptx.PTXArithmetic.Op2Reg; import com.oracle.graal.lir.ptx.PTXArithmetic.Op2Stack; import com.oracle.graal.lir.ptx.PTXArithmetic.ShiftOp; +import com.oracle.graal.lir.ptx.PTXBitManipulationOp; import com.oracle.graal.lir.ptx.PTXCompare.CompareOp; import com.oracle.graal.lir.ptx.PTXControlFlow.BranchOp; +import com.oracle.graal.lir.ptx.PTXControlFlow.CondMoveOp; +import com.oracle.graal.lir.ptx.PTXControlFlow.FloatCondMoveOp; import com.oracle.graal.lir.ptx.PTXControlFlow.ReturnOp; +import com.oracle.graal.lir.ptx.PTXControlFlow.SequentialSwitchOp; +import com.oracle.graal.lir.ptx.PTXControlFlow.TableSwitchOp; import com.oracle.graal.lir.ptx.PTXMove.LoadOp; import com.oracle.graal.lir.ptx.PTXMove.MoveFromRegOp; import com.oracle.graal.lir.ptx.PTXMove.MoveToRegOp; import com.oracle.graal.lir.ptx.PTXMove.StoreOp; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.calc.Condition; +import com.oracle.graal.nodes.calc.ConvertNode; +import com.oracle.graal.nodes.java.CompareAndSwapNode; /** * This class implements the PTX specific portion of the LIR generator. */ public class PTXLIRGenerator extends LIRGenerator { + public static final Descriptor ARITHMETIC_FREM = new Descriptor("arithmeticFrem", false, float.class, float.class, float.class); + public static final Descriptor ARITHMETIC_DREM = new Descriptor("arithmeticDrem", false, double.class, double.class, double.class); + public static class PTXSpillMoveFactory implements LIR.SpillMoveFactory { @Override @@ -131,7 +155,7 @@ baseRegister = asAllocatable(base); } - if (index != Value.ILLEGAL) { + if (index != Value.ILLEGAL && scale != 0) { if (isConstant(index)) { finalDisp += asConstant(index).asLong() * scale; } else { @@ -145,6 +169,9 @@ if (baseRegister == AllocatableValue.UNUSED) { baseRegister = asAllocatable(indexRegister); } else { + Variable newBase = newVariable(Kind.Int); + emitMove(newBase, baseRegister); + baseRegister = newBase; baseRegister = emitAdd(baseRegister, indexRegister); } } @@ -154,18 +181,18 @@ } @Override - public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap) { + public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, DeoptimizingNode deopting) { PTXAddressValue loadAddress = prepareAddress(kind, base, displacement, index, scale); Variable result = newVariable(loadAddress.getKind()); - append(new LoadOp(result, loadAddress, canTrap ? state() : null)); + append(new LoadOp(result, loadAddress, deopting != null ? state(deopting) : null)); return result; } @Override - public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, boolean canTrap) { + public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, DeoptimizingNode deopting) { PTXAddressValue storeAddress = prepareAddress(kind, base, displacement, index, scale); Variable input = load(inputVal); - append(new StoreOp(storeAddress, input, canTrap ? state() : null)); + append(new StoreOp(storeAddress, input, deopting != null ? state(deopting) : null)); } @Override @@ -190,6 +217,18 @@ append(new CompareOp(ICMP, cond, left, right)); append(new BranchOp(cond, label)); break; + case Long: + append(new CompareOp(LCMP, cond, left, right)); + append(new BranchOp(cond, label)); + break; + case Float: + append(new CompareOp(FCMP, cond, left, right)); + append(new BranchOp(cond, label)); + break; + case Double: + append(new CompareOp(DCMP, cond, left, right)); + append(new BranchOp(cond, label)); + break; case Object: append(new CompareOp(ACMP, cond, left, right)); append(new BranchOp(cond, label)); @@ -211,7 +250,67 @@ @Override public Variable emitConditionalMove(Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) { - throw new InternalError("NYI"); + boolean mirrored = emitCompare(cond, left, right); + Condition finalCondition = mirrored ? cond.mirror() : cond; + + Variable result = newVariable(trueValue.getKind()); + switch (left.getKind().getStackKind()) { + case Int: + case Long: + case Object: + append(new CondMoveOp(result, finalCondition, load(trueValue), loadNonConst(falseValue))); + break; + case Float: + case Double: + append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue))); + break; + default: + throw GraalInternalError.shouldNotReachHere("missing: " + left.getKind()); + } + return result; + } + + /** + * This method emits the compare instruction, and may reorder the operands. It returns true if + * it did so. + * + * @param a the left operand of the comparison + * @param b the right operand of the comparison + * @return true if the left and right operands were switched, false otherwise + */ + private boolean emitCompare(Condition cond, Value a, Value b) { + Variable left; + Value right; + boolean mirrored; + if (LIRValueUtil.isVariable(b)) { + left = load(b); + right = loadNonConst(a); + mirrored = true; + } else { + left = load(a); + right = loadNonConst(b); + mirrored = false; + } + switch (left.getKind().getStackKind()) { + case Int: + append(new CompareOp(ICMP, cond, left, right)); + break; + case Long: + append(new CompareOp(LCMP, cond, left, right)); + break; + case Object: + append(new CompareOp(ACMP, cond, left, right)); + break; + case Float: + append(new CompareOp(FCMP, cond, left, right)); + break; + case Double: + append(new CompareOp(DCMP, cond, left, right)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + return mirrored; } @Override @@ -226,6 +325,12 @@ case Int: append(new Op1Stack(INEG, result, input)); break; + case Float: + append(new Op1Stack(FNEG, result, input)); + break; + case Double: + append(new Op1Stack(DNEG, result, input)); + break; default: throw GraalInternalError.shouldNotReachHere(); } @@ -239,8 +344,17 @@ case Int: append(new Op2Stack(IADD, result, a, loadNonConst(b))); break; + case Long: + append(new Op2Stack(LADD, result, a, loadNonConst(b))); + break; + case Float: + append(new Op2Stack(FADD, result, a, loadNonConst(b))); + break; + case Double: + append(new Op2Stack(DADD, result, a, loadNonConst(b))); + break; default: - throw GraalInternalError.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind() + " prim: " + a.getKind().isPrimitive()); } return result; } @@ -252,8 +366,17 @@ case Int: append(new Op2Stack(ISUB, result, a, loadNonConst(b))); break; + case Long: + append(new Op2Stack(LSUB, result, a, loadNonConst(b))); + break; + case Float: + append(new Op2Stack(FSUB, result, a, loadNonConst(b))); + break; + case Double: + append(new Op2Stack(DSUB, result, a, loadNonConst(b))); + break; default: - throw GraalInternalError.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind()); } return result; } @@ -265,8 +388,17 @@ case Int: append(new Op2Reg(IMUL, result, a, loadNonConst(b))); break; + case Long: + append(new Op2Reg(LMUL, result, a, loadNonConst(b))); + break; + case Float: + append(new Op2Stack(FMUL, result, a, loadNonConst(b))); + break; + case Double: + append(new Op2Stack(DMUL, result, a, loadNonConst(b))); + break; default: - throw GraalInternalError.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind()); } return result; } @@ -278,22 +410,50 @@ } @Override - public Value emitDiv(Value a, Value b) { + public Value emitDiv(Value a, Value b, DeoptimizingNode deopting) { + Variable result = newVariable(a.getKind()); + switch (a.getKind()) { + case Int: + append(new Op2Reg(IDIV, result, a, loadNonConst(b))); + break; + case Long: + append(new Op2Reg(LDIV, result, a, loadNonConst(b))); + break; + case Float: + append(new Op2Stack(FDIV, result, a, loadNonConst(b))); + break; + case Double: + append(new Op2Stack(DDIV, result, a, loadNonConst(b))); + break; + default: + throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind()); + } + return result; + } + + @Override + public Value emitRem(Value a, Value b, DeoptimizingNode deopting) { + Variable result = newVariable(a.getKind()); + switch (a.getKind()) { + case Int: + append(new Op2Reg(IREM, result, a, loadNonConst(b))); + break; + case Long: + append(new Op2Reg(LREM, result, a, loadNonConst(b))); + break; + default: + throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind()); + } + return result; + } + + @Override + public Variable emitUDiv(Value a, Value b, DeoptimizingNode deopting) { throw new InternalError("NYI"); } @Override - public Value emitRem(Value a, Value b) { - throw new InternalError("NYI"); - } - - @Override - public Variable emitUDiv(Value a, Value b) { - throw new InternalError("NYI"); - } - - @Override - public Variable emitURem(Value a, Value b) { + public Variable emitURem(Value a, Value b, DeoptimizingNode deopting) { throw new InternalError("NYI"); } @@ -304,6 +464,42 @@ case Int: append(new Op2Stack(IAND, result, a, loadNonConst(b))); break; + case Long: + append(new Op2Stack(LAND, result, a, loadNonConst(b))); + break; + + default: + throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind()); + } + return result; + } + + @Override + public Variable emitOr(Value a, Value b) { + Variable result = newVariable(a.getKind()); + switch (a.getKind()) { + case Int: + append(new Op2Stack(IOR, result, a, loadNonConst(b))); + break; + case Long: + append(new Op2Stack(LOR, result, a, loadNonConst(b))); + break; + default: + throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind()); + } + return result; + } + + @Override + public Variable emitXor(Value a, Value b) { + Variable result = newVariable(a.getKind()); + switch (a.getKind()) { + case Int: + append(new Op2Stack(IXOR, result, a, loadNonConst(b))); + break; + case Long: + append(new Op2Stack(LXOR, result, a, loadNonConst(b))); + break; default: throw GraalInternalError.shouldNotReachHere(); } @@ -311,23 +507,35 @@ } @Override - public Variable emitOr(Value a, Value b) { - throw new InternalError("NYI"); - } - - @Override - public Variable emitXor(Value a, Value b) { - throw new InternalError("NYI"); - } - - @Override public Variable emitShl(Value a, Value b) { - throw new InternalError("NYI"); + Variable result = newVariable(a.getKind()); + switch (a.getKind()) { + case Int: + append(new Op2Stack(ISHL, result, a, loadNonConst(b))); + break; + case Long: + append(new Op1Stack(LSHL, result, loadNonConst(b))); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + return result; } @Override public Variable emitShr(Value a, Value b) { - throw new InternalError("NYI"); + Variable result = newVariable(a.getKind()); + switch (a.getKind()) { + case Int: + append(new Op2Stack(ISHR, result, a, loadNonConst(b))); + break; + case Long: + append(new Op1Stack(LSHR, result, loadNonConst(b))); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + return result; } @Override @@ -337,19 +545,91 @@ case Int: append(new ShiftOp(IUSHR, result, a, b)); break; + case Long: + append(new ShiftOp(LUSHR, result, a, b)); + break; default: - GraalInternalError.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere(); } return result; } @Override public Variable emitConvert(ConvertNode.Op opcode, Value inputVal) { - throw new InternalError("NYI"); + Variable input = load(inputVal); + Variable result = newVariable(opcode.to); + switch (opcode) { + case I2L: + append(new Unary2Op(I2L, result, input)); + break; + case L2I: + append(new Unary1Op(L2I, result, input)); + break; + case I2B: + append(new Unary2Op(I2B, result, input)); + break; + case I2C: + append(new Unary1Op(I2C, result, input)); + break; + case I2S: + append(new Unary2Op(I2S, result, input)); + break; + case F2D: + append(new Unary2Op(F2D, result, input)); + break; + case D2F: + append(new Unary2Op(D2F, result, input)); + break; + case I2F: + append(new Unary2Op(I2F, result, input)); + break; + case I2D: + append(new Unary2Op(I2D, result, input)); + break; + case F2I: + append(new Unary2Op(F2I, result, input)); + break; + case D2I: + append(new Unary2Op(D2I, result, input)); + break; + case L2F: + append(new Unary2Op(L2F, result, input)); + break; + case L2D: + append(new Unary2Op(L2D, result, input)); + break; + case F2L: + append(new Unary2Op(F2L, result, input)); + break; + case D2L: + append(new Unary2Op(D2L, result, input)); + break; + case MOV_I2F: + append(new Unary2Op(MOV_I2F, result, input)); + break; + case MOV_L2D: + append(new Unary2Op(MOV_L2D, result, input)); + break; + case MOV_F2I: + append(new Unary2Op(MOV_F2I, result, input)); + break; + case MOV_D2L: + append(new Unary2Op(MOV_D2L, result, input)); + break; + case UNSIGNED_I2L: + // Instructions that move or generate 32-bit register values also set the upper 32 + // bits of the register to zero. + // Consequently, there is no need for a special zero-extension move. + emitMove(result, input); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + return result; } @Override - public void emitDeoptimize(DeoptimizationAction action, DeoptimizationReason reason) { + public void emitDeoptimize(DeoptimizationAction action, DeoptimizingNode deopting) { append(new ReturnOp(Value.ILLEGAL)); } @@ -434,7 +714,14 @@ @Override protected void emitSequentialSwitch(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) { - throw new InternalError("NYI"); + // Making a copy of the switch value is necessary because jump table destroys the input + // value + if (key.getKind() == Kind.Int || key.getKind() == Kind.Long) { + append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, Value.ILLEGAL)); + } else { + assert key.getKind() == Kind.Object : key.getKind(); + append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, newVariable(Kind.Object))); + } } @Override @@ -444,7 +731,10 @@ @Override protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) { - throw new InternalError("NYI"); + // Making a copy of the switch value is necessary because jump table destroys the input + // value + Variable tmp = emitMove(key); + append(new TableSwitchOp(lowKey, defaultTarget, targets, tmp, newVariable(target.wordKind))); } @Override @@ -458,23 +748,24 @@ } @Override - public void visitExceptionObject(ExceptionObjectNode i) { - throw new InternalError("NYI"); - } - - @Override public void visitSafepointNode(SafepointNode i) { + // LIRFrameState info = state(); + // append(new PTXSafepointOp(info, runtime().config, this)); throw new InternalError("NYI"); } @Override public void emitUnwind(Value operand) { - // TODO Auto-generated method stub - + throw new InternalError("NYI"); } @Override - public void emitNullCheck(ValueNode v) { + public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) { + throw new InternalError("NYI"); + } + + @Override + public void visitInfopointNode(InfopointNode i) { throw new InternalError("NYI"); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java --- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Mon Apr 15 08:51:19 2013 +0200 @@ -214,13 +214,13 @@ } @Override - public Value emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap) { + public Value emitLoad(Kind kind, Value base, int displacement, Value index, int scale, DeoptimizingNode canTrap) { // SPARC: Auto-generated method stub return null; } @Override - public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value input, boolean canTrap) { + public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value input, DeoptimizingNode canTrap) { // SPARC: Auto-generated method stub } @@ -262,25 +262,25 @@ } @Override - public Value emitDiv(Value a, Value b) { + public Value emitDiv(Value a, Value b, DeoptimizingNode deopting) { // SPARC: Auto-generated method stub return null; } @Override - public Value emitRem(Value a, Value b) { + public Value emitRem(Value a, Value b, DeoptimizingNode deopting) { // SPARC: Auto-generated method stub return null; } @Override - public Value emitUDiv(Value a, Value b) { + public Value emitUDiv(Value a, Value b, DeoptimizingNode deopting) { // SPARC: Auto-generated method stub return null; } @Override - public Value emitURem(Value a, Value b) { + public Value emitURem(Value a, Value b, DeoptimizingNode deopting) { // SPARC: Auto-generated method stub return null; } @@ -334,7 +334,7 @@ } @Override - public void emitDeoptimize(DeoptimizationAction action, DeoptimizationReason reason) { + public void emitDeoptimize(DeoptimizationAction action, DeoptimizingNode deopting) { // SPARC: Auto-generated method stub } @@ -346,12 +346,6 @@ } @Override - public void visitExceptionObject(ExceptionObjectNode i) { - // SPARC: Auto-generated method stub - - } - - @Override public void visitSafepointNode(SafepointNode i) { // SPARC: Auto-generated method stub @@ -370,7 +364,13 @@ } @Override - public void emitNullCheck(ValueNode v) { + public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) { + // SPARC: Auto-generated method stub + + } + + @Override + public void visitInfopointNode(InfopointNode i) { // SPARC: Auto-generated method stub } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,17 +22,17 @@ */ package com.oracle.graal.compiler.test; -import java.util.*; - import org.junit.*; import com.oracle.graal.api.code.*; import com.oracle.graal.debug.*; +import com.oracle.graal.loop.phases.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.phases.*; -import com.oracle.graal.phases.PhasePlan.*; import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.virtual.nodes.*; +import com.oracle.graal.virtual.phases.ea.*; /** * In the following tests, the usages of local variable "a" are replaced with the integer constant @@ -57,17 +57,25 @@ return 1; } - public static Object boxedObject() { + public static Object boxedObjectShort() { return (short) 1; } + public static Object boxedObjectInteger() { + return (int) 1; + } + + public static Integer boxedInteger() { + return 2; + } + public static Short constantBoxedShort() { return s; } @Test public void test1() { - test("test1Snippet", "referenceSnippet1"); + compareGraphs("test1Snippet", "referenceSnippet1"); } @SuppressWarnings("all") @@ -77,17 +85,17 @@ @Test public void test2() { - test("test2Snippet", "referenceSnippet1"); + compareGraphs("test2Snippet", "referenceSnippet1"); } @SuppressWarnings("all") public static short test2Snippet() { - return (Short) boxedObject(); + return (Short) boxedObjectShort(); } @Test public void test3() { - test("test3Snippet", "referenceSnippet1"); + compareGraphs("test3Snippet", "referenceSnippet1"); } @SuppressWarnings("all") @@ -101,7 +109,7 @@ @Test public void test4() { - test("test4Snippet", "referenceSnippet2"); + compareGraphs("test4Snippet", "referenceSnippet2"); } @SuppressWarnings("all") @@ -109,33 +117,238 @@ return constantBoxedShort(); } - private void test(final String snippet, final String referenceSnippet) { - Debug.scope("BoxingEliminationTest", new DebugDumpScope(snippet), new Runnable() { + @Test + public void testLoop() { + compareGraphs("testLoopSnippet", "referenceLoopSnippet", false, true); + } + + public static int testLoopSnippet(int n, int a) { + Integer sum = a; + for (Integer i = 0; i < n; i++) { + sum += i; + } + return sum; + } + + public static int referenceLoopSnippet(int n, int a) { + int sum = a; + for (int i = 0; i < n; i++) { + sum += i; + } + return sum; + } + + @Test + public void testLoop2() { + compareGraphs("testLoop2Snippet", "referenceLoop2Snippet", true, true); + } + + public static int testLoop2Snippet(int n, Integer a) { + Integer sum = a; + for (Integer i = 0; i < n; i++) { + sum += i; + } + return sum; + } + + public static int referenceLoop2Snippet(int n, Integer a) { + Integer sum0; + if (n <= 0) { + sum0 = a; + } else { + int sum = a; + for (int i = 0; i < n; i++) { + sum += i; + } + sum0 = sum; + } + return sum0; + } + + public static int referenceIfSnippet(int a) { + int result; + if (a < 0) { + result = 2; + } else { + result = 1; + } + return result; + } + + @Test + public void testIf() { + compareGraphs("testIfSnippet", "referenceIfSnippet"); + } + + public static int testIfSnippet(int a) { + Integer result; + if (a < 0) { + result = boxedInteger(); + } else { + result = (Integer) boxedObjectInteger(); + } + return result; + } + + @Test + public void testComparison() { + compareGraphs("testComparison1Snippet", "referenceComparisonSnippet"); + compareGraphs("testComparison2Snippet", "referenceComparisonSnippet"); + } + + @SuppressWarnings("cast") + public static boolean testComparison1Snippet(int a, int b) { + return ((Integer) a) == b; + } + + public static boolean testComparison2Snippet(int a, int b) { + Integer x = a; + Integer y = b; + return x == y; + } + + public static boolean referenceComparisonSnippet(int a, int b) { + return a == b; + } + + @Test + public void testLateCanonicalization() { + compareGraphs("testLateCanonicalizationSnippet", "referenceLateCanonicalizationSnippet"); + } + + public static boolean testLateCanonicalizationSnippet(int a) { + Integer x = a; + Integer y = 1000; + return x == y; + } + + public static boolean referenceLateCanonicalizationSnippet(int a) { + return a == 1000; + } + + private StructuredGraph graph; + + public static Integer materializeReferenceSnippet(int a) { + return Integer.valueOf(a); + } + + public static Integer materializeTest1Snippet(int a) { + Integer v = a; + + if (v == a) { + return v; + } else { + return null; + } + } + + @Test + public void materializeTest1() { + test("materializeTest1Snippet", 1); + } + + public static int intTest1Snippet() { + return Integer.valueOf(1); + } + + @Test + public void intTest1() { + ValueNode result = getResult("intTest1Snippet"); + Assert.assertTrue(result.isConstant()); + Assert.assertEquals(1, result.asConstant().asInt()); + } + + public static int mergeTest1Snippet(boolean d, int a, int b) { + Integer v; + if (d) { + v = a; + } else { + v = b; + } + return v; + } + + @Test + public void mergeTest1() { + processMethod("mergeTest1Snippet"); + } + + public static boolean equalsTest1Snippet(int x, int y) { + Integer a = x; + Integer b = y; + return a == b; + } + + @Test + public void equalsTest1() { + processMethod("equalsTest1Snippet"); + } + + public static int loopTest1Snippet(int n, int v) { + Integer sum = 0; + for (int i = 0; i < n; i++) { + sum += v; + } + return sum; + } + + @Test + public void loopTest1() { + processMethod("loopTest1Snippet"); + + } + + final ValueNode getResult(String snippet) { + processMethod(snippet); + assertEquals(1, graph.getNodes(ReturnNode.class).count()); + return graph.getNodes(ReturnNode.class).first().result(); + } + + private void processMethod(final String snippet) { + graph = parse(snippet); + new ComputeProbabilityPhase().apply(graph); + Assumptions assumptions = new Assumptions(false); + HighTierContext context = new HighTierContext(runtime(), assumptions); + new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + new PartialEscapeAnalysisPhase(false, false).apply(graph, context); + new CullFrameStatesPhase().apply(graph); + } + + private void compareGraphs(final String snippet, final String referenceSnippet) { + compareGraphs(snippet, referenceSnippet, false, false); + } + + private void compareGraphs(final String snippet, final String referenceSnippet, final boolean loopPeeling, final boolean excludeVirtual) { + Debug.scope("BoxingEliminationTest " + snippet, new DebugDumpScope(snippet), new Runnable() { @Override public void run() { - StructuredGraph graph = parse(snippet); - BoxingMethodPool pool = new BoxingMethodPool(runtime()); - IdentifyBoxingPhase identifyBoxingPhase = new IdentifyBoxingPhase(pool); - PhasePlan phasePlan = getDefaultPhasePlan(); - phasePlan.addPhase(PhasePosition.AFTER_PARSING, identifyBoxingPhase); - identifyBoxingPhase.apply(graph); - Map hints = new HashMap<>(); - for (Invoke invoke : graph.getInvokes()) { - hints.put(invoke, 1000d); + graph = parse(snippet); + + new ComputeProbabilityPhase().apply(graph); + Assumptions assumptions = new Assumptions(false); + HighTierContext context = new HighTierContext(runtime(), assumptions); + new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + if (loopPeeling) { + new LoopTransformHighPhase().apply(graph); + } + new DeadCodeEliminationPhase().apply(graph); + new CanonicalizerPhase().apply(graph, context); + new PartialEscapeAnalysisPhase(false, false).apply(graph, context); + + for (MaterializeObjectNode materialize : graph.getNodes(MaterializeObjectNode.class)) { + materialize.getVirtualObject().materializeAt(materialize, materialize.getValues(), false, materialize.getLockCount()); } - Assumptions assumptions = new Assumptions(false); - new InliningPhase(runtime(), hints, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); - Debug.dump(graph, "Graph"); - new BoxingEliminationPhase(runtime()).apply(graph); - Debug.dump(graph, "Graph"); - new ExpandBoxingNodesPhase(pool).apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); + new CullFrameStatesPhase().apply(graph); new DeadCodeEliminationPhase().apply(graph); + new CanonicalizerPhase().apply(graph, context); + StructuredGraph referenceGraph = parse(referenceSnippet); - assertEquals(referenceGraph, graph); + new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(referenceGraph); + new DeadCodeEliminationPhase().apply(referenceGraph); + new CanonicalizerPhase().apply(referenceGraph, context); + assertEquals(referenceGraph, graph, excludeVirtual); } }); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -35,7 +35,7 @@ private StructuredGraph getCanonicalizedGraph(String name) { StructuredGraph graph = parse(name); - new CanonicalizerPhase(runtime(), null).apply(graph); + new CanonicalizerPhase.Instance(runtime(), null).apply(graph); return graph; } @@ -53,7 +53,7 @@ assertEquals(referenceGraph, graph); } Assumptions assumptions = new Assumptions(false); - new CanonicalizerPhase(runtime(), assumptions).apply(referenceGraph); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(referenceGraph); for (int i = 1; i < 4; i++) { StructuredGraph graph = getCanonicalizedGraph("canonicalCompare" + i); assertEquals(referenceGraph, graph); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -81,8 +81,8 @@ public void run() { StructuredGraph graph = parse(snippet); - new InliningPhase(runtime(), null, new Assumptions(false), null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); - new CanonicalizerPhase(runtime(), new Assumptions(false)).apply(graph); + new InliningPhase(runtime(), null, replacements, new Assumptions(false), null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + new CanonicalizerPhase.Instance(runtime(), new Assumptions(false)).apply(graph); Debug.dump(graph, "Graph"); StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); Debug.dump(referenceGraph, "ReferenceGraph"); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -57,7 +57,7 @@ public void run() { StructuredGraph graph = parse(snippet); - new LoweringPhase(null, runtime(), new Assumptions(false)).apply(graph); + new LoweringPhase(null, runtime(), replacements, new Assumptions(false)).apply(graph); new FloatingReadPhase().apply(graph); ReturnNode returnNode = null; diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -40,11 +40,13 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.PhasePlan.PhasePosition; import com.oracle.graal.phases.schedule.*; import com.oracle.graal.printer.*; import com.oracle.graal.test.*; +import com.oracle.graal.hotspot.phases.WriteBarrierAdditionPhase; /** * Base class for Graal compiler unit tests. @@ -68,10 +70,12 @@ public abstract class GraalCompilerTest extends GraalTest { protected final GraalCodeCacheProvider runtime; + protected final Replacements replacements; protected final Backend backend; public GraalCompilerTest() { this.runtime = Graal.getRequiredCapability(GraalCodeCacheProvider.class); + this.replacements = Graal.getRequiredCapability(Replacements.class); this.backend = Graal.getRequiredCapability(Backend.class); } @@ -81,11 +85,15 @@ } protected void assertEquals(StructuredGraph expected, StructuredGraph graph) { - String expectedString = getCanonicalGraphString(expected); - String actualString = getCanonicalGraphString(graph); + assertEquals(expected, graph, false); + } + + protected void assertEquals(StructuredGraph expected, StructuredGraph graph, boolean excludeVirtual) { + String expectedString = getCanonicalGraphString(expected, excludeVirtual); + String actualString = getCanonicalGraphString(graph, excludeVirtual); String mismatchString = "mismatch in graphs:\n========= expected =========\n" + expectedString + "\n\n========= actual =========\n" + actualString; - if (expected.getNodeCount() != graph.getNodeCount()) { + if (!excludeVirtual && expected.getNodeCount() != graph.getNodeCount()) { Debug.dump(expected, "Node count not matching - expected"); Debug.dump(graph, "Node count not matching - actual"); Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount() + "\n" + mismatchString); @@ -98,7 +106,7 @@ } protected void assertConstantReturn(StructuredGraph graph, int value) { - String graphString = getCanonicalGraphString(graph); + String graphString = getCanonicalGraphString(graph, false); Assert.assertEquals("unexpected number of ReturnNodes: " + graphString, graph.getNodes(ReturnNode.class).count(), 1); ValueNode result = graph.getNodes(ReturnNode.class).first().result(); Assert.assertTrue("unexpected ReturnNode result node: " + graphString, result.isConstant()); @@ -106,7 +114,7 @@ Assert.assertEquals("unexpected ReturnNode result: " + graphString, result.asConstant().asInt(), value); } - protected static String getCanonicalGraphString(StructuredGraph graph) { + protected static String getCanonicalGraphString(StructuredGraph graph, boolean excludeVirtual) { SchedulePhase schedule = new SchedulePhase(); schedule.apply(graph); @@ -125,15 +133,17 @@ } result.append("\n"); for (Node node : schedule.getBlockToNodesMap().get(block)) { - int id; - if (canonicalId.get(node) != null) { - id = canonicalId.get(node); - } else { - id = nextId++; - canonicalId.set(node, id); + if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode)) { + int id; + if (canonicalId.get(node) != null) { + id = canonicalId.get(node); + } else { + id = nextId++; + canonicalId.set(node, id); + } + String name = node instanceof ConstantNode ? node.toString(Verbosity.Name) : node.getClass().getSimpleName(); + result.append(" " + id + "|" + name + (excludeVirtual ? "\n" : " (" + node.usages().count() + ")\n")); } - String name = node instanceof ConstantNode ? node.toString(Verbosity.Name) : node.getClass().getSimpleName(); - result.append(" " + id + "|" + name + " (" + node.usages().count() + ")\n"); } } return result.toString(); @@ -395,14 +405,17 @@ } long start = System.currentTimeMillis(); PhasePlan phasePlan = new PhasePlan(); + StructuredGraph graphCopy = graph.copy(); GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL); phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase); + phasePlan.addPhase(PhasePosition.LOW_LEVEL, new WriteBarrierAdditionPhase()); editPhasePlan(method, graph, phasePlan); - CompilationResult compResult = GraalCompiler.compileMethod(runtime(), backend, runtime().getTarget(), method, graph, null, phasePlan, OptimisticOptimizations.ALL, new SpeculationLog()); + CompilationResult compResult = GraalCompiler.compileMethod(runtime(), replacements, backend, runtime().getTarget(), method, graph, null, phasePlan, OptimisticOptimizations.ALL, + new SpeculationLog()); if (printCompilation) { TTY.println(String.format("@%-6d Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, compResult.getTargetCodeSize())); } - return addMethod(method, compResult); + return addMethod(method, compResult, graphCopy); } }); @@ -412,12 +425,12 @@ return installedCode; } - protected InstalledCode addMethod(final ResolvedJavaMethod method, final CompilationResult compResult) { + protected InstalledCode addMethod(final ResolvedJavaMethod method, final CompilationResult compResult, final StructuredGraph graph) { return Debug.scope("CodeInstall", new Object[]{runtime, method}, new Callable() { @Override public InstalledCode call() throws Exception { - InstalledCode installedCode = runtime.addMethod(method, compResult); + InstalledCode installedCode = runtime.addMethod(method, compResult, graph); if (Debug.isDumpEnabled()) { Debug.dump(new Object[]{compResult, installedCode}, "After code installation"); } @@ -440,25 +453,41 @@ * Parses a Java method to produce a graph. */ protected StructuredGraph parse(Method m) { - ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(m); - StructuredGraph graph = new StructuredGraph(javaMethod); - new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); - return graph; + return parse0(m, GraphBuilderConfiguration.getEagerDefault()); } /** * Parses a Java method to produce a graph. */ protected StructuredGraph parseProfiled(Method m) { + return parse0(m, GraphBuilderConfiguration.getDefault()); + } + + /** + * Parses a Java method in debug mode to produce a graph with extra infopoints. + */ + protected StructuredGraph parseDebug(Method m) { + GraphBuilderConfiguration gbConf = GraphBuilderConfiguration.getEagerDefault(); + gbConf.setEagerInfopointMode(true); + return parse0(m, gbConf); + } + + private StructuredGraph parse0(Method m, GraphBuilderConfiguration conf) { ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(m); StructuredGraph graph = new StructuredGraph(javaMethod); - new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL).apply(graph); + new GraphBuilderPhase(runtime, conf, OptimisticOptimizations.ALL).apply(graph); return graph; } protected PhasePlan getDefaultPhasePlan() { + return getDefaultPhasePlan(false); + } + + protected PhasePlan getDefaultPhasePlan(boolean eagerInfopointMode) { PhasePlan plan = new PhasePlan(); - plan.addPhase(PhasePosition.AFTER_PARSING, new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL)); + GraphBuilderConfiguration gbConf = GraphBuilderConfiguration.getEagerDefault(); + gbConf.setEagerInfopointMode(eagerInfopointMode); + plan.addPhase(PhasePosition.AFTER_PARSING, new GraphBuilderPhase(runtime, gbConf, OptimisticOptimizations.ALL)); return plan; } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,111 +0,0 @@ -/* - * Copyright (c) 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. - */ -package com.oracle.graal.compiler.test; - -import java.util.*; - -import org.junit.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.PhasePlan.PhasePosition; -import com.oracle.graal.phases.common.*; - -public class IfBoxingEliminationTest extends GraalCompilerTest { - - private static final String REFERENCE_SNIPPET = "referenceSnippet"; - - public static int referenceSnippet(int a) { - int result; - if (a < 0) { - result = 1; - } else { - result = 2; - } - return result; - } - - public static Integer boxedInteger() { - return 1; - } - - public static Object boxedObject() { - return 2; - } - - @Test - public void test1() { - test("test1Snippet"); - } - - public static int test1Snippet(int a) { - Integer result; - if (a < 0) { - result = boxedInteger(); - } else { - result = (Integer) boxedObject(); - } - return result; - } - - private void test(final String snippet) { - Debug.scope("IfBoxingEliminationTest", new DebugDumpScope(snippet), new Runnable() { - - @Override - public void run() { - StructuredGraph graph = parse(snippet); - BoxingMethodPool pool = new BoxingMethodPool(runtime()); - IdentifyBoxingPhase identifyBoxingPhase = new IdentifyBoxingPhase(pool); - PhasePlan phasePlan = getDefaultPhasePlan(); - phasePlan.addPhase(PhasePosition.AFTER_PARSING, identifyBoxingPhase); - phasePlan.addPhase(PhasePosition.AFTER_PARSING, new PhiStampPhase()); - identifyBoxingPhase.apply(graph); - Map hints = new HashMap<>(); - for (Invoke invoke : graph.getInvokes()) { - hints.put(invoke, 1000d); - } - - Assumptions assumptions = new Assumptions(false); - new InliningPhase(runtime(), hints, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); - new PhiStampPhase().apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); - Debug.dump(graph, "Graph"); - new BoxingEliminationPhase(runtime()).apply(graph); - Debug.dump(graph, "Graph"); - new ExpandBoxingNodesPhase(pool).apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); - new DeadCodeEliminationPhase().apply(graph); - StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); - new CanonicalizerPhase(runtime(), assumptions).apply(referenceGraph); - new DeadCodeEliminationPhase().apply(referenceGraph); - - assertEquals(referenceGraph, graph); - } - }); - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -144,7 +144,7 @@ n.replaceFirstInput(local, constant); } Debug.dump(graph, "Graph"); - new CanonicalizerPhase(runtime(), new Assumptions(false)).apply(graph); + new CanonicalizerPhase.Instance(runtime(), new Assumptions(false)).apply(graph); StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); assertEquals(referenceGraph, graph); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,92 @@ +/* + * 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.graal.compiler.test; + +import static org.junit.Assert.*; + +import java.lang.reflect.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.CompilationResult.Call; +import com.oracle.graal.api.code.CompilationResult.Infopoint; +import com.oracle.graal.compiler.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.test.*; + +/** + * Test that infopoints in {@link CompilationResult}s have correctly assigned reasons. + */ +public class InfopointReasonTest extends GraalCompilerTest { + + public static final String[] STRINGS = new String[]{"world", "everyone", "you"}; + + public String testMethod() { + StringBuilder sb = new StringBuilder("Hello "); + for (String s : STRINGS) { + sb.append(s).append(", "); + } + sb.replace(sb.length() - 2, sb.length(), "!"); + return sb.toString(); + } + + @Test + public void callInfopoints() { + final Method method = getMethod("testMethod"); + final StructuredGraph graph = parse(method); + final CompilationResult cr = GraalCompiler.compileMethod(runtime, replacements, backend, runtime.getTarget(), runtime.lookupJavaMethod(method), graph, null, getDefaultPhasePlan(), + OptimisticOptimizations.ALL, new SpeculationLog()); + for (Infopoint sp : cr.getInfopoints()) { + assertNotNull(sp.reason); + if (sp instanceof Call) { + assertEquals(InfopointReason.CALL, sp.reason); + } + } + } + + @LongTest + public void lineInfopoints() { + final Method method = getMethod("testMethod"); + final StructuredGraph graph = parseDebug(method); + int graphLineSPs = 0; + for (InfopointNode ipn : graph.getNodes(InfopointNode.class)) { + if (ipn.reason == InfopointReason.LINE_NUMBER) { + ++graphLineSPs; + } + } + assertTrue(graphLineSPs > 0); + final CompilationResult cr = GraalCompiler.compileMethod(runtime, replacements, backend, runtime.getTarget(), runtime.lookupJavaMethod(method), graph, null, getDefaultPhasePlan(true), + OptimisticOptimizations.ALL, new SpeculationLog()); + int lineSPs = 0; + for (Infopoint sp : cr.getInfopoints()) { + assertNotNull(sp.reason); + if (sp.reason == InfopointReason.LINE_NUMBER) { + ++lineSPs; + } + } + assertTrue(lineSPs > 0); + } + +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -65,8 +65,8 @@ hints.put(invoke, 1000d); } Assumptions assumptions = new Assumptions(false); - new InliningPhase(runtime(), hints, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); + new InliningPhase(runtime(), hints, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(graph); new DeadCodeEliminationPhase().apply(graph); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -76,8 +76,8 @@ } Assumptions assumptions = new Assumptions(false); - new InliningPhase(runtime(), hints, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); + new InliningPhase(runtime(), hints, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(graph); new DeadCodeEliminationPhase().apply(graph); StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); assertEquals(referenceGraph, graph); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -133,8 +133,8 @@ } Assumptions assumptions = new Assumptions(false); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(referenceGraph); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(graph); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(referenceGraph); Debug.scope("Test", new DebugDumpScope("Test:" + snippet), new Runnable() { @Override diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -219,9 +219,9 @@ StructuredGraph graph = parse(snippet); if (mode == TestMode.INLINED_WITHOUT_FRAMESTATES) { Assumptions assumptions = new Assumptions(false); - new InliningPhase(runtime(), null, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); } - new LoweringPhase(null, runtime(), new Assumptions(false)).apply(graph); + new LoweringPhase(null, runtime(), replacements, new Assumptions(false)).apply(graph); if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) { for (Node node : graph.getNodes()) { if (node instanceof StateSplit) { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -93,8 +93,8 @@ hints.put(invoke, 1000d); } Assumptions assumptions = new Assumptions(false); - new InliningPhase(runtime(), hints, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); + new InliningPhase(runtime(), hints, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(graph); new DeadCodeEliminationPhase().apply(graph); return graph; } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,92 @@ +/* + * 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.graal.compiler.test; + +import junit.framework.Assert; + +import org.junit.Test; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.phases.common.*; + +public class PushNodesThroughPiTest extends GraalCompilerTest { + + public static class A { + + public long x = 20; + } + + public static class B extends A { + + public long y = 10; + } + + public static long test1Snippet(A a) { + B b = (B) a; + long ret = b.x; // this can be moved before the checkcast + ret += b.y; + // the null-check should be canonicalized with the null-check of the checkcast + ret += b != null ? 100 : 200; + return ret; + } + + @Test + public void test1() { + final String snippet = "test1Snippet"; + Debug.scope("PushThroughPi", new DebugDumpScope(snippet), new Runnable() { + + public void run() { + StructuredGraph graph = compileTestSnippet(snippet); + + for (ReadNode rn : graph.getNodes().filter(ReadNode.class)) { + Object locId = rn.location().locationIdentity(); + if (locId instanceof ResolvedJavaField) { + ResolvedJavaField field = (ResolvedJavaField) locId; + if (field.getName().equals("x")) { + Assert.assertTrue(rn.object() instanceof LocalNode); + } else { + Assert.assertTrue(rn.object() instanceof UnsafeCastNode); + } + } + } + + Assert.assertTrue(graph.getNodes().filter(IsNullNode.class).count() == 1); + } + }); + } + + private StructuredGraph compileTestSnippet(final String snippet) { + StructuredGraph graph = parse(snippet); + new LoweringPhase(null, runtime(), replacements, new Assumptions(false)).apply(graph); + new CanonicalizerPhase.Instance(runtime(), null).apply(graph); + new PushThroughPiPhase().apply(graph); + new CanonicalizerPhase.Instance(runtime(), null).apply(graph); + + return graph; + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCast.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCast.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCast.java Mon Apr 15 08:51:19 2013 +0200 @@ -85,11 +85,11 @@ // structure changes significantly public void run() { StructuredGraph graph = parse(snippet); - new LoweringPhase(null, runtime(), new Assumptions(false)).apply(graph); + new LoweringPhase(null, runtime(), replacements, new Assumptions(false)).apply(graph); new FloatingReadPhase().apply(graph); new EliminatePartiallyRedundantGuardsPhase(true, false).apply(graph); new ReadEliminationPhase().apply(graph); - new CanonicalizerPhase(runtime(), null).apply(graph); + new CanonicalizerPhase.Instance(runtime(), null).apply(graph); Debug.dump(graph, "After lowering"); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReassociateAndCanonicalTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReassociateAndCanonicalTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReassociateAndCanonicalTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -244,9 +244,9 @@ private void test(String test, String ref) { StructuredGraph testGraph = parse(test); Assumptions assumptions = new Assumptions(false); - new CanonicalizerPhase(runtime(), assumptions).apply(testGraph); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(testGraph); StructuredGraph refGraph = parse(ref); - new CanonicalizerPhase(runtime(), assumptions).apply(refGraph); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(refGraph); assertEquals(testGraph, refGraph); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -166,9 +166,9 @@ StructuredGraph graph = parse(snippet); Debug.dump(graph, "Graph"); Assumptions assumptions = new Assumptions(false); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(graph); new ConditionalEliminationPhase(runtime()).apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(graph); StructuredGraph referenceGraph = parse(referenceSnippet); assertEquals(referenceGraph, graph); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StampCanonicalizerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StampCanonicalizerTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StampCanonicalizerTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -98,7 +98,7 @@ private void testZeroReturn(String methodName) { StructuredGraph graph = parse(methodName); - new CanonicalizerPhase(runtime(), new Assumptions(false)).apply(graph); + new CanonicalizerPhase.Instance(runtime(), new Assumptions(false)).apply(graph); new DeadCodeEliminationPhase().apply(graph); assertConstantReturn(graph, 0); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StraighteningTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StraighteningTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StraighteningTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -89,7 +89,7 @@ // No debug scope to reduce console noise for @Test(expected = ...) tests StructuredGraph graph = parse(snippet); Debug.dump(graph, "Graph"); - new CanonicalizerPhase(runtime(), new Assumptions(false)).apply(graph); + new CanonicalizerPhase.Instance(runtime(), new Assumptions(false)).apply(graph); StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); assertEquals(referenceGraph, graph); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -186,13 +186,13 @@ StructuredGraph graph = parse(snippet); Debug.dump(graph, "Graph"); Assumptions assumptions = new Assumptions(false); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(graph); new ConditionalEliminationPhase(runtime()).apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(graph); // a second canonicalizer is needed to process nested MaterializeNodes - new CanonicalizerPhase(runtime(), assumptions).apply(graph); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(graph); StructuredGraph referenceGraph = parse(referenceSnippet); - new CanonicalizerPhase(runtime(), assumptions).apply(referenceGraph); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(referenceGraph); assertEquals(referenceGraph, graph); } @@ -206,19 +206,19 @@ } public static void outputGraph(StructuredGraph graph, String message) { - System.out.println("========================= " + message); + TTY.println("========================= " + message); SchedulePhase schedule = new SchedulePhase(); schedule.apply(graph); for (Block block : schedule.getCFG().getBlocks()) { - System.out.print("Block " + block + " "); + TTY.print("Block " + block + " "); if (block == schedule.getCFG().getStartBlock()) { - System.out.print("* "); + TTY.print("* "); } - System.out.print("-> "); + TTY.print("-> "); for (Block succ : block.getSuccessors()) { - System.out.print(succ + " "); + TTY.print(succ + " "); } - System.out.println(); + TTY.println(); for (Node node : schedule.getBlockToNodesMap().get(block)) { outputNode(node); } @@ -226,11 +226,11 @@ } private static void outputNode(Node node) { - System.out.print(" " + node + " (usage count: " + node.usages().count() + ") (inputs:"); + TTY.print(" " + node + " (usage count: " + node.usages().count() + ") (inputs:"); for (Node input : node.inputs()) { - System.out.print(" " + input.toString(Verbosity.Id)); + TTY.print(" " + input.toString(Verbosity.Id)); } - System.out.println(")"); + TTY.println(")"); if (node instanceof MergeNode) { for (PhiNode phi : ((MergeNode) node).phis()) { outputNode(phi); @@ -242,9 +242,9 @@ StructuredGraph graph = parse(snippet); Debug.dump(graph, "Graph"); Assumptions assumptions = new Assumptions(false); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(graph); new ConditionalEliminationPhase(runtime()).apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(graph); Debug.dump(graph, "Graph"); Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes(clazz).iterator().hasNext()); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -115,7 +115,7 @@ @Override public LIR call() { - return GraalCompiler.emitHIR(runtime, backend.target, graph, assumptions, null, phasePlan, OptimisticOptimizations.NONE, new SpeculationLog()); + return GraalCompiler.emitHIR(runtime, backend.target, graph, replacements, assumptions, null, phasePlan, OptimisticOptimizations.NONE, new SpeculationLog()); } }); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -27,13 +27,10 @@ import org.junit.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.InstalledCode.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.test.*; import com.oracle.graal.graph.*; -import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.test.*; @@ -58,7 +55,7 @@ public void test1() { Method method = getMethod("testMethod"); final StructuredGraph graph = parse(method); - new CanonicalizerPhase(runtime(), new Assumptions(false)).apply(graph); + new CanonicalizerPhase.Instance(runtime(), new Assumptions(false)).apply(graph); new DeadCodeEliminationPhase().apply(graph); for (Node node : graph.getNodes()) { @@ -75,7 +72,7 @@ try { Object result = compiledMethod.execute("1", "2", "3"); Assert.assertEquals("1-2-3", result); - } catch (MethodInvalidatedException t) { + } catch (InvalidInstalledCodeException t) { Assert.fail("method invalidated"); } } @@ -89,7 +86,7 @@ try { Object result = compiledMethod.executeVarargs("1", "2", "3"); Assert.assertEquals("1 2 3", result); - } catch (MethodInvalidatedException t) { + } catch (InvalidInstalledCodeException t) { Assert.fail("method invalidated"); } } @@ -104,98 +101,8 @@ f1 = "0"; Object result = compiledMethod.executeVarargs(this, "1", "2", "3"); Assert.assertEquals("0 1 2 3", result); - } catch (MethodInvalidatedException t) { + } catch (InvalidInstalledCodeException t) { Assert.fail("method invalidated"); } } - - @LongTest - public void test2() throws NoSuchMethodException, SecurityException { - Method method = CompilableObjectImpl.class.getDeclaredMethod("executeHelper", ObjectCompiler.class, String.class); - ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(method); - StructuredGraph graph = new StructuredGraph(javaMethod); - new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.NONE).apply(graph); - new CanonicalizerPhase(runtime, new Assumptions(false)).apply(graph); - new DeadCodeEliminationPhase().apply(graph); - - for (Node node : graph.getNodes()) { - if (node instanceof ConstantNode) { - ConstantNode constant = (ConstantNode) node; - if (constant.kind() == Kind.Object && "1 ".equals(constant.value.asObject())) { - graph.replaceFloating(constant, ConstantNode.forObject("1-", runtime, graph)); - } - } - } - - InstalledCode compiledMethod = getCode(javaMethod, graph); - final CompilableObject compilableObject = new CompilableObjectImpl(0); - - Object result; - result = compilableObject.execute(new ObjectCompilerImpl(compiledMethod), "3"); - Assert.assertEquals("1-3", result); - } - - public abstract class CompilableObject { - - private CompiledObject compiledObject; - private final int compileThreshold; - private int counter; - - public CompilableObject(int compileThreshold) { - this.compileThreshold = compileThreshold; - } - - public final Object execute(ObjectCompiler compiler, String args) { - if (counter++ < compileThreshold || compiler == null) { - return executeHelper(compiler, args); - } else { - compiledObject = compiler.compile(this); - return compiledObject.execute(compiler, args); - } - } - - protected abstract Object executeHelper(ObjectCompiler context, String args); - } - - private final class CompilableObjectImpl extends CompilableObject { - - private CompilableObjectImpl(int compileThreshold) { - super(compileThreshold); - } - - @Override - protected Object executeHelper(ObjectCompiler compiler, String args) { - return "1 " + args; - } - } - - public interface CompiledObject { - - Object execute(ObjectCompiler context, String args); - } - - public interface ObjectCompiler { - - CompiledObject compile(CompilableObject node); - } - - private final class ObjectCompilerImpl implements ObjectCompiler { - - private final InstalledCode compiledMethod; - - private ObjectCompilerImpl(InstalledCode compiledMethod) { - this.compiledMethod = compiledMethod; - } - - @Override - public CompiledObject compile(final CompilableObject node) { - return new CompiledObject() { - - @Override - public Object execute(ObjectCompiler compiler, String args) { - return compiledMethod.execute(node, compiler, args); - } - }; - } - } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/SynchronizedMethodDeoptimizationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/SynchronizedMethodDeoptimizationTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/SynchronizedMethodDeoptimizationTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -27,7 +27,6 @@ import org.junit.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.InstalledCode.MethodInvalidatedException; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.test.*; import com.oracle.graal.nodes.*; @@ -59,7 +58,7 @@ try { Object result = compiledMethod.executeVarargs(testString); Assert.assertEquals(testString, result); - } catch (MethodInvalidatedException t) { + } catch (InvalidInstalledCodeException t) { Assert.fail("method invalidated"); } @@ -67,7 +66,7 @@ Object result = compiledMethod.executeVarargs(new Object[]{null}); Assert.assertEquals(null, result); Assert.assertFalse(compiledMethod.isValid()); - } catch (MethodInvalidatedException t) { + } catch (InvalidInstalledCodeException t) { Assert.fail("method invalidated"); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,7 +22,8 @@ */ package com.oracle.graal.compiler.test.ea; -import junit.framework.*; +import java.util.concurrent.*; + import junit.framework.Assert; import org.junit.Test; @@ -30,10 +31,13 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.test.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; import com.oracle.graal.virtual.nodes.*; import com.oracle.graal.virtual.phases.ea.*; @@ -83,8 +87,8 @@ public static int testMonitorSnippet() { Integer x = new Integer(0); - Integer[] y = new Integer[0]; - Integer[] z = new Integer[1]; + Double y = new Double(0); + Object z = new Object(); synchronized (x) { synchronized (y) { synchronized (z) { @@ -106,8 +110,8 @@ */ public static int testMonitor2Snippet() { Integer x = new Integer(0); - Integer[] y = new Integer[0]; - Integer[] z = new Integer[1]; + Double y = new Double(0); + Object z = new Object(); synchronized (x) { synchronized (y) { synchronized (z) { @@ -161,6 +165,20 @@ return obj.x; } + @Test + public void testModifyingLoop() { + testEscapeAnalysis("testModifyingLoopSnippet", Constant.forInt(1), false); + } + + public int testModifyingLoopSnippet(int a) { + TestObject obj = new TestObject(1, 2); + for (int i = 0; i < a; i++) { + obj.x = 3; + notInlineable(); + } + return obj.x <= 3 ? 1 : 0; + } + public static class TestObject2 { Object o; @@ -192,28 +210,33 @@ return obj2.o instanceof TestObject2; } - private ReturnNode testEscapeAnalysis(String snippet, Constant expectedConstantResult, boolean iterativeEscapeAnalysis) { - StructuredGraph graph = parse(snippet); - try { - for (Invoke n : graph.getInvokes()) { - n.setInliningRelevance(1); - } + private ReturnNode testEscapeAnalysis(String snippet, final Constant expectedConstantResult, final boolean iterativeEscapeAnalysis) { + ResolvedJavaMethod method = runtime.lookupJavaMethod(getMethod(snippet)); + final StructuredGraph graph = new StructuredGraph(method); + + return Debug.scope("GraalCompiler", new Object[]{graph, method, runtime}, new Callable() { + + public ReturnNode call() { + new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); + for (Invoke n : graph.getInvokes()) { + n.setInliningRelevance(1); + } - Assumptions assumptions = new Assumptions(false); - new InliningPhase(runtime(), null, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); - new DeadCodeEliminationPhase().apply(graph); - new PartialEscapeAnalysisPhase(runtime(), assumptions, iterativeEscapeAnalysis, false).apply(graph); - Assert.assertEquals(1, graph.getNodes(ReturnNode.class).count()); - ReturnNode returnNode = graph.getNodes(ReturnNode.class).first(); - if (expectedConstantResult != null) { - Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant()); - Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant()); + Assumptions assumptions = new Assumptions(false); + HighTierContext context = new HighTierContext(runtime(), assumptions); + new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + new DeadCodeEliminationPhase().apply(graph); + new PartialEscapeAnalysisPhase(iterativeEscapeAnalysis, false).apply(graph, context); + Assert.assertEquals(1, graph.getNodes(ReturnNode.class).count()); + ReturnNode returnNode = graph.getNodes(ReturnNode.class).first(); + if (expectedConstantResult != null) { + Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant()); + Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant()); + } + int newInstanceCount = graph.getNodes(NewInstanceNode.class).count() + graph.getNodes(NewArrayNode.class).count() + graph.getNodes(MaterializeObjectNode.class).count(); + Assert.assertEquals(0, newInstanceCount); + return returnNode; } - int newInstanceCount = graph.getNodes(NewInstanceNode.class).count() + graph.getNodes(NewArrayNode.class).count() + graph.getNodes(MaterializeObjectNode.class).count(); - Assert.assertEquals(0, newInstanceCount); - return returnNode; - } catch (AssertionFailedError t) { - throw new RuntimeException(t.getMessage() + "\n" + getCanonicalGraphString(graph), t); - } + }); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -34,6 +34,7 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; import com.oracle.graal.virtual.phases.ea.*; public class IterativeInliningTest extends GraalCompilerTest { @@ -102,6 +103,7 @@ graph = parse(snippet); new ComputeProbabilityPhase().apply(graph); GraalOptions.OptEarlyReadElimination = true; - new IterativeInliningPhase(runtime(), new Assumptions(false), null, getDefaultPhasePlan(), OptimisticOptimizations.ALL, false).apply(graph); + HighTierContext context = new HighTierContext(runtime(), new Assumptions(false)); + new IterativeInliningPhase(replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL, false).apply(graph, context); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -34,6 +34,7 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; import com.oracle.graal.virtual.phases.ea.*; public class PEAReadEliminationTest extends GraalCompilerTest { @@ -143,10 +144,11 @@ } @SuppressWarnings("all") - public static int testBadLoopSnippet(TestObject obj, int a, int b) { + public static int testBadLoopSnippet(TestObject obj, TestObject obj2, int a, int b) { obj.x = a; for (int i = 0; i < 10; i++) { staticField = obj; + obj2.x = 10; obj.x = 0; } return obj.x; @@ -155,6 +157,24 @@ @Test public void testBadLoop() { ValueNode result = getReturn("testBadLoopSnippet").result(); + assertEquals(0, graph.getNodes(LoadFieldNode.class).count()); + assertTrue(result instanceof ProxyNode); + assertTrue(((ProxyNode) result).value() instanceof PhiNode); + } + + @SuppressWarnings("all") + public static int testBadLoop2Snippet(TestObject obj, TestObject obj2, int a, int b) { + obj.x = a; + for (int i = 0; i < 10; i++) { + obj.x = 0; + obj2.x = 10; + } + return obj.x; + } + + @Test + public void testBadLoop2() { + ValueNode result = getReturn("testBadLoop2Snippet").result(); assertEquals(1, graph.getNodes(LoadFieldNode.class).count()); assertTrue(result instanceof LoadFieldNode); } @@ -203,7 +223,8 @@ graph = parse(snippet); new ComputeProbabilityPhase().apply(graph); Assumptions assumptions = new Assumptions(false); - new InliningPhase(runtime(), null, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); - new PartialEscapeAnalysisPhase(runtime(), assumptions, false, true).apply(graph); + HighTierContext context = new HighTierContext(runtime(), assumptions); + new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + new PartialEscapeAnalysisPhase(false, true).apply(graph, context); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,18 +22,21 @@ */ package com.oracle.graal.compiler.test.ea; -import junit.framework.*; +import java.util.concurrent.*; + import junit.framework.Assert; import org.junit.Test; import com.oracle.graal.api.code.*; import com.oracle.graal.compiler.test.*; +import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; import com.oracle.graal.virtual.nodes.*; import com.oracle.graal.virtual.phases.ea.*; @@ -72,8 +75,8 @@ } @SuppressWarnings("all") - public static Object test1Snippet(int a, int b) { - TestObject obj = new TestObject(1, 2); + public static Object test1Snippet(int a, int b, Object x, Object y) { + TestObject2 obj = new TestObject2(x, y); if (a < 0) { if (b < 0) { return obj; @@ -90,9 +93,9 @@ testMaterialize("test2Snippet", 1.5, 3, LoadIndexedNode.class); } - public static Object test2Snippet(int a) { - TestObject2 obj = new TestObject2(1, 2); - obj.x = new TestObject2(obj, 3); + public static Object test2Snippet(int a, Object x, Object y, Object z) { + TestObject2 obj = new TestObject2(x, y); + obj.x = new TestObject2(obj, z); if (a < 0) { ((TestObject2) obj.x).y = null; obj.y = null; @@ -125,42 +128,50 @@ @SafeVarargs final void testMaterialize(final String snippet, double expectedProbability, int expectedCount, Class... invalidNodeClasses) { StructuredGraph result = processMethod(snippet); - Assert.assertTrue("partial escape analysis should have removed all NewInstanceNode allocations", result.getNodes(NewInstanceNode.class).isEmpty()); - Assert.assertTrue("partial escape analysis should have removed all NewArrayNode allocations", result.getNodes(NewArrayNode.class).isEmpty()); - double probabilitySum = 0; - int materializeCount = 0; - for (MaterializeObjectNode materialize : result.getNodes(MaterializeObjectNode.class)) { - probabilitySum += materialize.probability(); - materializeCount++; - } - Assert.assertEquals("unexpected number of MaterializeObjectNodes", expectedCount, materializeCount); - Assert.assertEquals("unexpected probability of MaterializeObjectNodes", expectedProbability, probabilitySum, 0.01); - for (Node node : result.getNodes()) { - for (Class clazz : invalidNodeClasses) { - Assert.assertFalse("instance of invalid class: " + clazz.getSimpleName(), clazz.isInstance(node) && node.usages().isNotEmpty()); + try { + Assert.assertTrue("partial escape analysis should have removed all NewInstanceNode allocations", result.getNodes(NewInstanceNode.class).isEmpty()); + Assert.assertTrue("partial escape analysis should have removed all NewArrayNode allocations", result.getNodes(NewArrayNode.class).isEmpty()); + double probabilitySum = 0; + int materializeCount = 0; + for (MaterializeObjectNode materialize : result.getNodes(MaterializeObjectNode.class)) { + probabilitySum += materialize.probability(); + materializeCount++; } + Assert.assertEquals("unexpected number of MaterializeObjectNodes", expectedCount, materializeCount); + Assert.assertEquals("unexpected probability of MaterializeObjectNodes", expectedProbability, probabilitySum, 0.01); + for (Node node : result.getNodes()) { + for (Class clazz : invalidNodeClasses) { + Assert.assertFalse("instance of invalid class: " + clazz.getSimpleName(), clazz.isInstance(node) && node.usages().isNotEmpty()); + } + } + } catch (AssertionError e) { + TypeSystemTest.outputGraph(result, snippet + ": " + e.getMessage()); + throw e; } } private StructuredGraph processMethod(final String snippet) { - StructuredGraph graph = parse(snippet); - try { - new ComputeProbabilityPhase().apply(graph); - for (Invoke n : graph.getInvokes()) { - n.node().setProbability(100000); + return Debug.scope("PartialEscapeAnalysisTest " + snippet, new DebugDumpScope(snippet), new Callable() { + + @Override + public StructuredGraph call() { + StructuredGraph graph = parse(snippet); + new ComputeProbabilityPhase().apply(graph); + for (Invoke n : graph.getInvokes()) { + n.asNode().setProbability(100000); + } + Assumptions assumptions = new Assumptions(false); + HighTierContext context = new HighTierContext(runtime(), assumptions); + new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + new DeadCodeEliminationPhase().apply(graph); + new CanonicalizerPhase().apply(graph, context); + new PartialEscapeAnalysisPhase(false, false).apply(graph, context); + + new CullFrameStatesPhase().apply(graph); + new DeadCodeEliminationPhase().apply(graph); + new CanonicalizerPhase().apply(graph, context); + return graph; } - Assumptions assumptions = new Assumptions(false); - new InliningPhase(runtime(), null, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); - new DeadCodeEliminationPhase().apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); - new PartialEscapeAnalysisPhase(runtime(), assumptions, false, false).apply(graph); - - new CullFrameStatesPhase().apply(graph); - new DeadCodeEliminationPhase().apply(graph); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); - return graph; - } catch (AssertionFailedError t) { - throw new RuntimeException(t.getMessage() + "\n" + getCanonicalGraphString(graph), t); - } + }); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 @@ -24,6 +24,7 @@ import static org.junit.Assert.*; +import java.lang.reflect.*; import java.util.concurrent.*; import org.junit.*; @@ -35,14 +36,15 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; +import com.oracle.graal.test.*; @SuppressWarnings("unused") public class InliningTest extends GraalCompilerTest { @Test public void testInvokeStaticInlining() { - assertInlined(getGraph("invokeStaticSnippet")); - assertInlined(getGraph("invokeStaticOnInstanceSnippet")); + assertInlined(getGraph("invokeStaticSnippet", false)); + assertInlined(getGraph("invokeStaticOnInstanceSnippet", false)); } @SuppressWarnings("all") @@ -57,9 +59,16 @@ @Test public void testStaticBindableInlining() { - assertInlined(getGraph("invokeConstructorSnippet")); - assertInlined(getGraph("invokeFinalMethodSnippet")); - assertInlined(getGraph("invokeMethodOnFinalClassSnippet")); + assertInlined(getGraph("invokeConstructorSnippet", false)); + assertInlined(getGraph("invokeFinalMethodSnippet", false)); + assertInlined(getGraph("invokeMethodOnFinalClassSnippet", false)); + } + + @LongTest + public void testStaticBindableInliningIP() { + assertManyMethodInfopoints(assertInlined(getGraph("invokeConstructorSnippet", true))); + assertManyMethodInfopoints(assertInlined(getGraph("invokeFinalMethodSnippet", true))); + assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFinalClassSnippet", true))); } @SuppressWarnings("all") @@ -81,14 +90,28 @@ @Test public void testClassHierarchyAnalysis() { - assertInlined(getGraph("invokeLeafClassMethodSnippet")); - assertInlined(getGraph("invokeConcreteMethodSnippet")); - assertInlined(getGraph("invokeSingleImplementorInterfaceSnippet")); - // assertInlined(getGraph("invokeConcreteInterfaceMethodSnippet")); + assertInlined(getGraph("invokeLeafClassMethodSnippet", false)); + assertInlined(getGraph("invokeConcreteMethodSnippet", false)); + assertInlined(getGraph("invokeSingleImplementorInterfaceSnippet", false)); + // assertInlined(getGraph("invokeConcreteInterfaceMethodSnippet", false)); + + assertNotInlined(getGraph("invokeOverriddenPublicMethodSnippet", false)); + assertNotInlined(getGraph("invokeOverriddenProtectedMethodSnippet", false)); + assertNotInlined(getGraph("invokeOverriddenInterfaceMethodSnippet", false)); + } - assertNotInlined(getGraph("invokeOverriddenPublicMethodSnippet")); - assertNotInlined(getGraph("invokeOverriddenProtectedMethodSnippet")); - assertNotInlined(getGraph("invokeOverriddenInterfaceMethodSnippet")); + @LongTest + public void testClassHierarchyAnalysisIP() { + assertManyMethodInfopoints(assertInlined(getGraph("invokeLeafClassMethodSnippet", true))); + assertManyMethodInfopoints(assertInlined(getGraph("invokeConcreteMethodSnippet", true))); + assertManyMethodInfopoints(assertInlined(getGraph("invokeSingleImplementorInterfaceSnippet", true))); + //@formatter:off + // assertInlineInfopoints(assertInlined(getGraph("invokeConcreteInterfaceMethodSnippet", true))); + //@formatter:on + + assertFewMethodInfopoints(assertNotInlined(getGraph("invokeOverriddenPublicMethodSnippet", true))); + assertFewMethodInfopoints(assertNotInlined(getGraph("invokeOverriddenProtectedMethodSnippet", true))); + assertFewMethodInfopoints(assertNotInlined(getGraph("invokeOverriddenInterfaceMethodSnippet", true))); } @SuppressWarnings("all") @@ -126,19 +149,20 @@ return superClass.protectedOverriddenMethod(); } - private StructuredGraph getGraph(final String snippet) { + private StructuredGraph getGraph(final String snippet, final boolean eagerInfopointMode) { return Debug.scope("InliningTest", new DebugDumpScope(snippet), new Callable() { @Override public StructuredGraph call() { - StructuredGraph graph = parse(snippet); - PhasePlan phasePlan = getDefaultPhasePlan(); + Method method = getMethod(snippet); + StructuredGraph graph = eagerInfopointMode ? parseDebug(method) : parse(method); + PhasePlan phasePlan = getDefaultPhasePlan(eagerInfopointMode); Assumptions assumptions = new Assumptions(true); new ComputeProbabilityPhase().apply(graph); Debug.dump(graph, "Graph"); - new InliningPhase(runtime(), null, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); + new InliningPhase(runtime(), null, replacements, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); Debug.dump(graph, "Graph"); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(graph); new DeadCodeEliminationPhase().apply(graph); return graph; } @@ -172,6 +196,35 @@ return graph; } + private static int[] countMethodInfopoints(StructuredGraph graph) { + int start = 0; + int end = 0; + for (InfopointNode ipn : graph.getNodes(InfopointNode.class)) { + if (ipn.reason == InfopointReason.METHOD_START) { + ++start; + } else if (ipn.reason == InfopointReason.METHOD_END) { + ++end; + } + } + return new int[]{start, end}; + } + + private static StructuredGraph assertManyMethodInfopoints(StructuredGraph graph) { + int[] counts = countMethodInfopoints(graph); + if (counts[0] <= 1 || counts[1] <= 1) { + fail(String.format("Graph contains too few required method boundary infopoints: %d starts, %d ends.", counts[0], counts[1])); + } + return graph; + } + + private static StructuredGraph assertFewMethodInfopoints(StructuredGraph graph) { + int[] counts = countMethodInfopoints(graph); + if (counts[0] > 1 || counts[1] > 1) { + fail(String.format("Graph contains too many method boundary infopoints: %d starts, %d ends.", counts[0], counts[1])); + } + return graph; + } + // some interfaces and classes for testing private interface MultipleImplementorsInterface { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/DebugFilter.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/DebugFilter.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/DebugFilter.java Mon Apr 15 08:51:19 2013 +0200 @@ -132,9 +132,6 @@ } } } - // if (match) { - // System.out.println(this + " matches " + input); - // } return match; } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Mon Apr 15 08:51:19 2013 +0200 @@ -31,11 +31,11 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.alloc.*; import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.phases.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.debug.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; -import com.oracle.graal.loop.phases.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.spi.*; @@ -43,12 +43,14 @@ import com.oracle.graal.phases.PhasePlan.PhasePosition; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.schedule.*; +import com.oracle.graal.phases.tiers.*; import com.oracle.graal.virtual.phases.ea.*; public class GraalCompiler { - public static CompilationResult compileMethod(final GraalCodeCacheProvider runtime, final Backend backend, final TargetDescription target, final ResolvedJavaMethod method, - final StructuredGraph graph, final GraphCache cache, final PhasePlan plan, final OptimisticOptimizations optimisticOpts, final SpeculationLog speculationLog) { + public static CompilationResult compileMethod(final GraalCodeCacheProvider runtime, final Replacements replacements, final Backend backend, final TargetDescription target, + final ResolvedJavaMethod method, final StructuredGraph graph, final GraphCache cache, final PhasePlan plan, final OptimisticOptimizations optimisticOpts, + final SpeculationLog speculationLog) { assert (method.getModifiers() & Modifier.NATIVE) == 0 : "compiling native methods is not supported"; final CompilationResult compilationResult = new CompilationResult(); @@ -59,7 +61,7 @@ final LIR lir = Debug.scope("FrontEnd", new Callable() { public LIR call() { - return emitHIR(runtime, target, graph, assumptions, cache, plan, optimisticOpts, speculationLog); + return emitHIR(runtime, target, graph, replacements, assumptions, cache, plan, optimisticOpts, speculationLog); } }); final LIRGenerator lirGen = Debug.scope("BackEnd", lir, new Callable() { @@ -98,7 +100,7 @@ * * @param target */ - public static LIR emitHIR(GraalCodeCacheProvider runtime, TargetDescription target, StructuredGraph graph, Assumptions assumptions, GraphCache cache, PhasePlan plan, + public static LIR emitHIR(GraalCodeCacheProvider runtime, TargetDescription target, StructuredGraph graph, Replacements replacements, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts, final SpeculationLog speculationLog) { if (speculationLog != null) { @@ -117,71 +119,42 @@ } if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(runtime, assumptions).apply(graph); + new CanonicalizerPhase.Instance(runtime, assumptions).apply(graph); } + HighTierContext highTierContext = new HighTierContext(runtime, assumptions); + if (GraalOptions.Inline && !plan.isPhaseDisabled(InliningPhase.class)) { if (GraalOptions.IterativeInlining) { - new IterativeInliningPhase(runtime, assumptions, cache, plan, optimisticOpts, GraalOptions.OptEarlyReadElimination).apply(graph); + new IterativeInliningPhase(replacements, cache, plan, optimisticOpts, GraalOptions.OptEarlyReadElimination).apply(graph, highTierContext); } else { - new InliningPhase(runtime, null, assumptions, cache, plan, optimisticOpts).apply(graph); + new InliningPhase(runtime, null, replacements, assumptions, cache, plan, optimisticOpts).apply(graph); new DeadCodeEliminationPhase().apply(graph); if (GraalOptions.ConditionalElimination && GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(runtime, assumptions).apply(graph); + new CanonicalizerPhase.Instance(runtime, assumptions).apply(graph); new IterativeConditionalEliminationPhase(runtime, assumptions).apply(graph); } } } - // new ConvertUnreachedToGuardPhase(optimisticOpts).apply(graph); - plan.runPhases(PhasePosition.HIGH_LEVEL, graph); - if (GraalOptions.FullUnroll) { - new LoopFullUnrollPhase(runtime, assumptions).apply(graph); + Suites.HIGH_TIER.apply(graph, highTierContext); + + new LoweringPhase(target, runtime, replacements, assumptions).apply(graph); + + if (GraalOptions.OptPushThroughPi) { + new PushThroughPiPhase().apply(graph); if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(runtime, assumptions).apply(graph); - } - } - - if (GraalOptions.OptTailDuplication) { - new TailDuplicationPhase().apply(graph); - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(runtime, assumptions).apply(graph); + new CanonicalizerPhase.Instance(runtime, assumptions).apply(graph); } } - if (GraalOptions.PartialEscapeAnalysis && !plan.isPhaseDisabled(PartialEscapeAnalysisPhase.class)) { - new PartialEscapeAnalysisPhase(runtime, assumptions, true, GraalOptions.OptEarlyReadElimination).apply(graph); - } - - if (GraalOptions.OptConvertDeoptsToGuards) { - new ConvertDeoptimizeToGuardPhase().apply(graph); - } - - new LockEliminationPhase().apply(graph); - - if (GraalOptions.OptLoopTransform) { - new LoopTransformHighPhase().apply(graph); - new LoopTransformLowPhase().apply(graph); - } - new RemoveValueProxyPhase().apply(graph); - - if (GraalOptions.CullFrameStates) { - new CullFrameStatesPhase().apply(graph); - } - - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(runtime, assumptions).apply(graph); - } - - new LoweringPhase(target, runtime, assumptions).apply(graph); - if (GraalOptions.OptFloatingReads) { int mark = graph.getMark(); new FloatingReadPhase().apply(graph); - new CanonicalizerPhase(runtime, assumptions, mark, null).apply(graph); + new CanonicalizerPhase.Instance(runtime, assumptions, mark, null).apply(graph); if (GraalOptions.OptReadElimination) { new ReadEliminationPhase().apply(graph); } @@ -189,7 +162,7 @@ new RemoveValueProxyPhase().apply(graph); if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(runtime, assumptions).apply(graph); + new CanonicalizerPhase.Instance(runtime, assumptions).apply(graph); } if (GraalOptions.OptEliminatePartiallyRedundantGuards) { @@ -205,17 +178,23 @@ } if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(runtime, assumptions).apply(graph); + new CanonicalizerPhase.Instance(runtime, assumptions).apply(graph); } plan.runPhases(PhasePosition.MID_LEVEL, graph); - plan.runPhases(PhasePosition.LOW_LEVEL, graph); + // Add safepoints to loops + new SafepointInsertionPhase().apply(graph); new GuardLoweringPhase(target).apply(graph); - // Add safepoints to loops - new SafepointInsertionPhase().apply(graph); + plan.runPhases(PhasePosition.LOW_LEVEL, graph); + + new LoweringPhase(target, runtime, replacements, assumptions).apply(graph); + + new FrameStateAssignmentPhase().apply(graph); + + new DeadCodeEliminationPhase().apply(graph); final SchedulePhase schedule = new SchedulePhase(); schedule.apply(graph); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Mon Apr 15 08:51:19 2013 +0200 @@ -82,21 +82,16 @@ for (Entry entry : virtualObjectsCopy.entrySet()) { if (entry.getValue().getValues() == null) { VirtualObjectNode vobj = entry.getKey(); - if (vobj instanceof BoxedVirtualObjectNode) { - BoxedVirtualObjectNode boxedVirtualObjectNode = (BoxedVirtualObjectNode) vobj; - entry.getValue().setValues(new Value[]{toValue(boxedVirtualObjectNode.getUnboxedValue())}); - } else { - Value[] values = new Value[vobj.entryCount()]; - if (values.length > 0) { - changed = true; - VirtualObjectState currentField = (VirtualObjectState) objectStates.get(vobj); - assert currentField != null; - for (int i = 0; i < vobj.entryCount(); i++) { - values[i] = toValue(currentField.fieldValues().get(i)); - } + Value[] values = new Value[vobj.entryCount()]; + if (values.length > 0) { + changed = true; + VirtualObjectState currentField = (VirtualObjectState) objectStates.get(vobj); + assert currentField != null; + for (int i = 0; i < vobj.entryCount(); i++) { + values[i] = toValue(currentField.fieldValues().get(i)); } - entry.getValue().setValues(values); } + entry.getValue().setValues(values); } } } while (changed); @@ -127,7 +122,7 @@ if (state.outerFrameState() != null) { caller = computeFrameForState(state.outerFrameState()); } - assert state.bci >= 0 || state.bci == FrameState.BEFORE_BCI : "bci == " + state.bci; + assert state.bci != FrameState.UNKNOWN_BCI : "bci == " + state.bci; return new BytecodeFrame(caller, state.method(), state.bci, state.rethrowException(), state.duringCall(), values, numLocals, numStack, numLocks); } @@ -165,7 +160,7 @@ if (value instanceof VirtualObjectNode) { VirtualObjectNode obj = (VirtualObjectNode) value; EscapeObjectState state = objectStates.get(obj); - if (state == null && obj.entryCount() > 0 && !(obj instanceof BoxedVirtualObjectNode)) { + if (state == null && obj.entryCount() > 0) { // null states occur for objects with 0 fields throw new GraalInternalError("no mapping found for virtual object %s", obj); } @@ -173,7 +168,7 @@ assert !(((MaterializedObjectState) state).materializedValue() instanceof VirtualObjectNode); return toValue(((MaterializedObjectState) state).materializedValue()); } else { - assert obj.entryCount() == 0 || state instanceof VirtualObjectState || obj instanceof BoxedVirtualObjectNode; + assert obj.entryCount() == 0 || state instanceof VirtualObjectState; VirtualObject vobject = virtualObjects.get(value); if (vobject == null) { vobject = VirtualObject.get(obj.type(), null, virtualObjects.size()); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Mon Apr 15 08:51:19 2013 +0200 @@ -218,13 +218,18 @@ return false; } - public LIRFrameState state() { - return state(null); + public LIRFrameState state(DeoptimizingNode deopt) { + if (!deopt.canDeoptimize()) { + return null; + } + return stateFor(deopt.getDeoptimizationState(), deopt.getDeoptimizationReason()); } - public LIRFrameState state(DeoptimizationReason reason) { - assert lastState != null || needOnlyOopMaps() : "must have state before instruction"; - return stateFor(lastState, reason); + public LIRFrameState stateWithExceptionEdge(DeoptimizingNode deopt, LabelRef exceptionEdge) { + if (!deopt.canDeoptimize()) { + return null; + } + return stateForWithExceptionEdge(deopt.getDeoptimizationState(), deopt.getDeoptimizationReason(), exceptionEdge); } public LIRFrameState stateFor(FrameState state, DeoptimizationReason reason) { @@ -235,6 +240,7 @@ if (needOnlyOopMaps()) { return new LIRFrameState(null, null, null, (short) -1); } + assert state != null; return debugInfoBuilder.build(state, lir.getDeoptimizationReasons().addSpeculation(reason), exceptionEdge); } @@ -329,11 +335,10 @@ TTY.println("LIRGen for " + instr); } FrameState stateAfter = null; - if (instr instanceof StateSplit) { + if (instr instanceof StateSplit && !(instr instanceof InfopointNode)) { stateAfter = ((StateSplit) instr).stateAfter(); } if (instr instanceof ValueNode) { - ValueNode valueNode = (ValueNode) instr; if (operand(valueNode) == null) { if (!peephole(valueNode)) { @@ -594,18 +599,18 @@ @Override public void emitInvoke(Invoke x) { AbstractCallTargetNode callTarget = (AbstractCallTargetNode) x.callTarget(); - CallingConvention cc = frameMap.registerConfig.getCallingConvention(callTarget.callType(), x.node().stamp().javaType(runtime), callTarget.signature(), target(), false); + CallingConvention cc = frameMap.registerConfig.getCallingConvention(callTarget.callType(), x.asNode().stamp().javaType(runtime), callTarget.signature(), target(), false); frameMap.callsMethod(cc); Value[] parameters = visitInvokeArguments(cc, callTarget.arguments()); - LIRFrameState callState = null; - if (x.stateAfter() != null) { - callState = stateForWithExceptionEdge(x.stateDuring(), null, x instanceof InvokeWithExceptionNode ? getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge()) : null); + LabelRef exceptionEdge = null; + if (x instanceof InvokeWithExceptionNode) { + exceptionEdge = getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge()); } + LIRFrameState callState = stateWithExceptionEdge(x, exceptionEdge); Value result = cc.getReturn(); - if (callTarget instanceof DirectCallTargetNode) { emitDirectCall((DirectCallTargetNode) callTarget, result, parameters, cc.getTemporaries(), callState); } else if (callTarget instanceof IndirectCallTargetNode) { @@ -615,7 +620,7 @@ } if (isLegal(result)) { - setResult(x.node(), emitMove(result)); + setResult(x.asNode(), emitMove(result)); } } @@ -658,8 +663,8 @@ } @Override - public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention cc, boolean canTrap, Value... args) { - LIRFrameState info = canTrap ? state() : null; + public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention cc, DeoptimizingNode info, Value... args) { + LIRFrameState state = info != null ? state(info) : null; // move the arguments into the correct location frameMap.callsMethod(cc); @@ -671,7 +676,7 @@ emitMove(loc, arg); argLocations[i] = loc; } - emitCall(callTarget, cc.getReturn(), argLocations, cc.getTemporaries(), info); + emitCall(callTarget, cc.getReturn(), argLocations, cc.getTemporaries(), state); if (isLegal(cc.getReturn())) { return emitMove(cc.getReturn()); @@ -688,25 +693,7 @@ Value resultOperand = cc.getReturn(); Value[] args = visitInvokeArguments(cc, x.arguments()); - LIRFrameState info = null; - FrameState stateAfter = x.stateAfter(); - if (stateAfter != null) { - // (cwimmer) I made the code that modifies the operand stack conditional. My scenario: - // runtime calls to, e.g., - // CreateNullPointerException have no equivalent in the bytecodes, so there is no invoke - // bytecode. - // Therefore, the result of the runtime call was never pushed to the stack, and we - // cannot pop it here. - FrameState stateBeforeReturn = stateAfter; - if ((stateAfter.stackSize() > 0 && stateAfter.stackAt(stateAfter.stackSize() - 1) == x) || (stateAfter.stackSize() > 1 && stateAfter.stackAt(stateAfter.stackSize() - 2) == x)) { - stateBeforeReturn = stateAfter.duplicateModified(stateAfter.bci, stateAfter.rethrowException(), x.kind()); - } - info = stateFor(stateBeforeReturn, null); - } else { - info = state(); - } - - emitCall(call, resultOperand, args, cc.getTemporaries(), info); + emitCall(call, resultOperand, args, cc.getTemporaries(), state(x)); if (isLegal(resultOperand)) { setResult(x, emitMove(resultOperand)); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/Suites.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/Suites.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,80 @@ +/* + * 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.graal.compiler.phases; + +import java.util.*; + +import com.oracle.graal.loop.phases.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.virtual.phases.ea.*; + +public class Suites { + + public static final PhaseSuite HIGH_TIER = createHighTier(); + + private static PhaseSuite createHighTier() { + ArrayList> phases = new ArrayList<>(); + + if (GraalOptions.FullUnroll) { + phases.add(new LoopFullUnrollPhase()); + if (GraalOptions.OptCanonicalizer) { + phases.add(new CanonicalizerPhase()); + } + } + + if (GraalOptions.OptTailDuplication) { + phases.add(new TailDuplicationPhase()); + if (GraalOptions.OptCanonicalizer) { + phases.add(new CanonicalizerPhase()); + } + } + + if (GraalOptions.PartialEscapeAnalysis) { + phases.add(new PartialEscapeAnalysisPhase(true, GraalOptions.OptEarlyReadElimination)); + } + + if (GraalOptions.OptConvertDeoptsToGuards) { + phases.add(new ConvertDeoptimizeToGuardPhase()); + } + + phases.add(new LockEliminationPhase()); + + if (GraalOptions.OptLoopTransform) { + phases.add(new LoopTransformHighPhase()); + phases.add(new LoopTransformLowPhase()); + } + phases.add(new RemoveValueProxyPhase()); + + if (GraalOptions.CullFrameStates) { + phases.add(new CullFrameStatesPhase()); + } + + if (GraalOptions.OptCanonicalizer) { + phases.add(new CanonicalizerPhase()); + } + + return new PhaseSuite<>("HighTier", phases); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.debug.test/src/com/oracle/graal/debug/test/DebugHistogramTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.debug.test/src/com/oracle/graal/debug/test/DebugHistogramTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2013, 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.graal.debug.test; + +import java.io.*; + +import org.junit.*; + +import com.oracle.graal.debug.*; + +public class DebugHistogramTest { + + @Test + public void testEmptyHistogram() { + DebugHistogram histogram = Debug.createHistogram("TestHistogram"); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + histogram.print(new PrintStream(outputStream)); + Assert.assertEquals("TestHistogram is empty.\n", outputStream.toString()); + } + + @Test + public void testSingleEntryHistogram() { + DebugHistogram histogram = Debug.createHistogram("TestHistogram"); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + histogram.add(new Integer(1)); + histogram.add(new Integer(1)); + histogram.print(new PrintStream(outputStream)); + String[] lines = outputStream.toString().split("\n"); + Assert.assertEquals(4, lines.length); + Assert.assertEquals("TestHistogram has 1 unique elements and 2 total elements:", lines[0]); + Assert.assertEquals( + "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------", + lines[1]); + Assert.assertEquals( + "| 1 | 2 | ==================================================================================================== |", + lines[2]); + Assert.assertEquals( + "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------", + lines[3]); + } + + @Test + public void testMultipleEntryHistogram() { + DebugHistogram histogram = Debug.createHistogram("TestHistogram"); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + histogram.add(new Integer(1)); + histogram.add(new Integer(2)); + histogram.add(new Integer(2)); + histogram.print(new PrintStream(outputStream)); + String[] lines = outputStream.toString().split("\n"); + Assert.assertEquals(5, lines.length); + Assert.assertEquals("TestHistogram has 2 unique elements and 3 total elements:", lines[0]); + Assert.assertEquals( + "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------", + lines[1]); + Assert.assertEquals( + "| 2 | 2 | ==================================================================================================== |", + lines[2]); + Assert.assertEquals( + "| 1 | 1 | ================================================== |", + lines[3]); + Assert.assertEquals( + "--------------------------------------------------------------------------------------------------------------------------------------------------------------------------", + lines[4]); + } + + @Test + public void testTooLongValueString() { + DebugHistogram histogram = Debug.createHistogram("TestHistogram"); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + histogram.add("MyCustomValue"); + histogram.print(new PrintStream(outputStream), Integer.MAX_VALUE, 10, 10); + String[] lines = outputStream.toString().split("\n"); + Assert.assertEquals(4, lines.length); + Assert.assertEquals("TestHistogram has 1 unique elements and 1 total elements:", lines[0]); + Assert.assertEquals("----------------------------------------", lines[1]); + Assert.assertEquals("| MyCusto... | 1 | ========== |", lines[2]); + Assert.assertEquals("----------------------------------------", lines[3]); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Mon Apr 15 08:51:19 2013 +0200 @@ -189,6 +189,10 @@ } } + public static DebugHistogram createHistogram(String name) { + return new DebugHistogramImpl(name); + } + public static DebugConfig fixedConfig(final boolean isLogEnabled, final boolean isDumpEnabled, final boolean isMeterEnabled, final boolean isTimerEnabled, final Collection dumpHandlers, final PrintStream output) { return new DebugConfig() { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugHistogram.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugHistogram.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,36 @@ +/* + * 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.graal.debug; + +import java.io.*; + +public interface DebugHistogram { + + String getName(); + + void add(Object value); + + void print(PrintStream os); + + void print(PrintStream os, int limit, int nameSize, int barSize); +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugHistogramImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugHistogramImpl.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,110 @@ +/* + * 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.graal.debug.internal; + +import java.io.*; +import java.util.*; + +import com.oracle.graal.debug.*; + +public class DebugHistogramImpl implements DebugHistogram { + + public static final int NumberSize = 10; + public static final int DefaultNameSize = 50; + public static final int DefaultBarSize = 100; + private final String name; + private HashMap map = new HashMap<>(); + + public DebugHistogramImpl(String name) { + this.name = name; + } + + public void add(Object value) { + if (!map.containsKey(value)) { + map.put(value, 1); + } else { + map.put(value, map.get(value) + 1); + } + } + + @Override + public String getName() { + return name; + } + + @Override + public void print(PrintStream os) { + print(os, Integer.MAX_VALUE, DefaultNameSize, DefaultBarSize); + } + + public void print(PrintStream os, int limit, int nameSize, int barSize) { + + List list = new ArrayList<>(map.keySet()); + if (list.size() == 0) { + // No elements in the histogram. + os.printf("%s is empty.\n", name); + return; + } + + // Sort from highest to smallest. + Collections.sort(list, new Comparator() { + + @Override + public int compare(Object o1, Object o2) { + return map.get(o2) - map.get(o1); + } + }); + + // Sum up the total number of elements. + int total = 0; + for (Object o : list) { + total += map.get(o); + } + + // Print header. + os.printf("%s has %d unique elements and %d total elements:\n", name, list.size(), total); + + int max = map.get(list.get(0)); + final int lineSize = nameSize + NumberSize + barSize + 10; + printLine(os, '-', lineSize); + String formatString = "| %-" + nameSize + "s | %-" + NumberSize + "d | %-" + barSize + "s |\n"; + for (int i = 0; i < list.size() && i < limit; ++i) { + Object o = list.get(i); + int value = map.get(o); + char[] bar = new char[(int) (((double) value / (double) max) * barSize)]; + Arrays.fill(bar, '='); + String objectString = o.toString(); + if (objectString.length() > nameSize) { + objectString = objectString.substring(0, nameSize - 3) + "..."; + } + os.printf(formatString, objectString, value, new String(bar)); + } + printLine(os, '-', lineSize); + } + + private static void printLine(PrintStream printStream, char c, int lineSize) { + char[] charArr = new char[lineSize]; + Arrays.fill(charArr, c); + printStream.printf("%s\n", new String(charArr)); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/TestNodeInterface.java --- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/TestNodeInterface.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * Copyright (c) 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. - */ -package com.oracle.graal.graph; - -public interface TestNodeInterface { - - String getName(); -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/TypedNodeIteratorTest.java --- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/TypedNodeIteratorTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,166 +0,0 @@ -/* - * Copyright (c) 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. - */ -package com.oracle.graal.graph; - -import static org.junit.Assert.*; - -import java.util.*; - -import org.junit.*; - -public class TypedNodeIteratorTest { - - private static class TestNode extends Node implements Node.IterableNodeType, TestNodeInterface { - - private final String name; - - public TestNode(String name) { - this.name = name; - } - - public String getName() { - return name; - } - } - - @Test - public void singleNodeTest() { - Graph graph = new Graph(); - graph.add(new TestNode("a")); - assertTrue(graph.hasNode(TestNode.class)); - assertEquals("a", toString(graph.getNodes(TestNode.class))); - } - - @Test - public void deletingNodeTest() { - TestNode testNode = new TestNode("a"); - Graph graph = new Graph(); - graph.add(testNode); - testNode.safeDelete(); - assertEquals("", toString(graph.getNodes(TestNode.class))); - } - - @Test - public void deleteAndAddTest() { - TestNode testNode = new TestNode("b"); - Graph graph = new Graph(); - graph.add(new TestNode("a")); - graph.add(testNode); - testNode.safeDelete(); - assertEquals("a", toString(graph.getNodes(TestNode.class))); - graph.add(new TestNode("c")); - assertEquals("ac", toString(graph.getNodes(TestNode.class))); - } - - @Test - public void iteratorBehaviorTest() { - Graph graph = new Graph(); - graph.add(new TestNode("a")); - Iterator iterator = graph.getNodes(TestNode.class).iterator(); - assertTrue(iterator.hasNext()); - assertEquals("a", iterator.next().getName()); - assertFalse(iterator.hasNext()); - graph.add(new TestNode("b")); - assertTrue(iterator.hasNext()); - assertEquals("b", iterator.next().getName()); - assertFalse(iterator.hasNext()); - TestNode c = new TestNode("c"); - graph.add(c); - assertTrue(iterator.hasNext()); - c.safeDelete(); - assertFalse(iterator.hasNext()); - } - - @Test - public void complicatedIterationTest() { - Graph graph = new Graph(); - graph.add(new TestNode("a")); - for (TestNode tn : graph.getNodes(TestNode.class)) { - String name = tn.getName(); - for (int i = 0; i < name.length(); ++i) { - char c = name.charAt(i); - if (c == 'a') { - tn.safeDelete(); - graph.add(new TestNode("b")); - graph.add(new TestNode("c")); - } else if (c == 'b') { - tn.safeDelete(); - } else if (c == 'c') { - graph.add(new TestNode("d")); - graph.add(new TestNode("e")); - graph.add(new TestNode("d")); - graph.add(new TestNode("e")); - graph.add(new TestNode("e")); - graph.add(new TestNode("d")); - graph.add(new TestNode("e")); - graph.add(new TestNode("d")); - } else if (c == 'd') { - for (TestNode tn2 : graph.getNodes(TestNode.class)) { - if (tn2.getName().equals("e")) { - tn2.safeDelete(); - } else if (tn2.getName().equals("c")) { - tn2.safeDelete(); - } - } - } else if (c == 'e') { - fail("All e nodes must have been deleted by visiting the d node"); - } - } - } - assertEquals("dddd", toString(graph.getNodes(TestNode.class))); - } - - @Test - public void addingNodeDuringIterationTest() { - Graph graph = new Graph(); - graph.add(new TestNode("a")); - StringBuilder sb = new StringBuilder(); - int z = 0; - for (TestNode tn : graph.getNodes(TestNode.class)) { - if (z == 0) { - graph.add(new TestNode("b")); - } - sb.append(tn.getName()); - z++; - } - assertEquals(2, z); - assertEquals("ab", sb.toString()); - z = 0; - for (TestNode tn : graph.getNodes(TestNode.class)) { - if (z == 0) { - graph.add(new TestNode("c")); - } - assertNotNull(tn); - z++; - } - assertEquals(3, z); - } - - public static String toString(Iterable nodes) { - StringBuilder sb = new StringBuilder(); - for (TestNodeInterface tn : nodes) { - sb.append(tn.getName()); - } - return sb.toString(); - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/TypedNodeIteratorTest2.java --- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/TypedNodeIteratorTest2.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +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. - */ -package com.oracle.graal.graph; - -import static org.junit.Assert.*; - -import org.junit.*; - -public class TypedNodeIteratorTest2 { - - private static class NodeA extends Node implements TestNodeInterface { - - private final String name; - - public NodeA(String name) { - this.name = name; - } - - public String getName() { - return name; - } - } - - private static class NodeB extends NodeA implements Node.IterableNodeType { - - public NodeB(String name) { - super(name); - } - } - - private static class NodeC extends NodeB { - - public NodeC(String name) { - super(name); - } - } - - private static class NodeD extends NodeC { - - public NodeD(String name) { - super(name); - } - } - - @Test - public void simpleSubclassTest() { - Graph graph = new Graph(); - graph.add(new NodeB("b")); - graph.add(new NodeD("d")); - - Assert.assertEquals("bd", TypedNodeIteratorTest.toString(graph.getNodes(NodeB.class))); - Assert.assertEquals("d", TypedNodeIteratorTest.toString(graph.getNodes(NodeD.class))); - } - - @Test - public void addingNodeDuringIterationTest() { - Graph graph = new Graph(); - graph.add(new NodeB("b1")); - NodeD d1 = graph.add(new NodeD("d1")); - StringBuilder sb = new StringBuilder(); - for (NodeB tn : graph.getNodes(NodeB.class)) { - if (tn == d1) { - graph.add(new NodeB("b2")); - } - sb.append(tn.getName()); - } - assertEquals("b1d1b2", sb.toString()); - for (NodeB tn : graph.getNodes(NodeB.class)) { - if (tn == d1) { - graph.add(new NodeB("b3")); - } - assertNotNull(tn); - } - assertEquals(4, graph.getNodes(NodeB.class).count()); - assertEquals(1, graph.getNodes(NodeD.class).count()); - } - -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TestNodeInterface.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TestNodeInterface.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 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. + */ +package com.oracle.graal.graph.test; + +public interface TestNodeInterface { + + String getName(); +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,168 @@ +/* + * Copyright (c) 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. + */ +package com.oracle.graal.graph.test; + +import static org.junit.Assert.*; + +import java.util.*; + +import org.junit.*; + +import com.oracle.graal.graph.*; + +public class TypedNodeIteratorTest { + + private static class TestNode extends Node implements Node.IterableNodeType, TestNodeInterface { + + private final String name; + + public TestNode(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } + + @Test + public void singleNodeTest() { + Graph graph = new Graph(); + graph.add(new TestNode("a")); + assertTrue(graph.hasNode(TestNode.class)); + assertEquals("a", toString(graph.getNodes(TestNode.class))); + } + + @Test + public void deletingNodeTest() { + TestNode testNode = new TestNode("a"); + Graph graph = new Graph(); + graph.add(testNode); + testNode.safeDelete(); + assertEquals("", toString(graph.getNodes(TestNode.class))); + } + + @Test + public void deleteAndAddTest() { + TestNode testNode = new TestNode("b"); + Graph graph = new Graph(); + graph.add(new TestNode("a")); + graph.add(testNode); + testNode.safeDelete(); + assertEquals("a", toString(graph.getNodes(TestNode.class))); + graph.add(new TestNode("c")); + assertEquals("ac", toString(graph.getNodes(TestNode.class))); + } + + @Test + public void iteratorBehaviorTest() { + Graph graph = new Graph(); + graph.add(new TestNode("a")); + Iterator iterator = graph.getNodes(TestNode.class).iterator(); + assertTrue(iterator.hasNext()); + assertEquals("a", iterator.next().getName()); + assertFalse(iterator.hasNext()); + graph.add(new TestNode("b")); + assertTrue(iterator.hasNext()); + assertEquals("b", iterator.next().getName()); + assertFalse(iterator.hasNext()); + TestNode c = new TestNode("c"); + graph.add(c); + assertTrue(iterator.hasNext()); + c.safeDelete(); + assertFalse(iterator.hasNext()); + } + + @Test + public void complicatedIterationTest() { + Graph graph = new Graph(); + graph.add(new TestNode("a")); + for (TestNode tn : graph.getNodes(TestNode.class)) { + String name = tn.getName(); + for (int i = 0; i < name.length(); ++i) { + char c = name.charAt(i); + if (c == 'a') { + tn.safeDelete(); + graph.add(new TestNode("b")); + graph.add(new TestNode("c")); + } else if (c == 'b') { + tn.safeDelete(); + } else if (c == 'c') { + graph.add(new TestNode("d")); + graph.add(new TestNode("e")); + graph.add(new TestNode("d")); + graph.add(new TestNode("e")); + graph.add(new TestNode("e")); + graph.add(new TestNode("d")); + graph.add(new TestNode("e")); + graph.add(new TestNode("d")); + } else if (c == 'd') { + for (TestNode tn2 : graph.getNodes(TestNode.class)) { + if (tn2.getName().equals("e")) { + tn2.safeDelete(); + } else if (tn2.getName().equals("c")) { + tn2.safeDelete(); + } + } + } else if (c == 'e') { + fail("All e nodes must have been deleted by visiting the d node"); + } + } + } + assertEquals("dddd", toString(graph.getNodes(TestNode.class))); + } + + @Test + public void addingNodeDuringIterationTest() { + Graph graph = new Graph(); + graph.add(new TestNode("a")); + StringBuilder sb = new StringBuilder(); + int z = 0; + for (TestNode tn : graph.getNodes(TestNode.class)) { + if (z == 0) { + graph.add(new TestNode("b")); + } + sb.append(tn.getName()); + z++; + } + assertEquals(2, z); + assertEquals("ab", sb.toString()); + z = 0; + for (TestNode tn : graph.getNodes(TestNode.class)) { + if (z == 0) { + graph.add(new TestNode("c")); + } + assertNotNull(tn); + z++; + } + assertEquals(3, z); + } + + public static String toString(Iterable nodes) { + StringBuilder sb = new StringBuilder(); + for (TestNodeInterface tn : nodes) { + sb.append(tn.getName()); + } + return sb.toString(); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest2.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,100 @@ +/* + * 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.graal.graph.test; + +import static org.junit.Assert.*; + +import org.junit.*; + +import com.oracle.graal.graph.*; + +public class TypedNodeIteratorTest2 { + + private static class NodeA extends Node implements TestNodeInterface { + + private final String name; + + public NodeA(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } + + private static class NodeB extends NodeA implements Node.IterableNodeType { + + public NodeB(String name) { + super(name); + } + } + + private static class NodeC extends NodeB { + + public NodeC(String name) { + super(name); + } + } + + private static class NodeD extends NodeC { + + public NodeD(String name) { + super(name); + } + } + + @Test + public void simpleSubclassTest() { + Graph graph = new Graph(); + graph.add(new NodeB("b")); + graph.add(new NodeD("d")); + + Assert.assertEquals("bd", TypedNodeIteratorTest.toString(graph.getNodes(NodeB.class))); + Assert.assertEquals("d", TypedNodeIteratorTest.toString(graph.getNodes(NodeD.class))); + } + + @Test + public void addingNodeDuringIterationTest() { + Graph graph = new Graph(); + graph.add(new NodeB("b1")); + NodeD d1 = graph.add(new NodeD("d1")); + StringBuilder sb = new StringBuilder(); + for (NodeB tn : graph.getNodes(NodeB.class)) { + if (tn == d1) { + graph.add(new NodeB("b2")); + } + sb.append(tn.getName()); + } + assertEquals("b1d1b2", sb.toString()); + for (NodeB tn : graph.getNodes(NodeB.class)) { + if (tn == d1) { + graph.add(new NodeB("b3")); + } + assertNotNull(tn); + } + assertEquals(4, graph.getNodes(NodeB.class).count()); + assertEquals(1, graph.getNodes(NodeD.class).count()); + } + +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.graph/.checkstyle_checks.xml --- a/graal/com.oracle.graal.graph/.checkstyle_checks.xml Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.graph/.checkstyle_checks.xml Mon Apr 15 08:51:19 2013 +0200 @@ -1,15 +1,15 @@ - - - + @@ -197,4 +197,14 @@ + + + + + + + + + + diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraphEvent.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraphEvent.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraphEvent.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.graph; +import java.io.*; + public abstract class GraphEvent { private Exception exceptionContext; @@ -43,9 +45,9 @@ } @Override - public StackTraceElement[] print(StackTraceElement[] last) { - System.out.println(type.toString() + ", " + nodeString); - return super.print(last); + public StackTraceElement[] print(StackTraceElement[] last, PrintStream stream) { + stream.println(type.toString() + ", " + nodeString); + return super.print(last, stream); } } @@ -72,7 +74,7 @@ exceptionContext = new Exception(); } - public StackTraceElement[] print(StackTraceElement[] last) { + public StackTraceElement[] print(StackTraceElement[] last, PrintStream stream) { StackTraceElement[] stackTrace = exceptionContext.getStackTrace(); boolean atTop = true; @@ -90,7 +92,7 @@ continue; } } - System.out.println(String.format("%s.%s(%s:%d)", elem.getClassName(), elem.getMethodName(), elem.getFileName(), elem.getLineNumber())); + stream.println(String.format("%s.%s(%s:%d)", elem.getClassName(), elem.getMethodName(), elem.getFileName(), elem.getLineNumber())); } return stackTrace; } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraphEventLog.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraphEventLog.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraphEventLog.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.graph; +import java.io.*; import java.util.*; public class GraphEventLog { @@ -32,10 +33,10 @@ this.events.add(e); } - public void printEvents() { + public void printEvents(PrintStream stream) { StackTraceElement[] last = new StackTraceElement[0]; for (GraphEvent e : events) { - last = e.print(last); + last = e.print(last, stream); } } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Mon Apr 15 08:51:19 2013 +0200 @@ -33,7 +33,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; -import com.oracle.graal.asm.amd64.AMD64Address.*; +import com.oracle.graal.asm.amd64.AMD64Address.Scale; import com.oracle.graal.compiler.amd64.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.graph.*; @@ -42,13 +42,13 @@ import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; -import com.oracle.graal.lir.StandardOp.*; +import com.oracle.graal.lir.StandardOp.ParametersOp; import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.amd64.AMD64Move.*; +import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp; +import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; /** * LIR generator specialized for AMD64 HotSpot. @@ -161,20 +161,10 @@ @Override public void visitSafepointNode(SafepointNode i) { - LIRFrameState info = state(); + LIRFrameState info = state(i); append(new AMD64SafepointOp(info, runtime().config, this)); } - @Override - public void visitExceptionObject(ExceptionObjectNode x) { - HotSpotVMConfig config = runtime().config; - RegisterValue thread = runtime().threadRegister().asValue(); - Value exception = emitLoad(Kind.Object, thread, config.threadExceptionOopOffset, Value.ILLEGAL, 0, false); - emitStore(Kind.Object, thread, config.threadExceptionOopOffset, Value.ILLEGAL, 0, Constant.NULL_OBJECT, false); - emitStore(Kind.Long, thread, config.threadExceptionPcOffset, Value.ILLEGAL, 0, Constant.LONG_0, false); - setResult(x, exception); - } - @SuppressWarnings("hiding") @Override public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) { @@ -242,8 +232,8 @@ } @Override - public void emitDeoptimize(DeoptimizationAction action, DeoptimizationReason reason) { - append(new AMD64DeoptimizeOp(action, reason, state())); + public void emitDeoptimize(DeoptimizationAction action, DeoptimizingNode deopting) { + append(new AMD64DeoptimizeOp(action, deopting.getDeoptimizationReason(), state(deopting))); } @Override diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java Mon Apr 15 08:51:19 2013 +0200 @@ -37,23 +37,22 @@ import static com.oracle.graal.hotspot.nodes.ThreadIsInterruptedStubCall.*; import static com.oracle.graal.hotspot.nodes.VMErrorNode.*; import static com.oracle.graal.hotspot.nodes.VerifyOopStubCall.*; +import static com.oracle.graal.hotspot.nodes.WriteBarrierPostStubCall.*; +import static com.oracle.graal.hotspot.nodes.WriteBarrierPreStubCall.*; import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.DecryptBlockStubCall.*; import static com.oracle.graal.hotspot.replacements.AESCryptSubstitutions.EncryptBlockStubCall.*; import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.DecryptAESCryptStubCall.*; import static com.oracle.graal.hotspot.replacements.CipherBlockChainingSubstitutions.EncryptAESCryptStubCall.*; -import static com.oracle.graal.hotspot.nodes.WriteBarrierPostStubCall.*; -import static com.oracle.graal.hotspot.nodes.WriteBarrierPreStubCall.*; +import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.amd64.*; -import com.oracle.graal.replacements.*; public class AMD64HotSpotRuntime extends HotSpotRuntime { @@ -73,13 +72,13 @@ /* ret */ ret(Kind.Void)); addRuntimeCall(ARITHMETIC_FREM, config.arithmeticFremStub, - /* temps */ null, + /* temps */ new Register[]{AMD64.rax}, /* ret */ ret(Kind.Float), /* arg0: a */ javaCallingConvention(Kind.Float, /* arg1: b */ Kind.Float)); addRuntimeCall(ARITHMETIC_DREM, config.arithmeticDremStub, - /* temps */ null, + /* temps */ new Register[]{AMD64.rax}, /* ret */ ret(Kind.Double), /* arg0: a */ javaCallingConvention(Kind.Double, /* arg1: b */ Kind.Double)); @@ -208,10 +207,9 @@ private AMD64ConvertSnippets.Templates convertSnippets; @Override - public void installReplacements(Backend backend, ReplacementsInstaller installer, Assumptions assumptions) { - installer.installSnippets(AMD64ConvertSnippets.class); - convertSnippets = new AMD64ConvertSnippets.Templates(this, assumptions, graalRuntime.getTarget()); - super.installReplacements(backend, installer, assumptions); + public void registerReplacements(Replacements replacements) { + convertSnippets = new AMD64ConvertSnippets.Templates(this, replacements, graalRuntime.getTarget()); + super.registerReplacements(replacements); } @Override diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64IndirectCallOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64IndirectCallOp.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64IndirectCallOp.java Mon Apr 15 08:51:19 2013 +0200 @@ -52,7 +52,7 @@ @Use({REG}) protected Value metaspaceMethod; - AMD64IndirectCallOp(InvokeTarget targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state) { + AMD64IndirectCallOp(ResolvedJavaMethod targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state) { super(targetMethod, result, parameters, temps, targetAddress, state); this.metaspaceMethod = metaspaceMethod; } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64SafepointOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64SafepointOp.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64SafepointOp.java Mon Apr 15 08:51:19 2013 +0200 @@ -63,11 +63,11 @@ if (config.isPollingPageFar) { asm.movq(scratch.getRegister(), config.safepointPollingAddress + offset); tasm.recordMark(Marks.MARK_POLL_FAR); - tasm.recordSafepoint(pos, state); + tasm.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); asm.movq(scratch.getRegister(), new AMD64Address(scratch.getRegister())); } else { tasm.recordMark(Marks.MARK_POLL_NEAR); - tasm.recordSafepoint(pos, state); + tasm.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); // The C++ code transforms the polling page offset into an RIP displacement // to the real address at that offset in the polling page. asm.movq(scratch.getRegister(), new AMD64Address(rip, offset)); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/InvocationSocket.java --- a/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/InvocationSocket.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/InvocationSocket.java Mon Apr 15 08:51:19 2013 +0200 @@ -38,6 +38,7 @@ */ public class InvocationSocket { + // CheckStyle: stop system..print check private static final boolean DEBUG = false; private static final boolean COUNT_CALLS = false; @@ -279,4 +280,5 @@ output.writeObject(new Result(obj)); output.flush(); } + // CheckStyle: resume system..print check } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/ArrayCopyIntrinsificationTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/ArrayCopyIntrinsificationTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,238 +0,0 @@ -/* - * Copyright (c) 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. - */ -package com.oracle.graal.hotspot; - -import static org.junit.Assert.*; - -import java.lang.reflect.*; -import java.util.*; - -import org.junit.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; - -/** - * Tests intrinsification of {@link System#arraycopy(Object, int, Object, int, int)}. - */ -public class ArrayCopyIntrinsificationTest extends GraalCompilerTest { - - @Override - protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph) { - int nodeCount = graph.getNodeCount(); - InstalledCode result = super.getCode(method, graph); - boolean graphWasProcessed = nodeCount != graph.getNodeCount(); - if (graphWasProcessed) { - if (mustIntrinsify) { - for (Node node : graph.getNodes()) { - if (node instanceof Invoke) { - Invoke invoke = (Invoke) node; - Assert.assertTrue(invoke.callTarget() instanceof DirectCallTargetNode); - AbstractCallTargetNode directCall = (AbstractCallTargetNode) invoke.callTarget(); - JavaMethod callee = directCall.target(); - Assert.assertTrue(callee.getName().equals("")); - Assert.assertTrue(runtime.lookupJavaType(ArrayIndexOutOfBoundsException.class).equals(callee.getDeclaringClass()) || - runtime.lookupJavaType(NullPointerException.class).equals(callee.getDeclaringClass())); - } - } - } else { - boolean found = false; - for (Node node : graph.getNodes()) { - if (node instanceof Invoke) { - Invoke invoke = (Invoke) node; - AbstractCallTargetNode directCall = (AbstractCallTargetNode) invoke.callTarget(); - JavaMethod callee = directCall.target(); - if (callee.getDeclaringClass().equals(runtime.lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) { - found = true; - } else { - fail("found invoke to some method other than arraycopy: " + callee); - } - } - } - Assert.assertTrue("did not find invoke to arraycopy", found); - } - } - return result; - } - - boolean mustIntrinsify = true; - - @Test - public void test0() { - mustIntrinsify = false; // a generic call to arraycopy will not be intrinsified - // Array store checks - test("genericArraycopy", new Object(), 0, new Object[0], 0, 0); - test("genericArraycopy", new Object[0], 0, new Object(), 0, 0); - - mustIntrinsify = true; - } - - @Test - public void test1() { - String name = "intArraycopy"; - int[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; - // Null checks - test(name, null, 0, src, 0, 0); - test(name, src, 0, null, 0, 0); - // Bounds checks - test(name, src, 0, src, 0, -1); - test(name, src, 0, src, 0, src.length + 1); - } - - @Test - public void testByte() { - byte[] src = {-1, 0, 1, 2, 3, 4}; - testHelper("byteArraycopy", src); - } - - @Test - public void testChar() { - char[] src = "some string of chars".toCharArray(); - testHelper("charArraycopy", src); - } - - @Test - public void testShort() { - short[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; - testHelper("shortArraycopy", src); - } - - @Test - public void testInt() { - int[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; - testHelper("intArraycopy", src); - } - - @Test - public void testFloat() { - float[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; - testHelper("floatArraycopy", src); - } - - @Test - public void testLong() { - long[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; - testHelper("longArraycopy", src); - } - - @Test - public void testDouble() { - double[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; - testHelper("doubleArraycopy", src); - } - - @Test - public void testObject() { - mustIntrinsify = false; // a generic call to arraycopy will not be intrinsified - - Object[] src = {"one", "two", "three", new ArrayList<>(), new HashMap<>()}; - testHelper("objectArraycopy", src); - - mustIntrinsify = true; - } - - @Test - public void testObjectExact() { - Integer[] src = {1, 2, 3, 4}; - testHelper("objectArraycopyExact", src); - } - - private static Object newArray(Object proto, int length) { - assert proto != null; - assert proto.getClass().isArray(); - return Array.newInstance(proto.getClass().getComponentType(), length); - } - - private void testHelper(String name, Object src) { - int srcLength = Array.getLength(src); - - // Complete array copy - test(name, src, 0, newArray(src, srcLength), 0, srcLength); - - for (int length : new int[]{0, 1, srcLength - 1, srcLength}) { - // Partial array copying - test(name, src, 0, newArray(src, length), 0, length); - test(name, src, srcLength - length, newArray(src, length), 0, length); - test(name, src, 0, newArray(src, srcLength), 0, length); - } - } - - public static Object genericArraycopy(Object src, int srcPos, Object dst, int dstPos, int length) { - System.arraycopy(src, srcPos, dst, dstPos, length); - return dst; - } - - public static Object[] objectArraycopy(Object[] src, int srcPos, Object[] dst, int dstPos, int length) { - System.arraycopy(src, srcPos, dst, dstPos, length); - return dst; - } - - public static Object[] objectArraycopyExact(Integer[] src, int srcPos, Integer[] dst, int dstPos, int length) { - System.arraycopy(src, srcPos, dst, dstPos, length); - return dst; - } - - public static boolean[] booleanArraycopy(boolean[] src, int srcPos, boolean[] dst, int dstPos, int length) { - System.arraycopy(src, srcPos, dst, dstPos, length); - return dst; - } - - public static byte[] byteArraycopy(byte[] src, int srcPos, byte[] dst, int dstPos, int length) { - System.arraycopy(src, srcPos, dst, dstPos, length); - return dst; - } - - public static char[] charArraycopy(char[] src, int srcPos, char[] dst, int dstPos, int length) { - System.arraycopy(src, srcPos, dst, dstPos, length); - return dst; - } - - public static short[] shortArraycopy(short[] src, int srcPos, short[] dst, int dstPos, int length) { - System.arraycopy(src, srcPos, dst, dstPos, length); - return dst; - } - - public static int[] intArraycopy(int[] src, int srcPos, int[] dst, int dstPos, int length) { - System.arraycopy(src, srcPos, dst, dstPos, length); - return dst; - } - - public static float[] floatArraycopy(float[] src, int srcPos, float[] dst, int dstPos, int length) { - System.arraycopy(src, srcPos, dst, dstPos, length); - return dst; - } - - public static long[] longArraycopy(long[] src, int srcPos, long[] dst, int dstPos, int length) { - System.arraycopy(src, srcPos, dst, dstPos, length); - return dst; - } - - public static double[] doubleArraycopy(double[] src, int srcPos, double[] dst, int dstPos, int length) { - System.arraycopy(src, srcPos, dst, dstPos, length); - return dst; - } - -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/HotSpotMethodSubstitutionTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/HotSpotMethodSubstitutionTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,165 +0,0 @@ -/* - * 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. - */ -package com.oracle.graal.hotspot; - -import org.junit.*; - -import com.oracle.graal.api.replacements.*; -import com.oracle.graal.hotspot.replacements.*; -import com.oracle.graal.replacements.*; - -/** - * Tests HotSpot specific {@link MethodSubstitution}s. - */ -public class HotSpotMethodSubstitutionTest extends MethodSubstitutionTest { - - @Test - public void testObjectSubstitutions() { - test("getClass_"); - test("objectHashCode"); - - Object obj = new Object(); - - assertEquals("a string".getClass(), ObjectSubstitutions.getClass("a string")); - assertEquals(obj.hashCode(), ObjectSubstitutions.hashCode(obj)); - } - - @SuppressWarnings("all") - public static boolean getClass_(Object obj, Class clazz) { - return obj.getClass() == clazz; - } - - @SuppressWarnings("all") - public static int objectHashCode(TestClassA obj) { - return obj.hashCode(); - } - - @Test - public void testClassSubstitutions() { - test("getModifiers"); - test("isInstance"); - test("isInterface"); - test("isArray"); - test("isPrimitive"); - test("getSuperClass"); - test("getComponentType"); - - for (Class c : new Class[]{getClass(), Cloneable.class, int[].class, String[][].class}) { - assertEquals(c.getModifiers(), ClassSubstitutions.getModifiers(c)); - assertEquals(c.isInterface(), ClassSubstitutions.isInterface(c)); - assertEquals(c.isArray(), ClassSubstitutions.isArray(c)); - assertEquals(c.isPrimitive(), ClassSubstitutions.isPrimitive(c)); - assertEquals(c.getSuperclass(), ClassSubstitutions.getSuperclass(c)); - assertEquals(c.getComponentType(), ClassSubstitutions.getComponentType(c)); - for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) { - assertEquals(c.isInstance(o), ClassSubstitutions.isInstance(c, o)); - } - } - } - - @SuppressWarnings("all") - public static int getModifiers(Class clazz) { - return clazz.getModifiers(); - } - - @SuppressWarnings("all") - public static boolean isInstance(Class clazz) { - return clazz.isInstance(Number.class); - } - - @SuppressWarnings("all") - public static boolean isInterface(Class clazz) { - return clazz.isInterface(); - } - - @SuppressWarnings("all") - public static boolean isArray(Class clazz) { - return clazz.isArray(); - } - - @SuppressWarnings("all") - public static boolean isPrimitive(Class clazz) { - return clazz.isPrimitive(); - } - - @SuppressWarnings("all") - public static Class getSuperClass(Class clazz) { - return clazz.getSuperclass(); - } - - @SuppressWarnings("all") - public static Class getComponentType(Class clazz) { - return clazz.getComponentType(); - } - - @Test - public void testThreadSubstitutions() { - test("currentThread"); - test("threadIsInterrupted"); - test("threadInterrupted"); - - Thread currentThread = Thread.currentThread(); - assertEquals(currentThread, ThreadSubstitutions.currentThread()); - assertEquals(currentThread.isInterrupted(), ThreadSubstitutions.isInterrupted(currentThread, false)); - } - - @SuppressWarnings("all") - public static Thread currentThread() { - return Thread.currentThread(); - } - - @SuppressWarnings("all") - public static boolean threadIsInterrupted(Thread thread) { - return thread.isInterrupted(); - } - - @SuppressWarnings("all") - public static boolean threadInterrupted() { - return Thread.interrupted(); - } - - @Test - public void testSystemSubstitutions() { - test("systemTime"); - test("systemIdentityHashCode"); - - SystemSubstitutions.currentTimeMillis(); - SystemSubstitutions.nanoTime(); - for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) { - assertEquals(System.identityHashCode(o), SystemSubstitutions.identityHashCode(o)); - } - } - - @SuppressWarnings("all") - public static long systemTime() { - return System.currentTimeMillis() + System.nanoTime(); - } - - @SuppressWarnings("all") - public static int systemIdentityHashCode(Object obj) { - return System.identityHashCode(obj); - } - - private static class TestClassA { - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/InstalledCodeExecuteHelperTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/InstalledCodeExecuteHelperTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2012, 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. - */ -package com.oracle.graal.hotspot; - -import java.lang.reflect.*; - -import org.junit.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.runtime.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.nodes.spi.*; - -public class InstalledCodeExecuteHelperTest extends GraalCompilerTest { - - private static final int ITERATIONS = 100000000; - - @Ignore - @Test - public void test1() throws NoSuchMethodException, SecurityException { - - final Method benchrMethod = InstalledCodeExecuteHelperTest.class.getMethod("bench", long.class, long.class); - final ResolvedJavaMethod benchJavaMethod = Graal.getRequiredCapability(GraalCodeCacheProvider.class).lookupJavaMethod(benchrMethod); - HotSpotInstalledCode benchCode = (HotSpotInstalledCode) getCode(benchJavaMethod, parse(benchrMethod)); - - final Method wrapperMethod = InstalledCodeExecuteHelperTest.class.getMethod("executeWrapper", long.class, long.class, Object.class, Object.class, Object.class); - final ResolvedJavaMethod wrapperJavaMethod = Graal.getRequiredCapability(GraalCodeCacheProvider.class).lookupJavaMethod(wrapperMethod); - HotSpotInstalledCode wrapperCode = (HotSpotInstalledCode) getCode(wrapperJavaMethod, parse(wrapperMethod)); - - final Method fooMethod = InstalledCodeExecuteHelperTest.class.getMethod("foo", Object.class, Object.class, Object.class); - final HotSpotResolvedJavaMethod fooJavaMethod = (HotSpotResolvedJavaMethod) Graal.getRequiredCapability(GraalCodeCacheProvider.class).lookupJavaMethod(fooMethod); - HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooJavaMethod, parse(fooMethod)); - - System.out.println(wrapperCode.executeVarargs(fooCode.getnmethod(), fooJavaMethod.getMetaspaceMethod(), null, null, null)); - - long nmethod = fooCode.getnmethod(); - long metaspacemethod = fooJavaMethod.getMetaspaceMethod(); - - System.out.println("Without replaced InstalledCode.execute:" + bench(nmethod, metaspacemethod)); - - System.out.println("WITH replaced InstalledCode.execute:" + benchCode.executeVarargs(nmethod, metaspacemethod)); - - } - - public static Long bench(long nmethod, long metaspacemethod) { - long start = System.currentTimeMillis(); - - for (int i = 0; i < ITERATIONS; i++) { - HotSpotInstalledCode.executeHelper(nmethod, metaspacemethod, null, null, null); - } - - long end = System.currentTimeMillis(); - return (end - start); - } - - public static Object foo(@SuppressWarnings("unused") Object a1, @SuppressWarnings("unused") Object a2, @SuppressWarnings("unused") Object a3) { - return 42; - } - - public static Object executeWrapper(long nmethod, long metaspaceMethod, Object arg1, Object arg2, Object arg3) { - return HotSpotInstalledCode.executeHelper(nmethod, metaspaceMethod, arg1, arg2, arg3); - } - -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ArrayCopyIntrinsificationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ArrayCopyIntrinsificationTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,238 @@ +/* + * Copyright (c) 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. + */ +package com.oracle.graal.hotspot.test; + +import static org.junit.Assert.*; + +import java.lang.reflect.*; +import java.util.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; + +/** + * Tests intrinsification of {@link System#arraycopy(Object, int, Object, int, int)}. + */ +public class ArrayCopyIntrinsificationTest extends GraalCompilerTest { + + @Override + protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph) { + int nodeCount = graph.getNodeCount(); + InstalledCode result = super.getCode(method, graph); + boolean graphWasProcessed = nodeCount != graph.getNodeCount(); + if (graphWasProcessed) { + if (mustIntrinsify) { + for (Node node : graph.getNodes()) { + if (node instanceof Invoke) { + Invoke invoke = (Invoke) node; + Assert.assertTrue(invoke.callTarget() instanceof DirectCallTargetNode); + AbstractCallTargetNode directCall = (AbstractCallTargetNode) invoke.callTarget(); + JavaMethod callee = directCall.target(); + Assert.assertTrue(callee.getName().equals("")); + Assert.assertTrue(runtime.lookupJavaType(ArrayIndexOutOfBoundsException.class).equals(callee.getDeclaringClass()) || + runtime.lookupJavaType(NullPointerException.class).equals(callee.getDeclaringClass())); + } + } + } else { + boolean found = false; + for (Node node : graph.getNodes()) { + if (node instanceof Invoke) { + Invoke invoke = (Invoke) node; + AbstractCallTargetNode directCall = (AbstractCallTargetNode) invoke.callTarget(); + JavaMethod callee = directCall.target(); + if (callee.getDeclaringClass().equals(runtime.lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) { + found = true; + } else { + fail("found invoke to some method other than arraycopy: " + callee); + } + } + } + Assert.assertTrue("did not find invoke to arraycopy", found); + } + } + return result; + } + + boolean mustIntrinsify = true; + + @Test + public void test0() { + mustIntrinsify = false; // a generic call to arraycopy will not be intrinsified + // Array store checks + test("genericArraycopy", new Object(), 0, new Object[0], 0, 0); + test("genericArraycopy", new Object[0], 0, new Object(), 0, 0); + + mustIntrinsify = true; + } + + @Test + public void test1() { + String name = "intArraycopy"; + int[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + // Null checks + test(name, null, 0, src, 0, 0); + test(name, src, 0, null, 0, 0); + // Bounds checks + test(name, src, 0, src, 0, -1); + test(name, src, 0, src, 0, src.length + 1); + } + + @Test + public void testByte() { + byte[] src = {-1, 0, 1, 2, 3, 4}; + testHelper("byteArraycopy", src); + } + + @Test + public void testChar() { + char[] src = "some string of chars".toCharArray(); + testHelper("charArraycopy", src); + } + + @Test + public void testShort() { + short[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + testHelper("shortArraycopy", src); + } + + @Test + public void testInt() { + int[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + testHelper("intArraycopy", src); + } + + @Test + public void testFloat() { + float[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + testHelper("floatArraycopy", src); + } + + @Test + public void testLong() { + long[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + testHelper("longArraycopy", src); + } + + @Test + public void testDouble() { + double[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + testHelper("doubleArraycopy", src); + } + + @Test + public void testObject() { + mustIntrinsify = false; // a generic call to arraycopy will not be intrinsified + + Object[] src = {"one", "two", "three", new ArrayList<>(), new HashMap<>()}; + testHelper("objectArraycopy", src); + + mustIntrinsify = true; + } + + @Test + public void testObjectExact() { + Integer[] src = {1, 2, 3, 4}; + testHelper("objectArraycopyExact", src); + } + + private static Object newArray(Object proto, int length) { + assert proto != null; + assert proto.getClass().isArray(); + return Array.newInstance(proto.getClass().getComponentType(), length); + } + + private void testHelper(String name, Object src) { + int srcLength = Array.getLength(src); + + // Complete array copy + test(name, src, 0, newArray(src, srcLength), 0, srcLength); + + for (int length : new int[]{0, 1, srcLength - 1, srcLength}) { + // Partial array copying + test(name, src, 0, newArray(src, length), 0, length); + test(name, src, srcLength - length, newArray(src, length), 0, length); + test(name, src, 0, newArray(src, srcLength), 0, length); + } + } + + public static Object genericArraycopy(Object src, int srcPos, Object dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static Object[] objectArraycopy(Object[] src, int srcPos, Object[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static Object[] objectArraycopyExact(Integer[] src, int srcPos, Integer[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static boolean[] booleanArraycopy(boolean[] src, int srcPos, boolean[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static byte[] byteArraycopy(byte[] src, int srcPos, byte[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static char[] charArraycopy(char[] src, int srcPos, char[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static short[] shortArraycopy(short[] src, int srcPos, short[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static int[] intArraycopy(int[] src, int srcPos, int[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static float[] floatArraycopy(float[] src, int srcPos, float[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static long[] longArraycopy(long[] src, int srcPos, long[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static double[] doubleArraycopy(double[] src, int srcPos, double[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,42 @@ +/* + * 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.graal.hotspot.test; + +import org.junit.*; + +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.hotspot.*; + +/** + * Tests {@link CompileTheWorld} functionality. + */ +public class CompileTheWorldTest extends GraalCompilerTest { + + @Test + public void testRtJar() throws Throwable { + // Compile a couple classes in rt.jar + String file = System.getProperty("java.home") + "/lib/rt.jar"; + new CompileTheWorld(file, 1, 5).compile(); + } + +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotInstalledCodeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotInstalledCodeTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2013, 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.graal.hotspot.test; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.nodes.*; + +public class HotSpotInstalledCodeTest extends GraalCompilerTest { + + private static final int ITERATION_COUNT = 100000; + + @Test + public void testInstallCodeInvalidation() { + final ResolvedJavaMethod testJavaMethod = runtime.lookupJavaMethod(getMethod("foo")); + final StructuredGraph graph = parse("otherFoo"); + final HotSpotInstalledCode installedCode = (HotSpotInstalledCode) getCode(testJavaMethod, graph); + Assert.assertTrue(installedCode.isValid()); + Object result; + try { + result = installedCode.execute("a", "b", "c"); + assertEquals(43, result); + } catch (InvalidInstalledCodeException e) { + Assert.fail("Code was invalidated"); + } + Assert.assertTrue(installedCode.isValid()); + installedCode.invalidate(); + Assert.assertFalse(installedCode.isValid()); + try { + result = installedCode.execute(null, null, null); + Assert.fail("Code was not invalidated"); + } catch (InvalidInstalledCodeException e) { + } + Assert.assertFalse(installedCode.isValid()); + } + + @Test + public void testInstalledCodeCalledFromCompiledCode() { + final ResolvedJavaMethod testJavaMethod = runtime.lookupJavaMethod(getMethod("foo")); + final StructuredGraph graph = parse("otherFoo"); + final HotSpotInstalledCode installedCode = (HotSpotInstalledCode) getCode(testJavaMethod, graph); + Assert.assertTrue(installedCode.isValid()); + try { + for (int i = 0; i < ITERATION_COUNT; ++i) { + installedCode.execute("a", "b", "c"); + } + } catch (InvalidInstalledCodeException e) { + Assert.fail("Code was invalidated"); + } + } + + @SuppressWarnings("unused") + public static Object foo(Object a1, Object a2, Object a3) { + return 42; + } + + @SuppressWarnings("unused") + public static Object otherFoo(Object a1, Object a2, Object a3) { + return 43; + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotMethodSubstitutionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotMethodSubstitutionTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,165 @@ +/* + * 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. + */ +package com.oracle.graal.hotspot.test; + +import org.junit.*; + +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.hotspot.replacements.*; +import com.oracle.graal.replacements.test.*; + +/** + * Tests HotSpot specific {@link MethodSubstitution}s. + */ +public class HotSpotMethodSubstitutionTest extends MethodSubstitutionTest { + + @Test + public void testObjectSubstitutions() { + test("getClass_"); + test("objectHashCode"); + + Object obj = new Object(); + + assertEquals("a string".getClass(), ObjectSubstitutions.getClass("a string")); + assertEquals(obj.hashCode(), ObjectSubstitutions.hashCode(obj)); + } + + @SuppressWarnings("all") + public static boolean getClass_(Object obj, Class clazz) { + return obj.getClass() == clazz; + } + + @SuppressWarnings("all") + public static int objectHashCode(TestClassA obj) { + return obj.hashCode(); + } + + @Test + public void testClassSubstitutions() { + test("getModifiers"); + test("isInstance"); + test("isInterface"); + test("isArray"); + test("isPrimitive"); + test("getSuperClass"); + test("getComponentType"); + + for (Class c : new Class[]{getClass(), Cloneable.class, int[].class, String[][].class}) { + assertEquals(c.getModifiers(), ClassSubstitutions.getModifiers(c)); + assertEquals(c.isInterface(), ClassSubstitutions.isInterface(c)); + assertEquals(c.isArray(), ClassSubstitutions.isArray(c)); + assertEquals(c.isPrimitive(), ClassSubstitutions.isPrimitive(c)); + assertEquals(c.getSuperclass(), ClassSubstitutions.getSuperclass(c)); + assertEquals(c.getComponentType(), ClassSubstitutions.getComponentType(c)); + for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) { + assertEquals(c.isInstance(o), ClassSubstitutions.isInstance(c, o)); + } + } + } + + @SuppressWarnings("all") + public static int getModifiers(Class clazz) { + return clazz.getModifiers(); + } + + @SuppressWarnings("all") + public static boolean isInstance(Class clazz) { + return clazz.isInstance(Number.class); + } + + @SuppressWarnings("all") + public static boolean isInterface(Class clazz) { + return clazz.isInterface(); + } + + @SuppressWarnings("all") + public static boolean isArray(Class clazz) { + return clazz.isArray(); + } + + @SuppressWarnings("all") + public static boolean isPrimitive(Class clazz) { + return clazz.isPrimitive(); + } + + @SuppressWarnings("all") + public static Class getSuperClass(Class clazz) { + return clazz.getSuperclass(); + } + + @SuppressWarnings("all") + public static Class getComponentType(Class clazz) { + return clazz.getComponentType(); + } + + @Test + public void testThreadSubstitutions() { + test("currentThread"); + test("threadIsInterrupted"); + test("threadInterrupted"); + + Thread currentThread = Thread.currentThread(); + assertEquals(currentThread, ThreadSubstitutions.currentThread()); + assertEquals(currentThread.isInterrupted(), ThreadSubstitutions.isInterrupted(currentThread, false)); + } + + @SuppressWarnings("all") + public static Thread currentThread() { + return Thread.currentThread(); + } + + @SuppressWarnings("all") + public static boolean threadIsInterrupted(Thread thread) { + return thread.isInterrupted(); + } + + @SuppressWarnings("all") + public static boolean threadInterrupted() { + return Thread.interrupted(); + } + + @Test + public void testSystemSubstitutions() { + test("systemTime"); + test("systemIdentityHashCode"); + + SystemSubstitutions.currentTimeMillis(); + SystemSubstitutions.nanoTime(); + for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) { + assertEquals(System.identityHashCode(o), SystemSubstitutions.identityHashCode(o)); + } + } + + @SuppressWarnings("all") + public static long systemTime() { + return System.currentTimeMillis() + System.nanoTime(); + } + + @SuppressWarnings("all") + public static int systemIdentityHashCode(Object obj) { + return System.identityHashCode(obj); + } + + private static class TestClassA { + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/InstalledCodeExecuteHelperTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/InstalledCodeExecuteHelperTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2012, 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. + */ +package com.oracle.graal.hotspot.test; + +import static com.oracle.graal.api.meta.MetaUtil.*; +import static java.lang.reflect.Modifier.*; + +import java.lang.reflect.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.nodes.*; + +public class InstalledCodeExecuteHelperTest extends GraalCompilerTest { + + private static final int ITERATIONS = 100000; + private final MetaAccessProvider metaAccessProvider; + Object[] argsToBind; + + public InstalledCodeExecuteHelperTest() { + this.metaAccessProvider = Graal.getRequiredCapability(MetaAccessProvider.class); + } + + @Test + public void test1() throws NoSuchMethodException, SecurityException, InvalidInstalledCodeException { + final Method fooMethod = InstalledCodeExecuteHelperTest.class.getMethod("foo", Object.class, Object.class, Object.class); + final HotSpotResolvedJavaMethod fooJavaMethod = (HotSpotResolvedJavaMethod) metaAccessProvider.lookupJavaMethod(fooMethod); + final HotSpotInstalledCode fooCode = (HotSpotInstalledCode) getCode(fooJavaMethod, parse(fooMethod)); + + argsToBind = new Object[]{fooCode}; + + final Method benchmarkMethod = InstalledCodeExecuteHelperTest.class.getMethod("benchmark", HotSpotInstalledCode.class); + final ResolvedJavaMethod benchmarkJavaMethod = metaAccessProvider.lookupJavaMethod(benchmarkMethod); + final HotSpotInstalledCode installedBenchmarkCode = (HotSpotInstalledCode) getCode(benchmarkJavaMethod, parse(benchmarkMethod)); + + Assert.assertEquals(Integer.valueOf(42), benchmark(fooCode)); + + Assert.assertEquals(Integer.valueOf(42), installedBenchmarkCode.executeVarargs(argsToBind[0])); + + } + + public static Integer benchmark(HotSpotInstalledCode code) throws InvalidInstalledCodeException { + int val = 0; + for (int j = 0; j < 100; j++) { + for (int i = 0; i < ITERATIONS; i++) { + val = (Integer) code.execute(null, null, null); + } + } + return val; + } + + public static Integer foo(@SuppressWarnings("unused") Object a1, @SuppressWarnings("unused") Object a2, @SuppressWarnings("unused") Object a3) { + return 42; + } + + @Override + protected StructuredGraph parse(Method m) { + StructuredGraph graph = super.parse(m); + if (argsToBind != null) { + Object receiver = isStatic(m.getModifiers()) ? null : this; + Object[] args = argsWithReceiver(receiver, argsToBind); + JavaType[] parameterTypes = signatureToTypes(runtime.lookupJavaMethod(m)); + assert parameterTypes.length == args.length; + for (int i = 0; i < argsToBind.length; i++) { + LocalNode local = graph.getLocal(i); + Constant c = Constant.forBoxed(parameterTypes[i].getKind(), argsToBind[i]); + ConstantNode replacement = ConstantNode.forConstant(c, runtime, graph); + local.replaceAtUsages(replacement); + } + } + return graph; + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,20 +22,22 @@ */ package com.oracle.graal.hotspot; +import static com.oracle.graal.nodes.StructuredGraph.*; import static com.oracle.graal.phases.common.InliningUtil.*; +import java.lang.reflect.Modifier; import java.util.concurrent.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.replacements.*; import com.oracle.graal.compiler.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.internal.*; +import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; -import static com.oracle.graal.nodes.StructuredGraph.*; public final class CompilationTask implements Runnable, Comparable { @@ -133,6 +135,9 @@ TTY.println(String.format("%-6d Graal %-70s %-45s %-50s %s...", id, method.getDeclaringClass().getName(), method.getName(), method.getSignature(), entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + entryBCI + ") ")); } + if (GraalOptions.HotSpotPrintCompilation) { + printCompilation(); + } CompilationResult result = null; TTY.Filter filter = new TTY.Filter(GraalOptions.PrintFilter, method); @@ -143,7 +148,8 @@ @Override public CompilationResult call() throws Exception { graalRuntime.evictDeoptedGraphs(); - StructuredGraph graph = (StructuredGraph) method.getCompilerStorage().get(MethodSubstitution.class); + Replacements replacements = graalRuntime.getReplacements(); + StructuredGraph graph = replacements.getMethodSubstitution(method); if (graph == null || entryBCI != INVOCATION_ENTRY_BCI) { graph = new StructuredGraph(method, entryBCI); } else { @@ -151,7 +157,7 @@ graph = graph.copy(); } InlinedBytecodes.add(method.getCodeSize()); - return GraalCompiler.compileMethod(graalRuntime.getRuntime(), graalRuntime.getBackend(), graalRuntime.getTarget(), method, graph, graalRuntime.getCache(), plan, + return GraalCompiler.compileMethod(graalRuntime.getRuntime(), replacements, graalRuntime.getBackend(), graalRuntime.getTarget(), method, graph, graalRuntime.getCache(), plan, optimisticOpts, method.getSpeculationLog()); } }); @@ -162,7 +168,7 @@ } } - installMethod(result); + installMethod(result, null); } catch (BailoutException bailout) { Debug.metric("Bailouts").increment(); if (GraalOptions.ExitVMOnBailout) { @@ -182,12 +188,22 @@ stats.finish(method); } - private void installMethod(final CompilationResult compResult) { + /** + * Print a HotSpot-style compilation message to the console. + */ + private void printCompilation() { + final boolean isOSR = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI; + final int mod = method.getModifiers(); + TTY.println(String.format("%7d %4d %c%c%c%c%c %s %s(%d bytes)", 0, id, isOSR ? '%' : ' ', Modifier.isSynchronized(mod) ? 's' : ' ', ' ', ' ', Modifier.isNative(mod) ? 'n' : ' ', + MetaUtil.format("%H::%n(%p)", method), isOSR ? "@ " + entryBCI + " " : "", method.getCodeSize())); + } + + private void installMethod(final CompilationResult compResult, final Graph graph) { Debug.scope("CodeInstall", new Object[]{new DebugDumpScope(String.valueOf(id), true), graalRuntime.getRuntime(), method}, new Runnable() { @Override public void run() { - HotSpotInstalledCode installedCode = graalRuntime.getRuntime().installMethod(method, entryBCI, compResult); + HotSpotInstalledCode installedCode = graalRuntime.getRuntime().installMethod(method, graph, entryBCI, compResult); if (Debug.isDumpEnabled()) { Debug.dump(new Object[]{compResult, installedCode}, "After code installation"); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,252 @@ +/* + * 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.graal.hotspot; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.*; +import java.util.Enumeration; +import java.util.jar.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.bytecode.Bytecodes; +import com.oracle.graal.debug.*; +import com.oracle.graal.hotspot.bridge.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.replacements.*; + +/** + * This class implements compile-the-world functionality in Graal. + */ +public final class CompileTheWorld { + + /** + * This is our magic token to trigger reading files from the boot class path. + */ + public static final String SUN_BOOT_CLASS_PATH = "sun.boot.class.path"; + + // Some runtime instances we need. + private final HotSpotGraalRuntime graalRuntime = HotSpotGraalRuntime.getInstance(); + private final VMToCompilerImpl vmToCompiler = (VMToCompilerImpl) graalRuntime.getVMToCompiler(); + + /** List of Zip/Jar files to compile (see {@link GraalOptions#CompileTheWorld}. */ + private final String files; + + /** Class index to start compilation at (see {@link GraalOptions#CompileTheWorldStartAt}. */ + private final int startAt; + + /** Class index to stop compilation at (see {@link GraalOptions#CompileTheWorldStopAt}. */ + private final int stopAt; + + // Counters + private int classFileCounter = 0; + private int compiledMethodsCounter = 0; + private long compileTime = 0; + + /** + * Create a compile-the-world instance with default values from + * {@link GraalOptions#CompileTheWorld}, {@link GraalOptions#CompileTheWorldStartAt} and + * {@link GraalOptions#CompileTheWorldStopAt}. + */ + public CompileTheWorld() { + this(GraalOptions.CompileTheWorld, GraalOptions.CompileTheWorldStartAt, GraalOptions.CompileTheWorldStopAt); + } + + /** + * Create a compile-the-world instance. + * + * @param files {@link File#pathSeparator} separated list of Zip/Jar files to compile + * @param startAt index of the class file to start compilation at + * @param stopAt index of the class file to stop compilation at + */ + public CompileTheWorld(String files, int startAt, int stopAt) { + this.files = files; + this.startAt = startAt; + this.stopAt = stopAt; + + // We don't want the VM to exit when a method fails to compile. + GraalOptions.ExitVMOnException = false; + } + + /** + * Compile all methods in all classes in the Zip/Jar files in + * {@link GraalOptions#CompileTheWorld}. If the GraalOptions.CompileTheWorld contains the magic + * token {@link CompileTheWorld#SUN_BOOT_CLASS_PATH} passed up from HotSpot we take the files + * from the boot class path. + * + * @throws Throwable + */ + public void compile() throws Throwable { + if (SUN_BOOT_CLASS_PATH.equals(files)) { + final String[] entries = System.getProperty(SUN_BOOT_CLASS_PATH).split(File.pathSeparator); + String bcpFiles = ""; + for (int i = 0; i < entries.length; i++) { + final String entry = entries[i]; + + // We stop at rt.jar, unless it is the first boot class path entry. + if (entry.endsWith("rt.jar") && (i > 0)) { + break; + } + if (i > 0) { + bcpFiles += File.pathSeparator; + } + bcpFiles += entry; + } + compile(bcpFiles); + } else { + compile(files); + } + } + + /** + * Compile all methods in all classes in the Zip/Jar files passed. + * + * @param fileList {@link File#pathSeparator} separated list of Zip/Jar files to compile + * @throws Throwable + */ + private void compile(String fileList) throws Throwable { + final String[] entries = fileList.split(File.pathSeparator); + + for (int i = 0; i < entries.length; i++) { + final String entry = entries[i]; + + // For now we only compile all methods in all classes in zip/jar files. + if (!entry.endsWith(".zip") && !entry.endsWith(".jar")) { + TTY.println("CompileTheWorld : Skipped classes in " + entry); + TTY.println(); + continue; + } + + TTY.println("CompileTheWorld : Compiling all classes in " + entry); + TTY.println(); + + URL url = new URL("jar", "", "file:" + entry + "!/"); + ClassLoader loader = new URLClassLoader(new URL[]{url}); + + JarFile jarFile = new JarFile(entry); + Enumeration e = jarFile.entries(); + + while (e.hasMoreElements()) { + JarEntry je = e.nextElement(); + if (je.isDirectory() || !je.getName().endsWith(".class")) { + continue; + } + + // Are we done? + if (classFileCounter >= stopAt) { + break; + } + + String className = je.getName().substring(0, je.getName().length() - ".class".length()); + className = className.replace('/', '.'); + classFileCounter++; + + try { + // Load and initialize class + Class javaClass = Class.forName(className, true, loader); + + // Pre-load all classes in the constant pool. + try { + HotSpotResolvedObjectType objectType = (HotSpotResolvedObjectType) HotSpotResolvedObjectType.fromClass(javaClass); + ConstantPool constantPool = objectType.constantPool(); + for (int cpi = 1; cpi < constantPool.length(); cpi++) { + constantPool.loadReferencedType(cpi, Bytecodes.LDC); + } + } catch (Throwable t) { + // If something went wrong during pre-loading we just ignore it. + TTY.println("CompileTheWorld (%d) : Preloading failed for %s", classFileCounter, className); + } + + // Are we compiling this class? + if (classFileCounter >= startAt) { + TTY.println("CompileTheWorld (%d) : %s", classFileCounter, className); + + // Enqueue each constructor/method in the class for compilation. + for (Constructor constructor : javaClass.getDeclaredConstructors()) { + HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) graalRuntime.getRuntime().lookupJavaConstructor(constructor); + if (canBeCompiled(javaMethod, constructor.getModifiers())) { + compileMethod(javaMethod); + } + } + for (Method method : javaClass.getDeclaredMethods()) { + HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) graalRuntime.getRuntime().lookupJavaMethod(method); + if (canBeCompiled(javaMethod, method.getModifiers())) { + compileMethod(javaMethod); + } + } + } + } catch (Throwable t) { + TTY.println("CompileTheWorld (%d) : Skipping %s", classFileCounter, className); + } + } + jarFile.close(); + } + + TTY.println(); + TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms)", classFileCounter, compiledMethodsCounter, compileTime); + } + + /** + * Helper method to schedule a method for compilation and gather some statistics. + */ + private void compileMethod(HotSpotResolvedJavaMethod method) { + try { + long start = System.currentTimeMillis(); + vmToCompiler.compileMethod(method, StructuredGraph.INVOCATION_ENTRY_BCI, true, 10); + compileTime += (System.currentTimeMillis() - start); + compiledMethodsCounter++; + method.reprofile(); // makes the method also not-entrant + } catch (Throwable t) { + // Catch everything and print a message + TTY.println("CompileTheWorld (%d) : Error compiling method: %s", classFileCounter, MetaUtil.format("%H.%n(%p):%r", method)); + t.printStackTrace(TTY.cachedOut); + } + } + + /** + * Helper method for CompileTheWorld to determine if a method should be compiled (Cf. + * CompilationPolicy::can_be_compiled). + * + * @return true if it can be compiled, false otherwise + */ + private static boolean canBeCompiled(HotSpotResolvedJavaMethod javaMethod, int modifiers) { + if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + return false; + } + // This number is from HotSpot: + final int hugeMethodLimit = 8000; + if (javaMethod.getCodeSize() > hugeMethodLimit) { + return false; + } + // Skip @Snippets for now + if (javaMethod.getAnnotation(Snippet.class) != null) { + return false; + } + return true; + } + +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompilationResult.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompilationResult.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompilationResult.java Mon Apr 15 08:51:19 2013 +0200 @@ -67,7 +67,7 @@ } private static Site[] getSortedSites(CompilationResult target) { - List[] lists = new List[]{target.getSafepoints(), target.getDataReferences(), target.getMarks()}; + List[] lists = new List[]{target.getInfopoints(), target.getDataReferences(), target.getMarks()}; int count = 0; for (List list : lists) { count += list.size(); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Mon Apr 15 08:51:19 2013 +0200 @@ -119,6 +119,7 @@ protected final HotSpotRuntime runtime; protected final TargetDescription target; + protected final Replacements replacements; private HotSpotRuntimeInterpreterInterface runtimeInterpreterInterface; private volatile HotSpotGraphCache cache; @@ -138,6 +139,19 @@ compilerToVm.initializeConfiguration(config); config.check(); + // Set some global options: + if (config.compileTheWorld) { + GraalOptions.CompileTheWorld = CompileTheWorld.SUN_BOOT_CLASS_PATH; + } + if (config.compileTheWorldStartAt != 1) { + GraalOptions.CompileTheWorldStartAt = config.compileTheWorldStartAt; + } + if (config.compileTheWorldStopAt != Integer.MAX_VALUE) { + GraalOptions.CompileTheWorldStopAt = config.compileTheWorldStopAt; + } + GraalOptions.HotSpotPrintCompilation = config.printCompilation; + GraalOptions.HotSpotPrintInlining = config.printInlining; + if (Boolean.valueOf(System.getProperty("graal.printconfig"))) { printConfig(config); } @@ -148,6 +162,11 @@ runtime = createRuntime(); + // Replacements cannot have speculative optimizations since they have + // to be valid for the entire run of the VM. + Assumptions assumptions = new Assumptions(false); + replacements = new HotSpotReplacementsImpl(runtime, assumptions, runtime.getGraalRuntime().getTarget()); + backend = createBackend(); GraalOptions.StackShadowPages = config.stackShadowPages; if (GraalOptions.CacheGraphs) { @@ -239,6 +258,10 @@ return runtime; } + public Replacements getReplacements() { + return replacements; + } + public void evictDeoptedGraphs() { if (cache != null) { long[] deoptedGraphs = getCompilerToVM().getDeoptedLeafGraphIds(); @@ -269,6 +292,9 @@ if (clazz == HotSpotRuntime.class) { return (T) runtime; } + if (clazz == Replacements.class) { + return (T) replacements; + } if (clazz == Backend.class) { return (T) getBackend(); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,86 @@ +/* + * 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.graal.hotspot; + +import java.lang.reflect.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.replacements.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.replacements.*; + +/** + * Filters certain method substitutions based on whether there is underlying hardware support for + * them. + */ +public class HotSpotReplacementsImpl extends ReplacementsImpl { + + private final HotSpotVMConfig config; + + public HotSpotReplacementsImpl(HotSpotRuntime runtime, Assumptions assumptions, TargetDescription target) { + super(runtime, assumptions, target); + this.config = runtime.config; + } + + @Override + protected ResolvedJavaMethod registerMethodSubstitution(Member originalMethod, Method substituteMethod) { + if (substituteMethod.getDeclaringClass() == IntegerSubstitutions.class || substituteMethod.getDeclaringClass() == LongSubstitutions.class) { + if (substituteMethod.getName().equals("bitCount")) { + if (!config.usePopCountInstruction) { + return null; + } + } + } else if (substituteMethod.getDeclaringClass() == AESCryptSubstitutions.class || substituteMethod.getDeclaringClass() == CipherBlockChainingSubstitutions.class) { + if (!config.useAESIntrinsics) { + return null; + } + assert config.aescryptEncryptBlockStub != 0L; + assert config.aescryptDecryptBlockStub != 0L; + assert config.cipherBlockChainingEncryptAESCryptStub != 0L; + assert config.cipherBlockChainingDecryptAESCryptStub != 0L; + } + return super.registerMethodSubstitution(originalMethod, substituteMethod); + } + + @Override + public Class getMacroSubstitution(ResolvedJavaMethod method) { + HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method; + int intrinsicId = hsMethod.intrinsicId(); + if (intrinsicId != 0) { + if (intrinsicId == config.vmIntrinsicInvokeBasic) { + return MethodHandleInvokeBasicNode.class; + } else if (intrinsicId == config.vmIntrinsicLinkToInterface) { + return MethodHandleLinkToInterfaceNode.class; + } else if (intrinsicId == config.vmIntrinsicLinkToSpecial) { + return MethodHandleLinkToSpecialNode.class; + } else if (intrinsicId == config.vmIntrinsicLinkToStatic) { + return MethodHandleLinkToStaticNode.class; + } else if (intrinsicId == config.vmIntrinsicLinkToVirtual) { + return MethodHandleLinkToVirtualNode.class; + } + } + return super.getMacroSubstitution(method); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsInstaller.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsInstaller.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +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. - */ -package com.oracle.graal.hotspot; - -import java.lang.reflect.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.replacements.*; -import com.oracle.graal.replacements.*; - -/** - * Filters certain method substitutions based on whether there is underlying hardware support for them. - */ -public class HotSpotReplacementsInstaller extends ReplacementsInstaller { - - private final HotSpotVMConfig config; - - public HotSpotReplacementsInstaller(HotSpotRuntime runtime, Assumptions assumptions, TargetDescription target) { - super(runtime, assumptions, target); - this.config = runtime.config; - } - - @Override - protected void installMethodSubstitution(Member originalMethod, Method substituteMethod) { - if (substituteMethod.getDeclaringClass() == IntegerSubstitutions.class || substituteMethod.getDeclaringClass() == LongSubstitutions.class) { - if (substituteMethod.getName().equals("bitCount")) { - if (!config.usePopCountInstruction) { - return; - } - } - } else if (substituteMethod.getDeclaringClass() == AESCryptSubstitutions.class || substituteMethod.getDeclaringClass() == CipherBlockChainingSubstitutions.class) { - if (!config.useAESIntrinsics) { - return; - } - assert config.aescryptEncryptBlockStub != 0L; - assert config.aescryptDecryptBlockStub != 0L; - assert config.cipherBlockChainingEncryptAESCryptStub != 0L; - assert config.cipherBlockChainingDecryptAESCryptStub != 0L; - } - super.installMethodSubstitution(originalMethod, substituteMethod); - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java Mon Apr 15 08:51:19 2013 +0200 @@ -24,6 +24,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.stubs.*; @@ -79,17 +80,19 @@ } public void setStub(Stub stub) { - assert address == 0L : "cannot stub for linkage that already has an address: " + this; + assert address == 0L : "cannot set stub for linkage that already has an address: " + this; this.stub = stub; } - public void setAddress(long address) { - assert this.address == 0L : "cannot re-initialize address of " + this; - this.address = address; + public void finalizeAddress(Backend backend) { + if (address == 0) { + assert stub != null : "linkage without an address must be a stub"; + address = stub.getAddress(backend); + } } - public long getAddress() { - assert address != 0L : "address not yet initialized for " + this; - return address; + @Override + public boolean preservesRegisters() { + return stub == null; } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -37,6 +37,11 @@ public int codeEntryAlignment; public boolean verifyOops; public boolean ciTime; + public boolean compileTheWorld; + public int compileTheWorldStartAt; + public int compileTheWorldStopAt; + public boolean printCompilation; + public boolean printInlining; public boolean useFastLocking; public boolean useTLAB; public boolean useBiasedLocking; @@ -185,6 +190,11 @@ public int methodAccessFlagsOffset; /** + * Offset of _intrinsic_id in a metaspace Method object. + */ + public int methodIntrinsicIdOffset; + + /** * Offset of _max_locals in a metaspace Method object. */ public int methodMaxLocalsOffset; @@ -376,6 +386,12 @@ public int deoptActionMakeNotEntrant; public int deoptActionMakeNotCompilable; + public int vmIntrinsicInvokeBasic; + public int vmIntrinsicLinkToVirtual; + public int vmIntrinsicLinkToStatic; + public int vmIntrinsicLinkToSpecial; + public int vmIntrinsicLinkToInterface; + public void check() { assert codeEntryAlignment > 0; assert stackShadowPages > 0; diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Mon Apr 15 08:51:19 2013 +0200 @@ -128,6 +128,8 @@ */ JavaType lookupType(String name, HotSpotResolvedObjectType accessingClass, boolean eagerResolve); + int constantPoolLength(HotSpotResolvedObjectType pool); + Object lookupConstantInPool(HotSpotResolvedObjectType pool, int cpi); JavaMethod lookupMethodInPool(HotSpotResolvedObjectType pool, int cpi, byte opcode); @@ -138,6 +140,8 @@ void lookupReferencedTypeInPool(HotSpotResolvedObjectType pool, int cpi, byte opcode); + Object lookupAppendixInPool(HotSpotResolvedObjectType pool, int cpi, byte opcode); + // Must be kept in sync with enum in graalEnv.hpp public enum CodeInstallResult { OK, DEPENDENCIES_FAILED, CACHE_FULL @@ -199,9 +203,9 @@ StackTraceElement getStackTraceElement(long metaspaceMethod, int bci); - Object executeCompiledMethod(long metaspaceMethod, long nmethod, Object arg1, Object arg2, Object arg3); + Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nativeMethod) throws InvalidInstalledCodeException; - Object executeCompiledMethodVarargs(long metaspaceMethod, long nmethod, Object... args); + Object executeCompiledMethodVarargs(Object[] args, long nativeMethod) throws InvalidInstalledCodeException; int getVtableEntryOffset(long metaspaceMethod); @@ -221,4 +225,8 @@ * @param metaspaceMethod the metaspace Method object */ void reprofile(long metaspaceMethod); + + void invalidateInstalledCode(long nativeMethod); + + boolean isInstalledCodeValid(long nativeMethod); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Mon Apr 15 08:51:19 2013 +0200 @@ -79,6 +79,9 @@ public native JavaType lookupType(String name, HotSpotResolvedObjectType accessingClass, boolean eagerResolve); @Override + public native int constantPoolLength(HotSpotResolvedObjectType pool); + + @Override public native Object lookupConstantInPool(HotSpotResolvedObjectType pool, int cpi); @Override @@ -133,10 +136,7 @@ public native StackTraceElement getStackTraceElement(long metaspaceMethod, int bci); @Override - public native Object executeCompiledMethod(long metaspaceMethod, long nmethod, Object arg1, Object arg2, Object arg3); - - @Override - public native Object executeCompiledMethodVarargs(long metaspaceMethod, long nmethod, Object... args); + public native Object executeCompiledMethodVarargs(Object[] args, long nativeMethod); @Override public native int getVtableEntryOffset(long metaspaceMethod); @@ -158,4 +158,27 @@ @Override public native void reprofile(long metaspaceMethod); + + @Override + public native Object lookupAppendixInPool(HotSpotResolvedObjectType pool, int cpi, byte opcode); + + @Override + public native void invalidateInstalledCode(long nativeMethod); + + @Override + public native boolean isInstalledCodeValid(long nativeMethod); + + @Override + public Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, long nativeMethod) throws InvalidInstalledCodeException { + return executeCompiledMethodIntrinsic(arg1, arg2, arg3, nativeMethod); + } + + /** + * Direct call to the given nativeMethod with three object arguments and an object return value. + * This method does not have an implementation on the C++ side, but its entry points (from + * interpreter and from compiled code) are directly pointing to a manually generated assembly + * stub that does the necessary argument shuffling and a tail call via an indirect jump to the + * verified entry point of the given native method. + */ + private static native Object executeCompiledMethodIntrinsic(Object arg1, Object arg2, Object arg3, long nativeMethod); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/MetricRateInPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/MetricRateInPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/MetricRateInPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.hotspot.bridge; +import java.io.*; import java.util.concurrent.*; import com.oracle.graal.debug.*; @@ -65,10 +66,10 @@ return (int) (v / t); } - public void printAll(String label) { + public void printAll(String label, PrintStream stream) { MetricRateInPhase rs = this; while (rs != null) { - System.out.println(label + "@" + rs.phase + ": " + rs.rate()); + stream.println(label + "@" + rs.phase + ": " + rs.rate()); rs = rs.previous; } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java Mon Apr 15 08:51:19 2013 +0200 @@ -34,8 +34,23 @@ */ public interface VMToCompiler { + /** + * Compiles a method to machine code. This method is called from the VM + * (VMToCompiler::compileMethod). + * + * @return true if the method is in the queue (either added to the queue or already in the + * queue) + */ boolean compileMethod(long metaspaceMethod, HotSpotResolvedObjectType holder, int entryBCI, boolean blocking, int priority) throws Throwable; + /** + * Compiles a method to machine code. + * + * @return true if the method is in the queue (either added to the queue or already in the + * queue) + */ + boolean compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, boolean blocking, int priority) throws Throwable; + void shutdownCompiler() throws Throwable; void startCompiler() throws Throwable; diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Mon Apr 15 08:51:19 2013 +0200 @@ -34,10 +34,10 @@ import java.util.concurrent.*; import java.util.concurrent.atomic.*; -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.internal.*; +import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.debug.*; import com.oracle.graal.hotspot.meta.*; @@ -45,6 +45,7 @@ import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.debug.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.PhasePlan.PhasePosition; import com.oracle.graal.printer.*; @@ -146,19 +147,24 @@ // Install intrinsics. final HotSpotRuntime runtime = graalRuntime.getCapability(HotSpotRuntime.class); + final Replacements replacements = graalRuntime.getCapability(Replacements.class); if (GraalOptions.Intrinsify) { - Debug.scope("InstallReplacements", new Object[]{new DebugDumpScope("InstallReplacements")}, new Runnable() { + Debug.scope("RegisterReplacements", new Object[]{new DebugDumpScope("RegisterReplacements")}, new Runnable() { @Override public void run() { - // Replacements cannot have speculative optimizations since they have - // to be valid for the entire run of the VM. - Assumptions assumptions = new Assumptions(false); - ReplacementsInstaller installer = new HotSpotReplacementsInstaller(runtime, assumptions, runtime.getGraalRuntime().getTarget()); - for (ReplacementsProvider provider : ServiceLoader.loadInstalled(ReplacementsProvider.class)) { - provider.installReplacements(installer); + ServiceLoader serviceLoader = ServiceLoader.loadInstalled(ReplacementsProvider.class); + for (ReplacementsProvider provider : serviceLoader) { + provider.registerReplacements(replacements); } - runtime.installReplacements(graalRuntime.getBackend(), installer, assumptions); + runtime.registerReplacements(replacements); + if (GraalOptions.BootstrapReplacements) { + for (ResolvedJavaMethod method : replacements.getAllReplacements()) { + replacements.getMacroSubstitution(method); + replacements.getMethodSubstitution(method); + replacements.getSnippet(method); + } + } } }); @@ -200,9 +206,22 @@ t.start(); } - if (GraalOptions.BenchmarkDynamicCounters) { - System.setErr(new PrintStream(new BenchmarkCountersOutputStream(System.err, " starting =====", " PASSED in ", "\n"))); - System.setOut(new PrintStream(new BenchmarkCountersOutputStream(System.out, "Iteration ~ (~s) begins: ", "Iteration ~ (~s) ends: ", "\n"))); + if (GraalOptions.BenchmarkDynamicCounters != null) { + String[] arguments = GraalOptions.BenchmarkDynamicCounters.split(","); + if (arguments.length == 0 || (arguments.length % 3) != 0) { + throw new GraalInternalError("invalid arguments to BenchmarkDynamicCounters: (err|out),start,end,(err|out),start,end,... (~ matches multiple digits)"); + } + for (int i = 0; i < arguments.length; i += 3) { + if (arguments[i].equals("err")) { + System.setErr(new PrintStream(new BenchmarkCountersOutputStream(System.err, arguments[i + 1], arguments[i + 2]))); + } else if (arguments[i].equals("out")) { + System.setOut(new PrintStream(new BenchmarkCountersOutputStream(System.out, arguments[i + 1], arguments[i + 2]))); + } else { + throw new GraalInternalError("invalid arguments to BenchmarkDynamicCounters: err|out"); + } + // dacapo: "err, starting =====, PASSED in " + // specjvm2008: "out,Iteration ~ (~s) begins: ,Iteration ~ (~s) ends: " + } DynamicCounterNode.excludedClassPrefix = "Lcom/oracle/graal/"; DynamicCounterNode.enabled = true; } @@ -217,8 +236,8 @@ private long startTime; private boolean waitingForEnd; - private BenchmarkCountersOutputStream(PrintStream delegate, String... patterns) { - super(delegate, patterns); + private BenchmarkCountersOutputStream(PrintStream delegate, String start, String end) { + super(delegate, new String[]{start, end, "\n"}); } @Override @@ -374,6 +393,10 @@ System.gc(); phaseTransition("bootstrap2"); + if (GraalOptions.CompileTheWorld != null) { + new CompileTheWorld().compile(); + System.exit(0); + } } private MetricRateInPhase parsedBytecodesPerSecond; @@ -441,8 +464,8 @@ phaseTransition("final"); if (graalRuntime.getConfig().ciTime) { - parsedBytecodesPerSecond.printAll("ParsedBytecodesPerSecond"); - inlinedBytecodesPerSecond.printAll("InlinedBytecodesPerSecond"); + parsedBytecodesPerSecond.printAll("ParsedBytecodesPerSecond", System.out); + inlinedBytecodesPerSecond.printAll("InlinedBytecodesPerSecond", System.out); } SnippetCounter.printGroups(TTY.out().out()); @@ -716,6 +739,7 @@ if (onStackReplacement) { phasePlan.addPhase(PhasePosition.AFTER_PARSING, new OnStackReplacementPhase()); } + phasePlan.addPhase(PhasePosition.LOW_LEVEL, new WriteBarrierAdditionPhase()); return phasePlan; } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/CountingProxy.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/CountingProxy.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/CountingProxy.java Mon Apr 15 08:51:19 2013 +0200 @@ -41,7 +41,9 @@ public CountingProxy(T delegate) { assert ENABLED; + // CheckStyle: stop system..print check System.out.println("Counting proxy for " + delegate.getClass().getSimpleName() + " created"); + // CheckStyle: resume system..print check this.delegate = delegate; proxies.add(this); } @@ -92,6 +94,7 @@ } } + // CheckStyle: stop system..print check protected void print() { long sum = 0; for (Map.Entry entry : calls.entrySet()) { @@ -102,4 +105,5 @@ } System.out.println(delegate.getClass().getSimpleName() + " calls: " + sum); } + // CheckStyle: resume system..print check } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/Logger.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/Logger.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/Logger.java Mon Apr 15 08:51:19 2013 +0200 @@ -70,6 +70,7 @@ } } + // CheckStyle: stop system..print check public static void info(String message) { if (ENABLED) { log(message); @@ -124,6 +125,8 @@ } } + // CheckStyle: resume system..print check + private static String[] spaces = new String[50]; private static String space(int count) { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java Mon Apr 15 08:51:19 2013 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.hotspot.meta; import com.oracle.graal.api.meta.*; +import com.oracle.graal.bytecode.*; import com.oracle.graal.hotspot.*; /** @@ -39,6 +40,11 @@ } @Override + public int length() { + return HotSpotGraalRuntime.getInstance().getCompilerToVM().constantPoolLength(type); + } + + @Override public Object lookupConstant(int cpi) { assert cpi != 0; Object constant = HotSpotGraalRuntime.getInstance().getCompilerToVM().lookupConstantInPool(type, cpi); @@ -51,6 +57,12 @@ } @Override + public Object lookupAppendix(int cpi, int opcode) { + assert Bytecodes.isInvoke(opcode); + return HotSpotGraalRuntime.getInstance().getCompilerToVM().lookupAppendixInPool(type, cpi, (byte) opcode); + } + + @Override public JavaMethod lookupMethod(int cpi, int opcode) { return HotSpotGraalRuntime.getInstance().getCompilerToVM().lookupMethodInPool(type, cpi, (byte) opcode); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java Mon Apr 15 08:51:19 2013 +0200 @@ -26,6 +26,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; /** @@ -39,11 +40,13 @@ private final HotSpotResolvedJavaMethod method; private final boolean isDefault; + private final Graph graph; long nmethod; long start; - public HotSpotInstalledCode(HotSpotResolvedJavaMethod method, boolean isDefault) { + public HotSpotInstalledCode(HotSpotResolvedJavaMethod method, Graph graph, boolean isDefault) { this.method = method; + this.graph = graph; this.isDefault = isDefault; } @@ -51,10 +54,14 @@ return isDefault; } - public long getnmethod() { + public long getMethodAddress() { return nmethod; } + public Graph getGraph() { + return graph; + } + @Override public ResolvedJavaMethod getMethod() { return method; @@ -62,7 +69,12 @@ @Override public boolean isValid() { - return nmethod != 0; + return HotSpotGraalRuntime.getInstance().getCompilerToVM().isInstalledCodeValid(nmethod); + } + + @Override + public void invalidate() { + HotSpotGraalRuntime.getInstance().getCompilerToVM().invalidateInstalledCode(nmethod); } @Override @@ -71,12 +83,12 @@ } @Override - public Object execute(Object arg1, Object arg2, Object arg3) { + public Object execute(Object arg1, Object arg2, Object arg3) throws InvalidInstalledCodeException { assert method.getSignature().getParameterCount(!Modifier.isStatic(method.getModifiers())) == 3; assert method.getSignature().getParameterKind(0) == Kind.Object; assert method.getSignature().getParameterKind(1) == Kind.Object; assert !Modifier.isStatic(method.getModifiers()) || method.getSignature().getParameterKind(2) == Kind.Object; - return HotSpotGraalRuntime.getInstance().getCompilerToVM().executeCompiledMethod(method.metaspaceMethod, nmethod, arg1, arg2, arg3); + return HotSpotGraalRuntime.getInstance().getCompilerToVM().executeCompiledMethod(arg1, arg2, arg3, nmethod); } private boolean checkArgs(Object... args) { @@ -94,9 +106,9 @@ } @Override - public Object executeVarargs(Object... args) { + public Object executeVarargs(Object... args) throws InvalidInstalledCodeException { assert checkArgs(args); - return HotSpotGraalRuntime.getInstance().getCompilerToVM().executeCompiledMethodVarargs(method.metaspaceMethod, nmethod, args); + return HotSpotGraalRuntime.getInstance().getCompilerToVM().executeCompiledMethodVarargs(args, nmethod); } @Override @@ -108,8 +120,4 @@ public byte[] getCode() { return HotSpotGraalRuntime.getInstance().getCompilerToVM().getCode(nmethod); } - - public static Object executeHelper(long nmethod, long metaspaceMethod, Object arg1, Object arg2, Object arg3) { - return HotSpotGraalRuntime.getInstance().getCompilerToVM().executeCompiledMethod(metaspaceMethod, nmethod, arg1, arg2, arg3); - } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java Mon Apr 15 08:51:19 2013 +0200 @@ -364,12 +364,12 @@ } totalCount += getTypesNotRecordedExecutionCount(data, position); - return createTypeProfile(types, counts, totalCount, entries); + return createTypeProfile(getNullSeen(data, position), types, counts, totalCount, entries); } protected abstract long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position); - private static JavaTypeProfile createTypeProfile(ResolvedJavaType[] types, long[] counts, long totalCount, int entries) { + private static JavaTypeProfile createTypeProfile(TriState nullSeen, ResolvedJavaType[] types, long[] counts, long totalCount, int entries) { if (entries <= 0 || totalCount < GraalOptions.MatureExecutionsTypeProfile) { return null; } @@ -387,7 +387,7 @@ double notRecordedTypeProbability = entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); assert notRecordedTypeProbability == 0 || entries == config.typeProfileWidth; - return new JavaTypeProfile(notRecordedTypeProbability, ptypes); + return new JavaTypeProfile(nullSeen, notRecordedTypeProbability, ptypes); } private static int getReceiverOffset(int row) { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodUnresolved.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodUnresolved.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodUnresolved.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.hotspot.meta; +import static com.oracle.graal.api.meta.MetaUtil.*; + import com.oracle.graal.api.meta.*; /** @@ -51,6 +53,6 @@ @Override public String toString() { - return "HotSpotMethod<" + holder.getName() + ". " + name + ", unresolved>"; + return format("HotSpotMethod<%H.%n(%p), unresolved>", this); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java Mon Apr 15 08:51:19 2013 +0200 @@ -23,6 +23,8 @@ package com.oracle.graal.hotspot.meta; +import static com.oracle.graal.api.meta.MetaUtil.*; + import java.lang.annotation.*; import java.lang.reflect.*; @@ -150,7 +152,7 @@ @Override public String toString() { - return "HotSpotField<" + MetaUtil.format("%h.%n", this) + ":" + offset + ">"; + return format("HotSpotField<%H.%n %t:", this) + offset + ">"; } @Override diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.hotspot.meta; +import static com.oracle.graal.api.meta.MetaUtil.*; import static com.oracle.graal.graph.FieldIntrospection.*; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; @@ -186,7 +187,7 @@ @Override public String toString() { - return "HotSpotMethod<" + MetaUtil.format("%h.%n", this) + ">"; + return format("HotSpotMethod<%H.%n(%p)>", this); } public int getCompiledCodeSize() { @@ -361,4 +362,51 @@ } return speculationLog; } + + public int intrinsicId() { + HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig(); + return unsafe.getByte(metaspaceMethod + config.methodIntrinsicIdOffset) & 0xff; + } + + @Override + public Constant invoke(Constant receiver, Constant[] arguments) { + assert !isConstructor(); + Method javaMethod = toJava(); + javaMethod.setAccessible(true); + + Object[] objArguments = new Object[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + objArguments[i] = arguments[i].asBoxedValue(); + } + Object objReceiver = receiver != null ? receiver.asObject() : null; + + try { + Object objResult = javaMethod.invoke(objReceiver, objArguments); + return javaMethod.getReturnType() == void.class ? null : Constant.forBoxed(getSignature().getReturnKind(), objResult); + + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new IllegalArgumentException(ex); + } + } + + @Override + public Constant newInstance(Constant[] arguments) { + assert isConstructor(); + Constructor javaConstructor = toJavaConstructor(); + javaConstructor.setAccessible(true); + + Object[] objArguments = new Object[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + objArguments[i] = arguments[i].asBoxedValue(); + } + + try { + Object objResult = javaConstructor.newInstance(objArguments); + assert objResult != null; + return Constant.forObject(objResult); + + } catch (IllegalAccessException | InvocationTargetException | InstantiationException ex) { + throw new IllegalArgumentException(ex); + } + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java Mon Apr 15 08:51:19 2013 +0200 @@ -135,7 +135,6 @@ assert name.charAt(0) != '[' || sizeOrSpecies == ARRAY_SPECIES_VALUE : name + " " + Long.toHexString(sizeOrSpecies); assert javaMirror.isArray() == isArray(); assert javaMirror.isInterface() == isInterface(); - // System.out.println("0x" + Long.toHexString(metaspaceKlass) + ": " + name); } @Override @@ -520,4 +519,31 @@ final Class encl = mirror().getEnclosingClass(); return encl == null ? null : fromClass(encl); } + + @Override + public ResolvedJavaMethod[] getDeclaredConstructors() { + Constructor[] constructors = javaMirror.getDeclaredConstructors(); + ResolvedJavaMethod[] result = new ResolvedJavaMethod[constructors.length]; + for (int i = 0; i < constructors.length; i++) { + result[i] = HotSpotGraalRuntime.getInstance().getRuntime().lookupJavaConstructor(constructors[i]); + assert result[i].isConstructor(); + } + return result; + } + + @Override + public ResolvedJavaMethod[] getDeclaredMethods() { + Method[] methods = javaMirror.getDeclaredMethods(); + ResolvedJavaMethod[] result = new ResolvedJavaMethod[methods.length]; + for (int i = 0; i < methods.length; i++) { + result[i] = HotSpotGraalRuntime.getInstance().getRuntime().lookupJavaMethod(methods[i]); + assert !result[i].isConstructor(); + } + return result; + } + + @Override + public Constant newArray(int length) { + return Constant.forObject(Array.newInstance(javaMirror, length)); + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java Mon Apr 15 08:51:19 2013 +0200 @@ -210,4 +210,19 @@ public ResolvedJavaType getEnclosingType() { return null; } + + @Override + public ResolvedJavaMethod[] getDeclaredConstructors() { + return new ResolvedJavaMethod[0]; + } + + @Override + public ResolvedJavaMethod[] getDeclaredMethods() { + return new ResolvedJavaMethod[0]; + } + + @Override + public Constant newArray(int length) { + return Constant.forObject(Array.newInstance(javaMirror, length)); + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Mon Apr 15 08:51:19 2013 +0200 @@ -30,12 +30,14 @@ import static com.oracle.graal.api.meta.Value.*; import static com.oracle.graal.graph.UnsafeAccess.*; import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; +import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*; +import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*; import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*; import static com.oracle.graal.java.GraphBuilderPhase.RuntimeCalls.*; import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*; import static com.oracle.graal.replacements.Log.*; import static com.oracle.graal.replacements.MathSubstitutionsX86.*; -import com.oracle.graal.replacements.*; + import java.lang.reflect.*; import java.util.*; @@ -46,11 +48,10 @@ import com.oracle.graal.api.code.CompilationResult.Call; import com.oracle.graal.api.code.CompilationResult.DataPatch; import com.oracle.graal.api.code.CompilationResult.Mark; -import com.oracle.graal.api.code.CompilationResult.Safepoint; +import com.oracle.graal.api.code.CompilationResult.Infopoint; import com.oracle.graal.api.code.Register.RegisterFlag; import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.target.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.bridge.*; @@ -63,12 +64,14 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.WriteNode.WriteBarrierType; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.*; import com.oracle.graal.printer.*; +import com.oracle.graal.replacements.*; import com.oracle.graal.word.*; /** @@ -87,9 +90,8 @@ private NewObjectSnippets.Templates newObjectSnippets; private MonitorSnippets.Templates monitorSnippets; private WriteBarrierSnippets.Templates writeBarrierSnippets; - - private NewInstanceStub newInstanceStub; - private NewArrayStub newArrayStub; + private BoxingSnippets.Templates boxingSnippets; + private LoadExceptionObjectSnippets.Templates exceptionObjectSnippets; private final Map runtimeCalls = new HashMap<>(); private final Map stubs = new HashMap<>(); @@ -223,25 +225,25 @@ /* arg0: index */ javaCallingConvention(Kind.Int)); addRuntimeCall(JAVA_TIME_MILLIS, config.javaTimeMillisStub, - /* temps */ null, + /* temps */ this.regConfig.getCallerSaveRegisters(), /* ret */ ret(Kind.Long)); addRuntimeCall(JAVA_TIME_NANOS, config.javaTimeNanosStub, - /* temps */ null, + /* temps */ this.regConfig.getCallerSaveRegisters(), /* ret */ ret(Kind.Long)); addRuntimeCall(ARITHMETIC_SIN, config.arithmeticSinStub, - /* temps */ null, + /* temps */ this.regConfig.getCallerSaveRegisters(), /* ret */ ret(Kind.Double), /* arg0: index */ javaCallingConvention(Kind.Double)); addRuntimeCall(ARITHMETIC_COS, config.arithmeticCosStub, - /* temps */ null, + /* temps */ this.regConfig.getCallerSaveRegisters(), /* ret */ ret(Kind.Double), /* arg0: index */ javaCallingConvention(Kind.Double)); addRuntimeCall(ARITHMETIC_TAN, config.arithmeticTanStub, - /* temps */ null, + /* temps */ this.regConfig.getCallerSaveRegisters(), /* ret */ ret(Kind.Double), /* arg0: index */ javaCallingConvention(Kind.Double)); @@ -277,7 +279,7 @@ * @param ret where the call returns its result * @param args where arguments are passed to the call */ - protected void addRuntimeCall(Descriptor descriptor, long address, Register[] tempRegs, Value ret, Value... args) { + protected RuntimeCallTarget addRuntimeCall(Descriptor descriptor, long address, Register[] tempRegs, Value ret, Value... args) { Value[] temps = tempRegs == null || tempRegs.length == 0 ? Value.NONE : new Value[tempRegs.length]; for (int i = 0; i < temps.length; i++) { temps[i] = tempRegs[i].asValue(); @@ -290,6 +292,7 @@ } HotSpotRuntimeCallTarget runtimeCall = new HotSpotRuntimeCallTarget(descriptor, address, new CallingConvention(temps, 0, ret, args), graalRuntime.getCompilerToVM()); runtimeCalls.put(descriptor, runtimeCall); + return runtimeCall; } private boolean checkAssignable(Class spec, Value value) { @@ -303,67 +306,44 @@ return kind == Kind.fromJavaClass(spec); } - /** - * Binds a snippet-base {@link Stub} to a runtime call descriptor. - * - * @return the linkage information for a call to the stub - */ - public HotSpotRuntimeCallTarget registerStub(Descriptor descriptor, Stub stub) { - HotSpotRuntimeCallTarget linkage = runtimeCalls.get(descriptor); - assert linkage != null; - linkage.setStub(stub); - stubs.put(stub.getMethod(), stub); - return linkage; - } - protected abstract RegisterConfig createRegisterConfig(boolean globalStubConfig); - public void installReplacements(Backend backend, ReplacementsInstaller installer, Assumptions assumptions) { + public void registerReplacements(Replacements replacements) { if (GraalOptions.IntrinsifyObjectMethods) { - installer.installSubstitutions(ObjectSubstitutions.class); + replacements.registerSubstitutions(ObjectSubstitutions.class); } if (GraalOptions.IntrinsifySystemMethods) { - installer.installSubstitutions(SystemSubstitutions.class); + replacements.registerSubstitutions(SystemSubstitutions.class); } if (GraalOptions.IntrinsifyThreadMethods) { - installer.installSubstitutions(ThreadSubstitutions.class); + replacements.registerSubstitutions(ThreadSubstitutions.class); } if (GraalOptions.IntrinsifyUnsafeMethods) { - installer.installSubstitutions(UnsafeSubstitutions.class); + replacements.registerSubstitutions(UnsafeSubstitutions.class); } if (GraalOptions.IntrinsifyClassMethods) { - installer.installSubstitutions(ClassSubstitutions.class); + replacements.registerSubstitutions(ClassSubstitutions.class); } if (GraalOptions.IntrinsifyAESMethods) { - installer.installSubstitutions(AESCryptSubstitutions.class); - installer.installSubstitutions(CipherBlockChainingSubstitutions.class); - } - if (GraalOptions.IntrinsifyArrayCopy) { - installer.installSnippets(ArrayCopySnippets.class); - } - if (GraalOptions.IntrinsifyObjectClone) { - installer.installSnippets(ObjectCloneSnippets.class); + replacements.registerSubstitutions(AESCryptSubstitutions.class); + replacements.registerSubstitutions(CipherBlockChainingSubstitutions.class); } - installer.installSnippets(CheckCastSnippets.class); - installer.installSnippets(InstanceOfSnippets.class); - installer.installSnippets(NewObjectSnippets.class); - installer.installSnippets(MonitorSnippets.class); - - installer.installSnippets(NewInstanceStub.class); - installer.installSnippets(NewArrayStub.class); - installer.installSnippets(WriteBarrierSnippets.class); + checkcastSnippets = new CheckCastSnippets.Templates(this, replacements, graalRuntime.getTarget()); + instanceofSnippets = new InstanceOfSnippets.Templates(this, replacements, graalRuntime.getTarget()); + newObjectSnippets = new NewObjectSnippets.Templates(this, replacements, graalRuntime.getTarget(), config.useTLAB); + monitorSnippets = new MonitorSnippets.Templates(this, replacements, graalRuntime.getTarget(), config.useFastLocking); + writeBarrierSnippets = new WriteBarrierSnippets.Templates(this, replacements, graalRuntime.getTarget()); + boxingSnippets = new BoxingSnippets.Templates(this, replacements, graalRuntime.getTarget()); + exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(this, replacements, graalRuntime.getTarget()); - checkcastSnippets = new CheckCastSnippets.Templates(this, assumptions, graalRuntime.getTarget()); - instanceofSnippets = new InstanceOfSnippets.Templates(this, assumptions, graalRuntime.getTarget()); - newObjectSnippets = new NewObjectSnippets.Templates(this, assumptions, graalRuntime.getTarget(), config.useTLAB); - monitorSnippets = new MonitorSnippets.Templates(this, assumptions, graalRuntime.getTarget(), config.useFastLocking); - writeBarrierSnippets = new WriteBarrierSnippets.Templates(this, assumptions, graalRuntime.getTarget()); + registerStub(new NewInstanceStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_INSTANCE))); + registerStub(new NewArrayStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_ARRAY))); + } - newInstanceStub = new NewInstanceStub(this, assumptions, graalRuntime.getTarget()); - newArrayStub = new NewArrayStub(this, assumptions, graalRuntime.getTarget()); - newInstanceStub.install(backend); - newArrayStub.install(backend); + private void registerStub(Stub stub) { + stub.getLinkage().setStub(stub); + stubs.put(stub.getMethod(), stub); } public HotSpotGraalRuntime getGraalRuntime() { @@ -391,18 +371,18 @@ addExceptionHandlersComment(compResult, hcf); Register fp = regConfig.getFrameRegister(); RefMapFormatter slotFormatter = new RefMapFormatter(target.arch, target.wordSize, fp, 0); - for (Safepoint safepoint : compResult.getSafepoints()) { - if (safepoint instanceof Call) { - Call call = (Call) safepoint; + for (Infopoint infopoint : compResult.getInfopoints()) { + if (infopoint instanceof Call) { + Call call = (Call) infopoint; if (call.debugInfo != null) { hcf.addComment(call.pcOffset + call.size, CodeUtil.append(new StringBuilder(100), call.debugInfo, slotFormatter).toString()); } addOperandComment(hcf, call.pcOffset, "{" + getTargetName(call) + "}"); } else { - if (safepoint.debugInfo != null) { - hcf.addComment(safepoint.pcOffset, CodeUtil.append(new StringBuilder(100), safepoint.debugInfo, slotFormatter).toString()); + if (infopoint.debugInfo != null) { + hcf.addComment(infopoint.pcOffset, CodeUtil.append(new StringBuilder(100), infopoint.debugInfo, slotFormatter).toString()); } - addOperandComment(hcf, safepoint.pcOffset, "{safepoint}"); + addOperandComment(hcf, infopoint.pcOffset, "{infopoint: " + infopoint.reason + "}"); } } for (DataPatch site : compResult.getDataReferences()) { @@ -496,15 +476,6 @@ return regConfig; } - /** - * HotSpots needs an area suitable for storing a program counter for temporary use during the - * deoptimization process. - */ - @Override - public int getCustomStackAreaSize() { - return graalRuntime.getTarget().wordSize; - } - @Override public int getMinimumOutgoingSize() { return config.runtimeCallStackSize; @@ -535,7 +506,7 @@ NodeInputList parameters = callTarget.arguments(); ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0); if (!callTarget.isStatic() && receiver.kind() == Kind.Object && !receiver.objectStamp().nonNull()) { - invoke.node().dependencies().add(tool.createNullCheckGuard(receiver)); + invoke.asNode().dependencies().add(tool.createNullCheckGuard(receiver)); } JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass()); @@ -555,10 +526,10 @@ ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, LocationNode.create(LocationNode.ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph), StampFactory.forKind(wordKind()))); - loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.node().stamp(), signature, callTarget.targetMethod(), + loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall)); - graph.addBeforeFixed(invoke.node(), hub); + graph.addBeforeFixed(invoke.asNode(), hub); graph.addAfterFixed(hub, metaspaceMethod); graph.addAfterFixed(metaspaceMethod, compiledEntry); } @@ -566,7 +537,7 @@ } if (loweredCallTarget == null) { - loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.node().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall, + loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall, callTarget.invokeKind())); } callTarget.replaceAndDelete(loweredCallTarget); @@ -575,16 +546,11 @@ LoadFieldNode loadField = (LoadFieldNode) n; HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field(); ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : loadField.object(); - LocationNode location = LocationNode.create(field, field.getKind(), field.offset(), graph); assert loadField.kind() != Kind.Illegal; ReadNode memoryRead = graph.add(new ReadNode(object, LocationNode.create(field, field.getKind(), field.offset(), graph), loadField.stamp())); memoryRead.dependencies().add(tool.createNullCheckGuard(object)); graph.replaceFixedWithFixed(loadField, memoryRead); - if (config.useG1GC && field.getKind() == Kind.Object && field.getDeclaringClass().getName().toString().equals("Ljava/lang/ref/Reference;") && field.getName().equals("referent")) { - WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(memoryRead.object(), memoryRead, location, false)); - graph.addAfterFixed(memoryRead, writeBarrierPre); - } if (loadField.isVolatile()) { MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ)); @@ -597,27 +563,14 @@ HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field(); ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : storeField.object(); LocationNode location = LocationNode.create(field, field.getKind(), field.offset(), graph); - WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), location)); + WriteBarrierType barrierType = getFieldStoreBarrier(storeField); + WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), location, barrierType)); memoryWrite.dependencies().add(tool.createNullCheckGuard(object)); memoryWrite.setStateAfter(storeField.stateAfter()); graph.replaceFixedWithFixed(storeField, memoryWrite); FixedWithNextNode last = memoryWrite; FixedWithNextNode first = memoryWrite; - if (field.getKind() == Kind.Object && !memoryWrite.value().objectStamp().alwaysNull()) { - if (config.useG1GC) { - WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(memoryWrite.object(), null, memoryWrite.location(), true)); - WriteBarrierPost writeBarrierPost = graph.add(new WriteBarrierPost(memoryWrite.object(), memoryWrite.value(), memoryWrite.location(), false)); - graph.addBeforeFixed(memoryWrite, writeBarrierPre); - graph.addAfterFixed(memoryWrite, writeBarrierPost); - first = writeBarrierPre; - last = writeBarrierPost; - } else { - FieldWriteBarrier writeBarrier = graph.add(new FieldWriteBarrier(memoryWrite.object())); - graph.addAfterFixed(memoryWrite, writeBarrier); - last = writeBarrier; - } - } if (storeField.isVolatile()) { MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE)); graph.addBeforeFixed(first, preMembar); @@ -627,31 +580,7 @@ } else if (n instanceof CompareAndSwapNode) { // Separate out GC barrier semantics CompareAndSwapNode cas = (CompareAndSwapNode) n; - ValueNode expected = cas.expected(); - LocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1); - if (expected.kind() == Kind.Object && !cas.newValue().objectStamp().alwaysNull()) { - ResolvedJavaType type = cas.object().objectStamp().type(); - if (type != null && !type.isArray() && !MetaUtil.isJavaLangObject(type)) { - // Use a field write barrier since it's not an array store - if (config.useG1GC) { - WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(cas.object(), null, location, true)); - WriteBarrierPost writeBarrierPost = graph.add(new WriteBarrierPost(cas.object(), cas.newValue(), location, false)); - graph.addBeforeFixed(cas, writeBarrierPre); - graph.addAfterFixed(cas, writeBarrierPost); - } else { - graph.addAfterFixed(cas, graph.add(new FieldWriteBarrier(cas.object()))); - } - } else { - // This may be an array store so use an array write barrier - if (config.useG1GC) { - WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(cas.object(), null, location, true)); - graph.addBeforeFixed(cas, writeBarrierPre); - graph.addAfterFixed(cas, graph.add(new WriteBarrierPost(cas.object(), cas.newValue(), location, true))); - } else { - graph.addAfterFixed(cas, graph.add(new ArrayWriteBarrier(cas.object(), location))); - } - } - } + cas.setWriteBarrierType(getCompareAndSwapBarrier(cas)); } else if (n instanceof LoadIndexedNode) { LoadIndexedNode loadIndexed = (LoadIndexedNode) n; ValueNode boundsCheck = createBoundsCheck(loadIndexed, tool); @@ -687,21 +616,12 @@ value = checkcast; } } - WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation)); + WriteBarrierType barrierType = getArrayStoreBarrier(storeIndexed); + WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation, barrierType)); memoryWrite.dependencies().add(boundsCheck); memoryWrite.setStateAfter(storeIndexed.stateAfter()); graph.replaceFixedWithFixed(storeIndexed, memoryWrite); - if (elementKind == Kind.Object && !value.objectStamp().alwaysNull()) { - if (config.useG1GC) { - WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(array, null, arrayLocation, true)); - graph.addBeforeFixed(memoryWrite, writeBarrierPre); - WriteBarrierPost writeBarrierPost = graph.add(new WriteBarrierPost(array, value, arrayLocation, true)); - graph.addAfterFixed(memoryWrite, writeBarrierPost); - } else { - graph.addAfterFixed(memoryWrite, graph.add(new ArrayWriteBarrier(array, arrayLocation))); - } - } } else if (n instanceof UnsafeLoadNode) { UnsafeLoadNode load = (UnsafeLoadNode) n; assert load.kind() != Kind.Illegal; @@ -715,32 +635,11 @@ UnsafeStoreNode store = (UnsafeStoreNode) n; IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, store.accessKind(), store.displacement(), store.offset(), graph, 1); ValueNode object = store.object(); - WriteNode write = graph.add(new WriteNode(object, store.value(), location)); + WriteBarrierType barrierType = getUnsafeStoreBarrier(store); + WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType)); write.setStateAfter(store.stateAfter()); graph.replaceFixedWithFixed(store, write); - if (write.value().kind() == Kind.Object && !write.value().objectStamp().alwaysNull()) { - ResolvedJavaType type = object.objectStamp().type(); - // WriteBarrier writeBarrier; - if (type != null && !type.isArray() && !MetaUtil.isJavaLangObject(type)) { - // Use a field write barrier since it's not an array store - if (config.useG1GC) { - WriteBarrierPre writeBarrierPre = new WriteBarrierPre(object, null, location, true); - graph.addBeforeFixed(write, graph.add(writeBarrierPre)); - graph.addAfterFixed(write, graph.add(new WriteBarrierPost(object, write.value(), location, false))); - } else { - graph.addAfterFixed(write, graph.add(new FieldWriteBarrier(object))); - } - } else { - // This may be an array store so use an array write barrier - if (config.useG1GC) { - WriteBarrierPre writeBarrierPre = graph.add(new WriteBarrierPre(object, null, location, true)); - graph.addBeforeFixed(write, writeBarrierPre); - graph.addAfterFixed(write, graph.add(new WriteBarrierPost(object, write.value(), location, true))); - } else { - graph.addAfterFixed(write, graph.add(new ArrayWriteBarrier(object, location))); - } - } - } + } else if (n instanceof LoadHubNode) { LoadHubNode loadHub = (LoadHubNode) n; assert loadHub.kind() == wordKind; @@ -771,14 +670,10 @@ monitorSnippets.lower((MonitorEnterNode) n, tool); } else if (n instanceof MonitorExitNode) { monitorSnippets.lower((MonitorExitNode) n, tool); - } else if (n instanceof FieldWriteBarrier) { - writeBarrierSnippets.lower((FieldWriteBarrier) n, tool); - } else if (n instanceof ArrayWriteBarrier) { - writeBarrierSnippets.lower((ArrayWriteBarrier) n, tool); - } else if (n instanceof WriteBarrierPre) { - writeBarrierSnippets.lower((WriteBarrierPre) n, tool); - } else if (n instanceof WriteBarrierPost) { - writeBarrierSnippets.lower((WriteBarrierPost) n, tool); + } else if (n instanceof SerialWriteBarrier) { + writeBarrierSnippets.lower((SerialWriteBarrier) n, tool); + } else if (n instanceof SerialArrayRangeWriteBarrier) { + writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool); } else if (n instanceof TLABAllocateNode) { newObjectSnippets.lower((TLABAllocateNode) n, tool); } else if (n instanceof InitializeObjectNode) { @@ -787,17 +682,65 @@ newObjectSnippets.lower((InitializeArrayNode) n, tool); } else if (n instanceof NewMultiArrayNode) { newObjectSnippets.lower((NewMultiArrayNode) n, tool); + } else if (n instanceof LoadExceptionObjectNode) { + exceptionObjectSnippets.lower((LoadExceptionObjectNode) n); } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) { // Nothing to do for division nodes. The HotSpot signal handler catches divisions by // zero and the MIN_VALUE / -1 cases. - } else if (n instanceof UnwindNode || n instanceof ExceptionObjectNode) { + } else if (n instanceof UnwindNode || n instanceof DeoptimizeNode) { // Nothing to do, using direct LIR lowering for these nodes. + } else if (n instanceof BoxNode) { + boxingSnippets.lower((BoxNode) n); + } else if (n instanceof UnboxNode) { + boxingSnippets.lower((UnboxNode) n); } else { assert false : "Node implementing Lowerable not handled: " + n; throw GraalInternalError.shouldNotReachHere(); } } + private static WriteBarrierType getFieldStoreBarrier(StoreFieldNode storeField) { + WriteBarrierType barrierType = WriteBarrierType.NONE; + if (storeField.field().getKind() == Kind.Object && !storeField.value().objectStamp().alwaysNull()) { + barrierType = WriteBarrierType.IMPRECISE; + } + return barrierType; + } + + private static WriteBarrierType getArrayStoreBarrier(StoreIndexedNode store) { + WriteBarrierType barrierType = WriteBarrierType.NONE; + if (store.elementKind() == Kind.Object && !store.value().objectStamp().alwaysNull()) { + barrierType = WriteBarrierType.PRECISE; + } + return barrierType; + } + + private static WriteBarrierType getUnsafeStoreBarrier(UnsafeStoreNode store) { + WriteBarrierType barrierType = WriteBarrierType.NONE; + if (store.value().kind() == Kind.Object && !store.value().objectStamp().alwaysNull()) { + ResolvedJavaType type = store.object().objectStamp().type(); + if ((type != null && type.isArray() && !MetaUtil.isJavaLangObject(type))) { + barrierType = WriteBarrierType.PRECISE; + } else { + barrierType = WriteBarrierType.IMPRECISE; + } + } + return barrierType; + } + + private static WriteBarrierType getCompareAndSwapBarrier(CompareAndSwapNode cas) { + WriteBarrierType barrierType = WriteBarrierType.NONE; + if (cas.expected().kind() == Kind.Object && !cas.newValue().objectStamp().alwaysNull()) { + ResolvedJavaType type = cas.object().objectStamp().type(); + if ((type != null && type.isArray() && !MetaUtil.isJavaLangObject(type))) { + barrierType = WriteBarrierType.PRECISE; + } else { + barrierType = WriteBarrierType.IMPRECISE; + } + } + return barrierType; + } + private IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index) { int scale = this.graalRuntime.getTarget().sizeInBytes(elementKind); return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, getArrayBaseOffset(elementKind), index, graph, scale); @@ -827,8 +770,10 @@ } public HotSpotRuntimeCallTarget lookupRuntimeCall(Descriptor descriptor) { - assert runtimeCalls.containsKey(descriptor) : descriptor; - return runtimeCalls.get(descriptor); + HotSpotRuntimeCallTarget callTarget = runtimeCalls.get(descriptor); + assert runtimeCalls != null : descriptor; + callTarget.finalizeAddress(graalRuntime.getBackend()); + return callTarget; } public ResolvedJavaMethod lookupJavaMethod(Method reflectionMethod) { @@ -851,16 +796,21 @@ return graalRuntime.getCompilerToVM().getJavaField(reflectionField); } - public HotSpotInstalledCode installMethod(HotSpotResolvedJavaMethod method, int entryBCI, CompilationResult compResult) { - HotSpotInstalledCode installedCode = new HotSpotInstalledCode(method, true); + public HotSpotInstalledCode installMethod(HotSpotResolvedJavaMethod method, Graph graph, int entryBCI, CompilationResult compResult) { + HotSpotInstalledCode installedCode = new HotSpotInstalledCode(method, graph, true); graalRuntime.getCompilerToVM().installCode(new HotSpotCompilationResult(method, entryBCI, compResult), installedCode, method.getSpeculationLog()); return installedCode; } @Override public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult) { + return addMethod(method, compResult, null); + } + + @Override + public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, Graph graph) { HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method; - HotSpotInstalledCode code = new HotSpotInstalledCode(hotspotMethod, false); + HotSpotInstalledCode code = new HotSpotInstalledCode(hotspotMethod, graph, false); CodeInstallResult result = graalRuntime.getCompilerToVM().installCode(new HotSpotCompilationResult(hotspotMethod, -1, compResult), code, null); if (result != CodeInstallResult.OK) { return null; @@ -979,7 +929,7 @@ public String disassemble(InstalledCode code) { if (code.isValid()) { - long nmethod = ((HotSpotInstalledCode) code).nmethod; + long nmethod = ((HotSpotInstalledCode) code).getMethodAddress(); return graalRuntime.getCompilerToVM().disassembleNMethod(nmethod); } return null; diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedField.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedField.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotUnresolvedField.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.hotspot.meta; +import static com.oracle.graal.api.meta.MetaUtil.*; + import com.oracle.graal.api.meta.*; /** @@ -60,6 +62,6 @@ */ @Override public String toString() { - return MetaUtil.format("%H.%n [unresolved]", this); + return format("HotSpotField<%H.%n %t, unresolved>", this); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ArrayWriteBarrier.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ArrayWriteBarrier.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * 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. - */ -package com.oracle.graal.hotspot.nodes; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public final class ArrayWriteBarrier extends FixedWithNextNode implements Lowerable { - - @Input private ValueNode object; - @Input private LocationNode location; - - public ValueNode getObject() { - return object; - } - - public LocationNode getLocation() { - return location; - } - - public ArrayWriteBarrier(ValueNode object, LocationNode location) { - super(StampFactory.forVoid()); - this.object = object; - this.location = location; - } - - public void lower(LoweringTool generator) { - generator.getRuntime().lower(this, generator); - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -70,7 +70,6 @@ @Override public void generate(LIRGenerator gen) { assert lockDepth != -1; - assert stateAfter() != null; HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen; StackSlot slot = hsGen.getLockSlot(lockDepth); if (!eliminated) { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizingStubCall.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizingStubCall.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013, 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.graal.hotspot.nodes; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; + +public class DeoptimizingStubCall extends DeoptimizingFixedWithNextNode { + + public DeoptimizingStubCall(Stamp stamp) { + super(stamp); + } + + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public DeoptimizationReason getDeoptimizationReason() { + return null; + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/FieldWriteBarrier.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/FieldWriteBarrier.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * 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. - */ -package com.oracle.graal.hotspot.nodes; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -public final class FieldWriteBarrier extends FixedWithNextNode implements Lowerable { - - @Input private ValueNode object; - - public ValueNode getObject() { - return object; - } - - public FieldWriteBarrier(ValueNode object) { - super(StampFactory.forVoid()); - this.object = object; - } - - public void lower(LoweringTool generator) { - generator.getRuntime().lower(this, generator); - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotInstalledCodeExecuteNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -24,22 +24,24 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -import com.oracle.graal.word.*; +import com.oracle.graal.phases.common.*; public class HotSpotInstalledCodeExecuteNode extends AbstractCallNode implements Lowerable { - @Input private final ValueNode targetAddress; - @Input private final ValueNode metaspaceObject; + @Input private final ValueNode code; private final Class[] signature; - public HotSpotInstalledCodeExecuteNode(Kind kind, ValueNode targetAddress, ValueNode metaspaceObject, Class[] signature, ValueNode arg1, ValueNode arg2, ValueNode arg3) { + public HotSpotInstalledCodeExecuteNode(Kind kind, Class[] signature, ValueNode code, ValueNode arg1, ValueNode arg2, ValueNode arg3) { super(StampFactory.forKind(kind), new ValueNode[]{arg1, arg2, arg3}); - this.targetAddress = targetAddress; - this.metaspaceObject = metaspaceObject; + this.code = code; this.signature = signature; } @@ -50,30 +52,57 @@ @Override public void lower(LoweringTool tool) { - replaceWithInvoke(tool); + if (code.isConstant() && code.asConstant().asObject() instanceof HotSpotInstalledCode) { + HotSpotInstalledCode hsCode = (HotSpotInstalledCode) code.asConstant().asObject(); + InvokeNode invoke = replaceWithInvoke(tool.getRuntime()); + StructuredGraph graph = (StructuredGraph) hsCode.getGraph(); + if (graph != null) { + InliningUtil.inline(invoke, (StructuredGraph) hsCode.getGraph(), false); + } + } else { + replaceWithInvoke(tool.getRuntime()); + } } - private InvokeNode replaceWithInvoke(LoweringTool tool) { - InvokeNode invoke = createInvoke(tool); - ((StructuredGraph) graph()).replaceFixedWithFixed(this, invoke); - return invoke; - } - - protected InvokeNode createInvoke(LoweringTool tool) { + protected InvokeNode replaceWithInvoke(MetaAccessProvider tool) { ResolvedJavaMethod method = null; + ResolvedJavaField methodField = null; + ResolvedJavaField metaspaceMethodField = null; + ResolvedJavaField nmethodField = null; try { - method = tool.getRuntime().lookupJavaMethod(HotSpotInstalledCodeExecuteNode.class.getMethod("placeholder", Object.class, Object.class, Object.class)); - } catch (NoSuchMethodException | SecurityException e) { - throw new IllegalStateException(); + method = tool.lookupJavaMethod(HotSpotInstalledCodeExecuteNode.class.getMethod("placeholder", Object.class, Object.class, Object.class)); + methodField = tool.lookupJavaField(HotSpotInstalledCode.class.getDeclaredField("method")); + nmethodField = tool.lookupJavaField(HotSpotInstalledCode.class.getDeclaredField("nmethod")); + metaspaceMethodField = tool.lookupJavaField(HotSpotResolvedJavaMethod.class.getDeclaredField("metaspaceMethod")); + } catch (NoSuchMethodException | SecurityException | NoSuchFieldException e) { + throw new IllegalStateException(e); } ResolvedJavaType[] signatureTypes = new ResolvedJavaType[signature.length]; for (int i = 0; i < signature.length; i++) { - signatureTypes[i] = tool.getRuntime().lookupJavaType(signature[i]); + signatureTypes[i] = tool.lookupJavaType(signature[i]); } - HotSpotIndirectCallTargetNode callTarget = graph().add( - new HotSpotIndirectCallTargetNode(metaspaceObject, targetAddress, arguments, stamp(), signatureTypes, method, CallingConvention.Type.JavaCall)); - InvokeNode invoke = graph().add(new InvokeNode(callTarget, 0)); + final int verifiedEntryPointOffset = HotSpotSnippetUtils.verifiedEntryPointOffset(); + + StructuredGraph g = (StructuredGraph) graph(); + + LoadFieldNode loadnmethod = g.add(new LoadFieldNode(code, nmethodField)); + UnsafeLoadNode load = g.add(new UnsafeLoadNode(loadnmethod, verifiedEntryPointOffset, ConstantNode.forLong(0, graph()), HotSpotGraalRuntime.getInstance().getTarget().wordKind)); + + LoadFieldNode loadMethod = g.add(new LoadFieldNode(code, methodField)); + LoadFieldNode loadmetaspaceMethod = g.add(new LoadFieldNode(loadMethod, metaspaceMethodField)); + + HotSpotIndirectCallTargetNode callTarget = g.add(new HotSpotIndirectCallTargetNode(loadmetaspaceMethod, load, arguments, stamp(), signatureTypes, method, CallingConvention.Type.JavaCall)); + + InvokeNode invoke = g.add(new InvokeNode(callTarget, 0)); + invoke.setStateAfter(stateAfter()); + g.replaceFixedWithFixed(this, invoke); + + g.addBeforeFixed(invoke, loadmetaspaceMethod); + g.addBeforeFixed(loadmetaspaceMethod, loadMethod); + g.addBeforeFixed(invoke, load); + g.addBeforeFixed(load, loadnmethod); + return invoke; } @@ -82,6 +111,6 @@ } @NodeIntrinsic - public static native T call(@ConstantNodeParameter Kind kind, Word targetAddress, long metaspaceObject, @ConstantNodeParameter Class[] signature, Object arg1, Object arg2, Object arg3); + public static native T call(@ConstantNodeParameter Kind kind, @ConstantNodeParameter Class[] signature, Object code, Object arg1, Object arg2, Object arg3); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/IdentityHashCodeStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/IdentityHashCodeStubCall.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/IdentityHashCodeStubCall.java Mon Apr 15 08:51:19 2013 +0200 @@ -34,7 +34,7 @@ /** * Node implementing a call to HotSpot's {@code graal_identityhashcode} stub. */ -public class IdentityHashCodeStubCall extends FixedWithNextNode implements LIRGenLowerable { +public class IdentityHashCodeStubCall extends DeoptimizingStubCall implements LIRGenLowerable { @Input private final ValueNode object; public static final Descriptor IDENTITY_HASHCODE = new Descriptor("identity_hashcode", false, int.class, Object.class); @@ -47,7 +47,7 @@ @Override public void generate(LIRGenerator gen) { RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(IdentityHashCodeStubCall.IDENTITY_HASHCODE); - Variable result = gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(object)); + Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(object)); gen.setResult(this, result); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeArrayNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -23,7 +23,6 @@ package com.oracle.graal.hotspot.nodes; import com.oracle.graal.api.meta.*; -import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -75,7 +74,7 @@ public boolean fillContents() { // We fill contents when G1 GC is used since we want to record // the original field values prior to stores - return HotSpotSnippetUtils.useG1GC() ? true : fillContents; + return fillContents; } public boolean locked() { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeObjectNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeObjectNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/InitializeObjectNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -23,7 +23,6 @@ package com.oracle.graal.hotspot.nodes; import com.oracle.graal.api.meta.*; -import com.oracle.graal.hotspot.replacements.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -57,7 +56,7 @@ } public boolean fillContents() { - return HotSpotSnippetUtils.useG1GC() ? true : fillContents; + return fillContents; } public boolean locked() { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorEnterStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorEnterStubCall.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorEnterStubCall.java Mon Apr 15 08:51:19 2013 +0200 @@ -33,7 +33,7 @@ /** * Node implementing a call to HotSpot's {@code graal_monitorenter} stub. */ -public class MonitorEnterStubCall extends FixedWithNextNode implements LIRGenLowerable { +public class MonitorEnterStubCall extends DeoptimizingStubCall implements LIRGenLowerable { @Input private final ValueNode object; @Input private final ValueNode lock; @@ -48,7 +48,7 @@ @Override public void generate(LIRGenerator gen) { RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(MonitorEnterStubCall.MONITORENTER); - gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(object), gen.operand(lock)); + gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(object), gen.operand(lock)); } @NodeIntrinsic diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorExitStubCall.java Mon Apr 15 08:51:19 2013 +0200 @@ -35,7 +35,7 @@ /** * Node implementing a call to HotSpot's {@code graal_monitorexit} stub. */ -public class MonitorExitStubCall extends FixedWithNextNode implements LIRGenLowerable, MonitorReference { +public class MonitorExitStubCall extends DeoptimizingStubCall implements LIRGenLowerable, MonitorReference { @Input private final ValueNode object; private int lockDepth; @@ -60,7 +60,7 @@ HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen; StackSlot slot = hsGen.getLockSlot(lockDepth); RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(MonitorExitStubCall.MONITOREXIT); - gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(object), gen.emitLea(slot)); + gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(object), gen.emitLea(slot)); } @NodeIntrinsic diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArraySlowStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArraySlowStubCall.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArraySlowStubCall.java Mon Apr 15 08:51:19 2013 +0200 @@ -35,7 +35,7 @@ /** * Node implementing a call to the {@code new_array} stub. */ -public class NewArraySlowStubCall extends FixedWithNextNode implements LIRGenLowerable { +public class NewArraySlowStubCall extends DeoptimizingStubCall implements LIRGenLowerable { private static final Stamp defaultStamp = StampFactory.objectNonNull(); @@ -62,7 +62,7 @@ @Override public void generate(LIRGenerator gen) { RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_ARRAY_SLOW); - Variable result = gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(hub), gen.operand(length)); + Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub), gen.operand(length)); gen.setResult(this, result); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java Mon Apr 15 08:51:19 2013 +0200 @@ -36,7 +36,7 @@ /** * A call to the {@link NewArrayStub}. */ -public class NewArrayStubCall extends FixedWithNextNode implements LIRGenLowerable { +public class NewArrayStubCall extends DeoptimizingStubCall implements LIRGenLowerable { private static final Stamp defaultStamp = StampFactory.objectNonNull(); @@ -63,7 +63,7 @@ @Override public void generate(LIRGenerator gen) { RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_ARRAY); - Variable result = gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(hub), gen.operand(length)); + Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub), gen.operand(length)); gen.setResult(this, result); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceSlowStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceSlowStubCall.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceSlowStubCall.java Mon Apr 15 08:51:19 2013 +0200 @@ -35,7 +35,7 @@ /** * Node implementing a call to HotSpot's {@code new_instance} stub. */ -public class NewInstanceSlowStubCall extends FixedWithNextNode implements LIRGenLowerable { +public class NewInstanceSlowStubCall extends DeoptimizingStubCall implements LIRGenLowerable { private static final Stamp defaultStamp = StampFactory.objectNonNull(); @@ -60,7 +60,7 @@ @Override public void generate(LIRGenerator gen) { RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_INSTANCE_SLOW); - Variable result = gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(hub)); + Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub)); gen.setResult(this, result); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java Mon Apr 15 08:51:19 2013 +0200 @@ -36,7 +36,7 @@ /** * A call to the {@link NewInstanceStub}. */ -public class NewInstanceStubCall extends FixedWithNextNode implements LIRGenLowerable { +public class NewInstanceStubCall extends DeoptimizingStubCall implements LIRGenLowerable { private static final Stamp defaultStamp = StampFactory.objectNonNull(); @@ -61,7 +61,7 @@ @Override public void generate(LIRGenerator gen) { RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NEW_INSTANCE); - Variable result = gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(hub)); + Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub)); gen.setResult(this, result); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java Mon Apr 15 08:51:19 2013 +0200 @@ -36,7 +36,7 @@ /** * Node implementing a call to HotSpot's {@code new_multi_array} stub. */ -public class NewMultiArrayStubCall extends FixedWithNextNode implements LIRGenLowerable { +public class NewMultiArrayStubCall extends DeoptimizingStubCall implements LIRGenLowerable { private static final Stamp defaultStamp = StampFactory.objectNonNull(); @@ -65,7 +65,7 @@ @Override public void generate(LIRGenerator gen) { RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(NewMultiArrayStubCall.NEW_MULTI_ARRAY); - Variable result = gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(hub), Constant.forInt(rank), gen.operand(dims)); + Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(hub), Constant.forInt(rank), gen.operand(dims)); gen.setResult(this, result); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -69,7 +69,7 @@ parameters.add(frameState.localAt(slot)); } Value[] args = gen.visitInvokeArguments(cc, parameters); - Value entry = gen.emitLoad(Kind.Long, gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0, false); + Value entry = gen.emitLoad(Kind.Long, gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0, null); HotSpotLIRGenerator hsgen = (HotSpotLIRGenerator) gen; hsgen.emitTailcall(args, entry); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ThreadIsInterruptedStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ThreadIsInterruptedStubCall.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ThreadIsInterruptedStubCall.java Mon Apr 15 08:51:19 2013 +0200 @@ -37,7 +37,7 @@ /** * Node implementing a call to HotSpot's ThreadIsInterrupted stub. */ -public class ThreadIsInterruptedStubCall extends FixedWithNextNode implements LIRGenLowerable { +public class ThreadIsInterruptedStubCall extends DeoptimizingStubCall implements LIRGenLowerable { @Input private final ValueNode thread; @Input private final ValueNode clearIsInterrupted; @@ -52,7 +52,7 @@ @Override public void generate(LIRGenerator gen) { RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(ThreadIsInterruptedStubCall.THREAD_IS_INTERRUPTED); - Variable result = gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(thread), gen.operand(clearIsInterrupted)); + Variable result = gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(thread), gen.operand(clearIsInterrupted)); gen.setResult(this, result); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -28,7 +28,6 @@ import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.replacements.*; @@ -51,15 +50,7 @@ @Override public void generate(LIRGenerator gen) { - String where; - try { - LIRFrameState state = gen.state(); - BytecodePosition pos = state.topFrame; - where = "near or " + CodeUtil.append(new StringBuilder(100), pos).toString().replace(CodeUtil.NEW_LINE, CodeUtil.NEW_LINE + "\t"); - } catch (Throwable t) { - // Report a less accurate location when debug info cannot be obtained - where = "in compiled code for " + MetaUtil.format("%H.%n(%p)", gen.method()); - } + String where = "in compiled code for " + MetaUtil.format("%H.%n(%p)", gen.method()); HotSpotRuntime runtime = (HotSpotRuntime) gen.getRuntime(); Constant whereArg = Constant.forObject(runtime.registerGCRoot(where)); @@ -71,7 +62,7 @@ } RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(VMErrorNode.VM_ERROR); - gen.emitCall(stub, stub.getCallingConvention(), false, whereArg, formatArg, gen.operand(value)); + gen.emitCall(stub, stub.getCallingConvention(), null, whereArg, formatArg, gen.operand(value)); } @NodeIntrinsic diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VerifyOopStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VerifyOopStubCall.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VerifyOopStubCall.java Mon Apr 15 08:51:19 2013 +0200 @@ -32,7 +32,7 @@ /** * Node implementing a call to HotSpot's object pointer verification stub. */ -public class VerifyOopStubCall extends FixedWithNextNode implements LIRGenLowerable { +public class VerifyOopStubCall extends DeoptimizingStubCall implements LIRGenLowerable { @Input private final ValueNode object; public static final Descriptor VERIFY_OOP = new Descriptor("verify_oop", false, void.class, Object.class); @@ -45,7 +45,7 @@ @Override public void generate(LIRGenerator gen) { RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(VerifyOopStubCall.VERIFY_OOP); - gen.emitCall(stub, stub.getCallingConvention(), true, gen.operand(object)); + gen.emitCall(stub, stub.getCallingConvention(), this, gen.operand(object)); } @NodeIntrinsic diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPostStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPostStubCall.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPostStubCall.java Mon Apr 15 08:51:19 2013 +0200 @@ -48,7 +48,7 @@ @Override public void generate(LIRGenerator gen) { RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(WriteBarrierPostStubCall.WBPOSTCALL); - gen.emitCall(stub, stub.getCallingConvention(), false, gen.operand(object), gen.operand(card)); + gen.emitCall(stub, stub.getCallingConvention(), null, gen.operand(object), gen.operand(card)); } @NodeIntrinsic diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPreStubCall.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPreStubCall.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrierPreStubCall.java Mon Apr 15 08:51:19 2013 +0200 @@ -45,7 +45,7 @@ @Override public void generate(LIRGenerator gen) { RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(WriteBarrierPreStubCall.WBPRECALL); - gen.emitCall(stub, stub.getCallingConvention(), false, gen.operand(object)); + gen.emitCall(stub, stub.getCallingConvention(), null, gen.operand(object)); } @NodeIntrinsic diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013, 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.graal.hotspot.phases; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.WriteNode.WriteBarrierType; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; + +public class WriteBarrierAdditionPhase extends Phase { + + public WriteBarrierAdditionPhase() { + } + + @Override + protected void run(StructuredGraph graph) { + for (WriteNode node : graph.getNodes(WriteNode.class)) { + addWriteNodeBarriers(node, graph); + } + for (CompareAndSwapNode node : graph.getNodes(CompareAndSwapNode.class)) { + addCASBarriers(node, graph); + } + for (GenericArrayRangeWriteBarrier node : graph.getNodes(GenericArrayRangeWriteBarrier.class)) { + addArrayRangeBarriers(node, graph); + } + } + + private static void addWriteNodeBarriers(WriteNode node, StructuredGraph graph) { + WriteBarrierType barrierType = node.getWriteBarrierType(); + if (barrierType == WriteBarrierType.PRECISE) { + graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(node.object(), node.location(), true))); + } else if (barrierType == WriteBarrierType.IMPRECISE) { + graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(node.object(), node.location(), false))); + } else { + assert barrierType == WriteBarrierType.NONE; + } + + } + + private static void addCASBarriers(CompareAndSwapNode node, StructuredGraph graph) { + WriteBarrierType barrierType = node.getWriteBarrierType(); + if (barrierType == WriteBarrierType.PRECISE) { + LocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, node.expected().kind(), node.displacement(), node.offset(), graph, 1); + graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(node.object(), location, true))); + } else if (barrierType == WriteBarrierType.IMPRECISE) { + LocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, node.expected().kind(), node.displacement(), node.offset(), graph, 1); + graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(node.object(), location, false))); + } else { + assert barrierType == WriteBarrierType.NONE; + } + } + + private static void addArrayRangeBarriers(GenericArrayRangeWriteBarrier node, StructuredGraph graph) { + SerialArrayRangeWriteBarrier serialArrayRangeWriteBarrier = graph.add(new SerialArrayRangeWriteBarrier(node.getDstObject(), node.getDstPos(), node.getLength())); + graph.replaceFixedWithFixed(node, serialArrayRangeWriteBarrier); + } + +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Mon Apr 15 08:51:19 2013 +0200 @@ -69,7 +69,7 @@ } private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt) { - Word kAddr = Word.fromObject(rcvr).readWord(Word.unsigned(kOffset), UNKNOWN_LOCATION).add(arrayBaseOffset(Kind.Byte)); + Word kAddr = Word.fromObject(rcvr).readWord(Word.unsigned(kOffset), ANY_LOCATION).add(arrayBaseOffset(Kind.Byte)); Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset); Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset); if (encrypt) { @@ -98,7 +98,7 @@ @Override public void generate(LIRGenerator gen) { RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(descriptor); - gen.emitCall(stub, stub.getCallingConvention(), false, gen.operand(in), gen.operand(out), gen.operand(key)); + gen.emitCall(stub, stub.getCallingConvention(), null, gen.operand(in), gen.operand(out), gen.operand(key)); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -31,7 +31,7 @@ import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; -import com.oracle.graal.replacements.*; +import com.oracle.graal.phases.tiers.*; import com.oracle.graal.replacements.nodes.*; public class ArrayCopyNode extends MacroNode implements Virtualizable, IterableNodeType, Lowerable { @@ -60,7 +60,7 @@ return arguments.get(4); } - private StructuredGraph selectSnippet(LoweringTool tool) { + private StructuredGraph selectSnippet(LoweringTool tool, Replacements replacements) { ResolvedJavaType srcType = getSource().objectStamp().type(); ResolvedJavaType destType = getDestination().objectStamp().type(); @@ -72,7 +72,7 @@ } Kind componentKind = srcType.getComponentType().getKind(); ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind)); - return (StructuredGraph) snippetMethod.getCompilerStorage().get(Snippet.class); + return replacements.getSnippet(snippetMethod); } private static void unrollFixedLengthLoop(StructuredGraph snippetGraph, int length, LoweringTool tool) { @@ -82,9 +82,10 @@ } // the canonicalization before loop unrolling is needed to propagate the length into // additions, etc. - new CanonicalizerPhase(tool.getRuntime(), tool.assumptions()).apply(snippetGraph); - new LoopFullUnrollPhase(tool.getRuntime(), tool.assumptions()).apply(snippetGraph); - new CanonicalizerPhase(tool.getRuntime(), tool.assumptions()).apply(snippetGraph); + HighTierContext context = new HighTierContext(tool.getRuntime(), tool.assumptions()); + new CanonicalizerPhase().apply(snippetGraph, context); + new LoopFullUnrollPhase().apply(snippetGraph, context); + new CanonicalizerPhase().apply(snippetGraph, context); } @Override @@ -93,12 +94,11 @@ return null; } - StructuredGraph snippetGraph = selectSnippet(tool); + Replacements replacements = tool.getReplacements(); + StructuredGraph snippetGraph = selectSnippet(tool, replacements); if (snippetGraph == null) { ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.genericArraycopySnippet); - snippetGraph = ((StructuredGraph) snippetMethod.getCompilerStorage().get(Snippet.class)).copy(); - assert snippetGraph != null : "ArrayCopySnippets should be installed"; - + snippetGraph = replacements.getSnippet(snippetMethod).copy(); replaceSnippetInvokes(snippetGraph); } else { assert snippetGraph != null : "ArrayCopySnippets should be installed"; diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopySnippets.java Mon Apr 15 08:51:19 2013 +0200 @@ -37,7 +37,6 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.Snippet.*; import com.oracle.graal.replacements.nodes.*; import com.oracle.graal.word.*; @@ -75,7 +74,7 @@ private static final Kind VECTOR_KIND = Kind.Long; private static final long VECTOR_SIZE = arrayIndexScale(Kind.Long); - public static void vectorizedCopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter("baseKind") Kind baseKind) { + private static void vectorizedCopy(Object src, int srcPos, Object dest, int destPos, int length, Kind baseKind) { checkNonNull(src); checkNonNull(dest); checkLimits(src, srcPos, dest, destPos, length); @@ -236,9 +235,14 @@ } } + @Snippet + public static void arraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length) { + arrayObjectCopy(src, srcPos, dest, destPos, length); + } + // Does NOT perform store checks @Snippet - public static void arraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length) { + public static void arrayObjectCopy(Object src, int srcPos, Object dest, int destPos, int length) { objectCounter.inc(); checkNonNull(src); checkNonNull(dest); @@ -260,15 +264,7 @@ } } if (length > 0) { - int cardShift = cardTableShift(); - long cardStart = cardTableStart(); - long dstAddr = GetObjectAddressNode.get(dest); - long start = (dstAddr + header + (long) destPos * scale) >>> cardShift; - long end = (dstAddr + header + ((long) destPos + length - 1) * scale) >>> cardShift; - long count = end - start + 1; - while (count-- > 0) { - DirectStoreNode.store((start + cardStart) + count, false, Kind.Boolean); - } + GenericArrayRangeWriteBarrier.insertWriteBarrier(dest, destPos, length); } } @@ -278,14 +274,22 @@ // loading the hubs also checks for nullness Word srcHub = loadHub(src); Word destHub = loadHub(dest); + int layoutHelper = checkArrayType(srcHub); + int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); + final boolean isObjectArray = ((layoutHelper & layoutHelperElementTypePrimitiveInPlace()) == 0); - int layoutHelper = checkArrayType(srcHub); if (srcHub.equal(destHub) && src != dest) { probability(FAST_PATH_PROBABILITY); checkLimits(src, srcPos, dest, destPos, length); - - arraycopyInnerloop(src, srcPos, dest, destPos, length, layoutHelper); + if (isObjectArray) { + genericObjectExactCallCounter.inc(); + probability(FAST_PATH_PROBABILITY); + arrayObjectCopy(src, srcPos, dest, destPos, length); + } else { + genericPrimitiveCallCounter.inc(); + arraycopyInnerloop(src, srcPos, dest, destPos, length, layoutHelper); + } } else { genericObjectCallCounter.inc(); System.arraycopy(src, srcPos, dest, destPos, length); @@ -308,34 +312,15 @@ Word destNonVectorEnd = destStart.add(nonVectorBytes); while (destOffset.belowThan(destNonVectorEnd)) { - destOffset.writeByte(0, srcOffset.readByte(0, UNKNOWN_LOCATION), ANY_LOCATION); + destOffset.writeByte(0, srcOffset.readByte(0, ANY_LOCATION), ANY_LOCATION); destOffset = destOffset.add(1); srcOffset = srcOffset.add(1); } while (destOffset.belowThan(destEnd)) { - destOffset.writeWord(0, srcOffset.readWord(0, UNKNOWN_LOCATION), ANY_LOCATION); + destOffset.writeWord(0, srcOffset.readWord(0, ANY_LOCATION), ANY_LOCATION); destOffset = destOffset.add(wordSize()); srcOffset = srcOffset.add(wordSize()); } - - if ((layoutHelper & layoutHelperElementTypePrimitiveInPlace()) != 0) { - genericPrimitiveCallCounter.inc(); - - } else { - probability(LIKELY_PROBABILITY); - genericObjectExactCallCounter.inc(); - - if (length > 0) { - int cardShift = cardTableShift(); - long cardStart = cardTableStart(); - Word destCardOffset = destStart.unsignedShiftRight(cardShift).add(Word.unsigned(cardStart)); - Word destCardEnd = destEnd.subtract(1).unsignedShiftRight(cardShift).add(Word.unsigned(cardStart)); - while (destCardOffset.belowOrEqual(destCardEnd)) { - DirectStoreNode.store(destCardOffset.rawValue(), false, Kind.Boolean); - destCardOffset = destCardOffset.add(1); - } - } - } } private static final SnippetCounter.Group checkCounters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("System.arraycopy checkInputs") : null; diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteSubstitutions.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,64 @@ +/* + * 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.graal.hotspot.replacements; + +import java.lang.invoke.*; + +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.*; + +@ServiceProvider(ReplacementsProvider.class) +public class CallSiteSubstitutions implements ReplacementsProvider { + + @Override + public void registerReplacements(Replacements replacements) { + if (GraalOptions.IntrinsifyCallSiteTarget) { + replacements.registerSubstitutions(ConstantCallSiteSubstitutions.class); + replacements.registerSubstitutions(MutableCallSiteSubstitutions.class); + replacements.registerSubstitutions(VolatileCallSiteSubstitutions.class); + } + } + + @ClassSubstitution(ConstantCallSite.class) + private static class ConstantCallSiteSubstitutions { + + @MacroSubstitution(isStatic = false, macro = CallSiteTargetNode.class) + public static native MethodHandle getTarget(ConstantCallSite callSite); + } + + @ClassSubstitution(MutableCallSite.class) + private static class MutableCallSiteSubstitutions { + + @MacroSubstitution(isStatic = false, macro = CallSiteTargetNode.class) + public static native MethodHandle getTarget(MutableCallSite callSite); + } + + @ClassSubstitution(VolatileCallSite.class) + private static class VolatileCallSiteSubstitutions { + + @MacroSubstitution(isStatic = false, macro = CallSiteTargetNode.class) + public static native MethodHandle getTarget(VolatileCallSite callSite); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,78 @@ +/* + * 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.graal.hotspot.replacements; + +import java.lang.invoke.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.replacements.nodes.*; + +public class CallSiteTargetNode extends MacroNode implements Canonicalizable, Lowerable { + + public CallSiteTargetNode(Invoke invoke) { + super(invoke); + } + + private ValueNode getCallSite() { + return arguments.get(0); + } + + private ConstantNode getConstantCallTarget(MetaAccessProvider metaAccessProvider, Assumptions assumptions) { + if (getCallSite().isConstant() && !getCallSite().isNullConstant()) { + CallSite callSite = (CallSite) getCallSite().asConstant().asObject(); + if (callSite instanceof ConstantCallSite) { + return ConstantNode.forObject(callSite.getTarget(), metaAccessProvider, graph()); + } else if (callSite instanceof MutableCallSite || callSite instanceof VolatileCallSite && assumptions != null && assumptions.useOptimisticAssumptions()) { + MethodHandle target = callSite.getTarget(); + assumptions.record(new Assumptions.CallSiteTargetValue(callSite, target)); + return ConstantNode.forObject(target, metaAccessProvider, graph()); + } + } + return null; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + ConstantNode target = getConstantCallTarget(tool.runtime(), tool.assumptions()); + if (target != null) { + return target; + } + + return this; + } + + @Override + public void lower(LoweringTool tool) { + StructuredGraph graph = (StructuredGraph) graph(); + ConstantNode target = getConstantCallTarget(tool.getRuntime(), tool.assumptions()); + + if (target != null) { + graph.replaceFixedWithFloating(this, target); + } else { + graph.replaceFixedWithFixed(this, createInvoke()); + } + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastSnippets.java Mon Apr 15 08:51:19 2013 +0200 @@ -28,11 +28,9 @@ import static com.oracle.graal.hotspot.replacements.TypeCheckSnippetUtils.*; import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; import static com.oracle.graal.replacements.SnippetTemplate.*; -import static com.oracle.graal.replacements.SnippetTemplate.Arguments.*; import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.hotspot.meta.*; @@ -42,7 +40,11 @@ import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.Snippet.ConstantParameter; +import com.oracle.graal.replacements.Snippet.VarargsParameter; +import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; import com.oracle.graal.replacements.nodes.*; import com.oracle.graal.word.*; @@ -58,16 +60,11 @@ @NodeIntrinsic(BreakpointNode.class) static native void bkpt(Object object, Word hub, Word objectHub); - // @formatter:off - /** * Type test used when the type being tested against is a final type. */ @Snippet - public static Object checkcastExact( - @Parameter("object") Object object, - @Parameter("exactHub") Word exactHub, - @ConstantParameter("checkNull") boolean checkNull) { + public static Object checkcastExact(Object object, Word exactHub, @ConstantParameter boolean checkNull) { if (checkNull && object == null) { probability(NOT_FREQUENT_PROBABILITY); isNull.inc(); @@ -76,30 +73,25 @@ if (objectHub.notEqual(exactHub)) { probability(DEOPT_PATH_PROBABILITY); exactMiss.inc(); - //bkpt(object, exactHub, objectHub); DeoptimizeNode.deopt(InvalidateReprofile, ClassCastException); } exactHit.inc(); } - /* make sure that the unsafeCast is done *after* the check above, - * cf. ReadAfterCheckCast */ + /* + * make sure that the unsafeCast is done *after* the check above, cf. ReadAfterCheckCast + */ BeginNode anchorNode = BeginNode.anchor(StampFactory.forNodeIntrinsic()); return unsafeCast(verifyOop(object), StampFactory.forNodeIntrinsic(), anchorNode); } /** * Type test used when the type being tested against is a restricted primary type. - * - * This test ignores use of hints altogether as the display-based type check only - * involves one extra load where the second load should hit the same cache line as the - * first. + * + * This test ignores use of hints altogether as the display-based type check only involves one + * extra load where the second load should hit the same cache line as the first. */ @Snippet - public static Object checkcastPrimary( - @Parameter("hub") Word hub, - @Parameter("object") Object object, - @ConstantParameter("checkNull") boolean checkNull, - @ConstantParameter("superCheckOffset") int superCheckOffset) { + public static Object checkcastPrimary(Word hub, Object object, @ConstantParameter int superCheckOffset, @ConstantParameter boolean checkNull) { if (checkNull && object == null) { probability(NOT_FREQUENT_PROBABILITY); isNull.inc(); @@ -120,11 +112,7 @@ * Type test used when the type being tested against is a restricted secondary type. */ @Snippet - public static Object checkcastSecondary( - @Parameter("hub") Word hub, - @Parameter("object") Object object, - @VarargsParameter("hints") Word[] hints, - @ConstantParameter("checkNull") boolean checkNull) { + public static Object checkcastSecondary(Word hub, Object object, @VarargsParameter Word[] hints, @ConstantParameter boolean checkNull) { if (checkNull && object == null) { probability(NOT_FREQUENT_PROBABILITY); isNull.inc(); @@ -149,14 +137,11 @@ } /** - * Type test used when the type being tested against is not known at compile time (e.g. the type test - * in an object array store check). + * Type test used when the type being tested against is not known at compile time (e.g. the type + * test in an object array store check). */ @Snippet - public static Object checkcastDynamic( - @Parameter("hub") Word hub, - @Parameter("object") Object object, - @ConstantParameter("checkNull") boolean checkNull) { + public static Object checkcastDynamic(Word hub, Object object, @ConstantParameter boolean checkNull) { if (checkNull && object == null) { probability(NOT_FREQUENT_PROBABILITY); isNull.inc(); @@ -170,21 +155,15 @@ return unsafeCast(verifyOop(object), StampFactory.forNodeIntrinsic(), anchorNode); } - // @formatter:on - - public static class Templates extends AbstractTemplates { + public static class Templates extends AbstractTemplates { - private final ResolvedJavaMethod exact; - private final ResolvedJavaMethod primary; - private final ResolvedJavaMethod secondary; - private final ResolvedJavaMethod dynamic; + private final SnippetInfo exact = snippet(CheckCastSnippets.class, "checkcastExact"); + private final SnippetInfo primary = snippet(CheckCastSnippets.class, "checkcastPrimary"); + private final SnippetInfo secondary = snippet(CheckCastSnippets.class, "checkcastSecondary"); + private final SnippetInfo dynamic = snippet(CheckCastSnippets.class, "checkcastDynamic"); - public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) { - super(runtime, assumptions, target, CheckCastSnippets.class); - exact = snippet("checkcastExact", Object.class, Word.class, boolean.class); - primary = snippet("checkcastPrimary", Word.class, Object.class, boolean.class, int.class); - secondary = snippet("checkcastSecondary", Word.class, Object.class, Word[].class, boolean.class); - dynamic = snippet("checkcastDynamic", Word.class, Object.class, boolean.class); + public Templates(CodeCacheProvider runtime, Replacements replacements, TargetDescription target) { + super(runtime, replacements, target); } /** @@ -193,31 +172,34 @@ public void lower(CheckCastNode checkcast, LoweringTool tool) { StructuredGraph graph = (StructuredGraph) checkcast.graph(); ValueNode object = checkcast.object(); - final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) checkcast.type(); + HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) checkcast.type(); TypeCheckHints hintInfo = new TypeCheckHints(checkcast.type(), checkcast.profile(), tool.assumptions(), GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints); ValueNode hub = ConstantNode.forConstant(type.klass(), runtime, checkcast.graph()); - boolean checkNull = !object.stamp().nonNull(); - Arguments arguments; - Key key; - assert type != null; + Arguments args; if (hintInfo.exact) { - ConstantNode[] hints = createHints(hintInfo, runtime, graph); + ConstantNode[] hints = createHints(hintInfo, runtime, true, graph).hubs; assert hints.length == 1; - key = new Key(exact).add("checkNull", checkNull); - arguments = arguments("object", object).add("exactHub", hints[0]); + args = new Arguments(exact); + args.add("object", object); + args.add("exactHub", hints[0]); } else if (type.isPrimaryType()) { - key = new Key(primary).add("checkNull", checkNull).add("superCheckOffset", type.superCheckOffset()); - arguments = arguments("hub", hub).add("object", object); + args = new Arguments(primary); + args.add("hub", hub); + args.add("object", object); + args.addConst("superCheckOffset", type.superCheckOffset()); } else { - ConstantNode[] hints = createHints(hintInfo, runtime, graph); - key = new Key(secondary).add("hints", Varargs.vargargs(new Word[hints.length], StampFactory.forKind(wordKind()))).add("checkNull", checkNull); - arguments = arguments("hub", hub).add("object", object).add("hints", hints); + ConstantNode[] hints = createHints(hintInfo, runtime, true, graph).hubs; + args = new Arguments(secondary); + args.add("hub", hub); + args.add("object", object); + args.addVarargs("hints", Word.class, StampFactory.forKind(wordKind()), hints); } + args.addConst("checkNull", !object.stamp().nonNull()); - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering checkcast in %s: node=%s, template=%s, arguments=%s", graph, checkcast, template, arguments); - template.instantiate(runtime, checkcast, DEFAULT_REPLACER, arguments); + SnippetTemplate template = template(args); + Debug.log("Lowering checkcast in %s: node=%s, template=%s, arguments=%s", graph, checkcast, template, args); + template.instantiate(runtime, checkcast, DEFAULT_REPLACER, args); } /** @@ -225,16 +207,16 @@ */ public void lower(CheckCastDynamicNode checkcast) { StructuredGraph graph = (StructuredGraph) checkcast.graph(); - ValueNode hub = checkcast.type(); ValueNode object = checkcast.object(); - boolean checkNull = !object.stamp().nonNull(); - Key key = new Key(dynamic).add("checkNull", checkNull); - Arguments arguments = arguments("hub", hub).add("object", object); + Arguments args = new Arguments(dynamic); + args.add("hub", checkcast.type()); + args.add("object", object); + args.addConst("checkNull", !object.stamp().nonNull()); - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering dynamic checkcast in %s: node=%s, template=%s, arguments=%s", graph, checkcast, template, arguments); - template.instantiate(runtime, checkcast, DEFAULT_REPLACER, arguments); + SnippetTemplate template = template(args); + Debug.log("Lowering dynamic checkcast in %s: node=%s, template=%s, arguments=%s", graph, checkcast, template, args); + template.instantiate(runtime, checkcast, DEFAULT_REPLACER, args); } } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Mon Apr 15 08:51:19 2013 +0200 @@ -65,7 +65,7 @@ @MethodSubstitution(isStatic = false) static void encrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { - Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset), UNKNOWN_LOCATION); + Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset), ANY_LOCATION); if (getAESCryptClass().isInstance(embeddedCipher)) { crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, true); } else { @@ -74,8 +74,8 @@ } private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt) { - Word kAddr = Word.fromObject(embeddedCipher).readWord(Word.unsigned(AESCryptSubstitutions.kOffset), UNKNOWN_LOCATION).add(arrayBaseOffset(Kind.Byte)); - Word rAddr = Word.unsigned(GetObjectAddressNode.get(rcvr)).readWord(Word.unsigned(rOffset), UNKNOWN_LOCATION).add(arrayBaseOffset(Kind.Byte)); + Word kAddr = Word.fromObject(embeddedCipher).readWord(Word.unsigned(AESCryptSubstitutions.kOffset), ANY_LOCATION).add(arrayBaseOffset(Kind.Byte)); + Word rAddr = Word.unsigned(GetObjectAddressNode.get(rcvr)).readWord(Word.unsigned(rOffset), ANY_LOCATION).add(arrayBaseOffset(Kind.Byte)); Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset); Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset); if (encrypt) { @@ -88,7 +88,7 @@ @MethodSubstitution(isStatic = false) static void decrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { - Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset), UNKNOWN_LOCATION); + Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset), ANY_LOCATION); if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, false); } else { @@ -119,7 +119,7 @@ @Override public void generate(LIRGenerator gen) { RuntimeCallTarget stub = gen.getRuntime().lookupRuntimeCall(descriptor); - gen.emitCall(stub, stub.getCallingConvention(), false, gen.operand(in), gen.operand(out), gen.operand(key), gen.operand(r), gen.operand(inLength)); + gen.emitCall(stub, stub.getCallingConvention(), null, gen.operand(in), gen.operand(out), gen.operand(key), gen.operand(r), gen.operand(inLength)); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotInstalledCodeIntrinsics.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotInstalledCodeIntrinsics.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotInstalledCodeIntrinsics.java Mon Apr 15 08:51:19 2013 +0200 @@ -23,16 +23,16 @@ package com.oracle.graal.hotspot.replacements; import com.oracle.graal.api.runtime.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; -import com.oracle.graal.replacements.*; @ServiceProvider(ReplacementsProvider.class) public class HotSpotInstalledCodeIntrinsics implements ReplacementsProvider { @Override - public void installReplacements(ReplacementsInstaller installer) { + public void registerReplacements(Replacements replacements) { if (GraalOptions.IntrinsifyInstalledCodeMethods) { - installer.installSubstitutions(HotSpotInstalledCodeSubstitutions.class); + replacements.registerSubstitutions(HotSpotInstalledCodeSubstitutions.class); } } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotInstalledCodeSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotInstalledCodeSubstitutions.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotInstalledCodeSubstitutions.java Mon Apr 15 08:51:19 2013 +0200 @@ -27,20 +27,18 @@ import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.replacements.Snippet.Fold; -import com.oracle.graal.word.*; @ClassSubstitution(HotSpotInstalledCode.class) public class HotSpotInstalledCodeSubstitutions { - @MethodSubstitution - public static Object executeHelper(long nmethod, long metaspaceMethod, final Object arg1, final Object arg2, final Object arg3) { - final int verifiedEntryPointOffset = HotSpotSnippetUtils.verifiedEntryPointOffset(); - final Word callTarget = Word.unsigned(nmethod).readWord(verifiedEntryPointOffset); - return HotSpotInstalledCodeExecuteNode.call(Kind.Object, callTarget, metaspaceMethod, getSignature(), arg1, arg2, arg3); + @MethodSubstitution(isStatic = false) + public static Object execute(HotSpotInstalledCode code, final Object arg1, final Object arg2, final Object arg3) { + return HotSpotInstalledCodeExecuteNode.call(Kind.Object, getSignature(), code, arg1, arg2, arg3); } @Fold private static Class[] getSignature() { return new Class[]{Object.class, Object.class, Object.class}; } + } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSnippetUtils.java Mon Apr 15 08:51:19 2013 +0200 @@ -46,7 +46,6 @@ public class HotSpotSnippetUtils { public static final Object ANY_LOCATION = LocationNode.ANY_LOCATION; - public static final Object UNKNOWN_LOCATION = LocationNode.UNKNOWN_LOCATION; public static final Object FINAL_LOCATION = LocationNode.FINAL_LOCATION; public static HotSpotVMConfig config() { @@ -63,6 +62,20 @@ return config().verifyOops; } + public static final Object EXCEPTION_OOP_LOCATION = LocationNode.createLocation("ExceptionOop"); + + @Fold + public static int threadExceptionOopOffset() { + return config().threadExceptionOopOffset; + } + + public static final Object EXCEPTION_PC_LOCATION = LocationNode.createLocation("ExceptionPc"); + + @Fold + public static int threadExceptionPcOffset() { + return config().threadExceptionPcOffset; + } + public static final Object TLAB_TOP_LOCATION = LocationNode.createLocation("TlabTop"); @Fold @@ -84,6 +97,18 @@ return config().threadTlabStartOffset; } + public static Object readExceptionOop(Word thread) { + return thread.readObject(threadExceptionOopOffset(), EXCEPTION_OOP_LOCATION); + } + + public static void writeExceptionOop(Word thread, Object value) { + thread.writeObject(threadExceptionOopOffset(), value, EXCEPTION_OOP_LOCATION); + } + + public static void writeExceptionPc(Word thread, Word value) { + thread.writeWord(threadExceptionPcOffset(), value, EXCEPTION_PC_LOCATION); + } + public static Word readTlabTop(Word thread) { return thread.readWord(threadTlabTopOffset(), TLAB_TOP_LOCATION); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java Mon Apr 15 08:51:19 2013 +0200 @@ -24,20 +24,22 @@ import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; import static com.oracle.graal.hotspot.replacements.TypeCheckSnippetUtils.*; -import static com.oracle.graal.replacements.SnippetTemplate.Arguments.*; import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.hotspot.replacements.TypeCheckSnippetUtils.Hints; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.Snippet.*; -import com.oracle.graal.replacements.SnippetTemplate.*; +import com.oracle.graal.replacements.Snippet.ConstantParameter; +import com.oracle.graal.replacements.Snippet.VarargsParameter; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; import com.oracle.graal.replacements.nodes.*; import com.oracle.graal.word.*; @@ -51,18 +53,11 @@ */ public class InstanceOfSnippets implements Snippets { - // @formatter:off - /** * A test against a final type. */ @Snippet - public static Object instanceofExact( - @Parameter("object") Object object, - @Parameter("exactHub") Word exactHub, - @Parameter("trueValue") Object trueValue, - @Parameter("falseValue") Object falseValue, - @ConstantParameter("checkNull") boolean checkNull) { + public static Object instanceofExact(Object object, Word exactHub, Object trueValue, Object falseValue, @ConstantParameter boolean checkNull) { if (checkNull && object == null) { probability(NOT_FREQUENT_PROBABILITY); isNull.inc(); @@ -82,13 +77,7 @@ * A test against a primary type. */ @Snippet - public static Object instanceofPrimary( - @Parameter("hub") Word hub, - @Parameter("object") Object object, - @Parameter("trueValue") Object trueValue, - @Parameter("falseValue") Object falseValue, - @ConstantParameter("checkNull") boolean checkNull, - @ConstantParameter("superCheckOffset") int superCheckOffset) { + public static Object instanceofPrimary(Word hub, Object object, @ConstantParameter int superCheckOffset, Object trueValue, Object falseValue, @ConstantParameter boolean checkNull) { if (checkNull && object == null) { probability(NOT_FREQUENT_PROBABILITY); isNull.inc(); @@ -108,13 +97,8 @@ * A test against a restricted secondary type type. */ @Snippet - public static Object instanceofSecondary( - @Parameter("hub") Word hub, - @Parameter("object") Object object, - @Parameter("trueValue") Object trueValue, - @Parameter("falseValue") Object falseValue, - @VarargsParameter("hints") Word[] hints, - @ConstantParameter("checkNull") boolean checkNull) { + public static Object instanceofSecondary(Word hub, Object object, @VarargsParameter Word[] hints, @VarargsParameter boolean[] hintIsPositive, Object trueValue, Object falseValue, + @ConstantParameter boolean checkNull) { if (checkNull && object == null) { probability(NOT_FREQUENT_PROBABILITY); isNull.inc(); @@ -125,10 +109,11 @@ ExplodeLoopNode.explodeLoop(); for (int i = 0; i < hints.length; i++) { Word hintHub = hints[i]; + boolean positive = hintIsPositive[i]; if (hintHub.equal(objectHub)) { probability(NOT_FREQUENT_PROBABILITY); hintsHit.inc(); - return trueValue; + return positive ? trueValue : falseValue; } } if (!checkSecondarySubType(hub, objectHub)) { @@ -141,12 +126,7 @@ * Type test used when the type being tested against is not known at compile time. */ @Snippet - public static Object instanceofDynamic( - @Parameter("mirror") Class mirror, - @Parameter("object") Object object, - @Parameter("trueValue") Object trueValue, - @Parameter("falseValue") Object falseValue, - @ConstantParameter("checkNull") boolean checkNull) { + public static Object instanceofDynamic(Class mirror, Object object, Object trueValue, Object falseValue, @ConstantParameter boolean checkNull) { if (checkNull && object == null) { probability(NOT_FREQUENT_PROBABILITY); isNull.inc(); @@ -161,61 +141,63 @@ return trueValue; } - // @formatter:on - - public static class Templates extends InstanceOfSnippetsTemplates { + public static class Templates extends InstanceOfSnippetsTemplates { - private final ResolvedJavaMethod instanceofExact; - private final ResolvedJavaMethod instanceofPrimary; - private final ResolvedJavaMethod instanceofSecondary; - private final ResolvedJavaMethod instanceofDynamic; + private final SnippetInfo instanceofExact = snippet(InstanceOfSnippets.class, "instanceofExact"); + private final SnippetInfo instanceofPrimary = snippet(InstanceOfSnippets.class, "instanceofPrimary"); + private final SnippetInfo instanceofSecondary = snippet(InstanceOfSnippets.class, "instanceofSecondary"); + private final SnippetInfo instanceofDynamic = snippet(InstanceOfSnippets.class, "instanceofDynamic"); - public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) { - super(runtime, assumptions, target, InstanceOfSnippets.class); - instanceofExact = snippet("instanceofExact", Object.class, Word.class, Object.class, Object.class, boolean.class); - instanceofPrimary = snippet("instanceofPrimary", Word.class, Object.class, Object.class, Object.class, boolean.class, int.class); - instanceofSecondary = snippet("instanceofSecondary", Word.class, Object.class, Object.class, Object.class, Word[].class, boolean.class); - instanceofDynamic = snippet("instanceofDynamic", Class.class, Object.class, Object.class, Object.class, boolean.class); + public Templates(CodeCacheProvider runtime, Replacements replacements, TargetDescription target) { + super(runtime, replacements, target); } @Override - protected KeyAndArguments getKeyAndArguments(InstanceOfUsageReplacer replacer, LoweringTool tool) { + protected Arguments makeArguments(InstanceOfUsageReplacer replacer, LoweringTool tool) { if (replacer.instanceOf instanceof InstanceOfNode) { InstanceOfNode instanceOf = (InstanceOfNode) replacer.instanceOf; - ValueNode trueValue = replacer.trueValue; - ValueNode falseValue = replacer.falseValue; ValueNode object = instanceOf.object(); TypeCheckHints hintInfo = new TypeCheckHints(instanceOf.type(), instanceOf.profile(), tool.assumptions(), GraalOptions.InstanceOfMinHintHitProbability, GraalOptions.InstanceOfMaxHints); final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) instanceOf.type(); ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, instanceOf.graph()); - boolean checkNull = !object.stamp().nonNull(); - Arguments arguments; - Key key; + + Arguments args; if (hintInfo.exact) { - ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph()); + ConstantNode[] hints = createHints(hintInfo, runtime, true, hub.graph()).hubs; assert hints.length == 1; - key = new Key(instanceofExact).add("checkNull", checkNull); - arguments = arguments("object", object).add("exactHub", hints[0]).add("trueValue", trueValue).add("falseValue", falseValue); + args = new Arguments(instanceofExact); + args.add("object", object); + args.add("exactHub", hints[0]); } else if (type.isPrimaryType()) { - key = new Key(instanceofPrimary).add("checkNull", checkNull).add("superCheckOffset", type.superCheckOffset()); - arguments = arguments("hub", hub).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue); + args = new Arguments(instanceofPrimary); + args.add("hub", hub); + args.add("object", object); + args.addConst("superCheckOffset", type.superCheckOffset()); } else { - ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph()); - key = new Key(instanceofSecondary).add("hints", Varargs.vargargs(new Word[hints.length], StampFactory.forKind(wordKind()))).add("checkNull", checkNull); - arguments = arguments("hub", hub).add("object", object).add("hints", hints).add("trueValue", trueValue).add("falseValue", falseValue); + Hints hints = createHints(hintInfo, runtime, false, hub.graph()); + args = new Arguments(instanceofSecondary); + args.add("hub", hub); + args.add("object", object); + args.addVarargs("hints", Word.class, StampFactory.forKind(wordKind()), hints.hubs); + args.addVarargs("hintIsPositive", boolean.class, StampFactory.forKind(Kind.Boolean), hints.isPositive); } - return new KeyAndArguments(key, arguments); + args.add("trueValue", replacer.trueValue); + args.add("falseValue", replacer.falseValue); + args.addConst("checkNull", !object.stamp().nonNull()); + return args; + } else { assert replacer.instanceOf instanceof InstanceOfDynamicNode; InstanceOfDynamicNode instanceOf = (InstanceOfDynamicNode) replacer.instanceOf; - ValueNode trueValue = replacer.trueValue; - ValueNode falseValue = replacer.falseValue; ValueNode object = instanceOf.object(); - ValueNode mirror = instanceOf.mirror(); - boolean checkNull = !object.stamp().nonNull(); - Key key = new Key(instanceofDynamic).add("checkNull", checkNull); - Arguments arguments = arguments("mirror", mirror).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue); - return new KeyAndArguments(key, arguments); + + Arguments args = new Arguments(instanceofDynamic); + args.add("mirror", instanceOf.mirror()); + args.add("object", object); + args.add("trueValue", replacer.trueValue); + args.add("falseValue", replacer.falseValue); + args.addConst("checkNull", !object.stamp().nonNull()); + return args; } } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,66 @@ +/* + * 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. + */ +package com.oracle.graal.hotspot.replacements; + +import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; +import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; +import static com.oracle.graal.replacements.SnippetTemplate.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; +import com.oracle.graal.word.*; + +/** + * Snippet for loading the exception object at the start of an exception dispatcher. + */ +public class LoadExceptionObjectSnippets implements Snippets { + + @Snippet + public static Object loadException() { + Word thread = thread(); + Object exception = readExceptionOop(thread); + writeExceptionOop(thread, null); + writeExceptionPc(thread, Word.zero()); + return unsafeCast(exception, StampFactory.forNodeIntrinsic()); + } + + public static class Templates extends AbstractTemplates { + + private final SnippetInfo loadException = snippet(LoadExceptionObjectSnippets.class, "loadException"); + + public Templates(CodeCacheProvider runtime, Replacements replacements, TargetDescription target) { + super(runtime, replacements, target); + } + + public void lower(LoadExceptionObjectNode loadExceptionObject) { + Arguments args = new Arguments(loadException); + template(args).instantiate(runtime, loadExceptionObject, DEFAULT_REPLACER, args); + } + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleInvokeBasicNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleInvokeBasicNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,38 @@ +/* + * 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.graal.hotspot.replacements; + +import java.lang.invoke.*; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Macro node for {@link MethodHandle}{@code .invokeBasic(Object...)}. + */ +public class MethodHandleInvokeBasicNode extends MacroNode { + + public MethodHandleInvokeBasicNode(Invoke invoke) { + super(invoke); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToInterfaceNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToInterfaceNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,38 @@ +/* + * 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.graal.hotspot.replacements; + +import java.lang.invoke.*; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Macro node for {@link MethodHandle}{@code .linkToInterface(Object...)}. + */ +public class MethodHandleLinkToInterfaceNode extends MacroNode { + + public MethodHandleLinkToInterfaceNode(Invoke invoke) { + super(invoke); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToSpecialNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToSpecialNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,38 @@ +/* + * 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.graal.hotspot.replacements; + +import java.lang.invoke.*; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Macro node for {@link MethodHandle}{@code .linkToSpecial(Object...)}. + */ +public class MethodHandleLinkToSpecialNode extends MacroNode { + + public MethodHandleLinkToSpecialNode(Invoke invoke) { + super(invoke); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToStaticNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToStaticNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,38 @@ +/* + * 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.graal.hotspot.replacements; + +import java.lang.invoke.*; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Macro node for {@link MethodHandle}{@code .linkToStatic(Object...)}. + */ +public class MethodHandleLinkToStaticNode extends MacroNode { + + public MethodHandleLinkToStaticNode(Invoke invoke) { + super(invoke); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToVirtualNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToVirtualNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,38 @@ +/* + * 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.graal.hotspot.replacements; + +import java.lang.invoke.*; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Macro node for {@link MethodHandle}{@code .linkToVirtual(Object...)}. + */ +public class MethodHandleLinkToVirtualNode extends MacroNode { + + public MethodHandleLinkToVirtualNode(Invoke invoke) { + super(invoke); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Mon Apr 15 08:51:19 2013 +0200 @@ -46,7 +46,10 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.Snippet.ConstantParameter; +import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; import com.oracle.graal.word.*; /** @@ -73,7 +76,7 @@ public static final boolean CHECK_BALANCED_MONITORS = Boolean.getBoolean("graal.monitors.checkBalanced"); @Snippet - public static void monitorenter(@Parameter("object") Object object, @ConstantParameter("checkNull") boolean checkNull, @ConstantParameter("trace") boolean trace) { + public static void monitorenter(Object object, @ConstantParameter boolean checkNull, @ConstantParameter boolean trace) { verifyOop(object); if (checkNull && object == null) { @@ -262,7 +265,7 @@ * Calls straight out to the monitorenter stub. */ @Snippet - public static void monitorenterStub(@Parameter("object") Object object, @ConstantParameter("checkNull") boolean checkNull, @ConstantParameter("trace") boolean trace) { + public static void monitorenterStub(Object object, @ConstantParameter boolean checkNull, @ConstantParameter boolean trace) { verifyOop(object); incCounter(); if (checkNull && object == null) { @@ -276,7 +279,7 @@ } @Snippet - public static void monitorexit(@Parameter("object") Object object, @ConstantParameter("trace") boolean trace) { + public static void monitorexit(Object object, @ConstantParameter boolean trace) { trace(trace, " object: 0x%016lx\n", Word.fromObject(object)); if (useBiasedLocking()) { // Check for biased locking unlock case, which is a no-op @@ -328,7 +331,7 @@ * Calls straight out to the monitorexit stub. */ @Snippet - public static void monitorexitStub(@Parameter("object") Object object, @ConstantParameter("trace") boolean trace) { + public static void monitorexitStub(Object object, @ConstantParameter boolean trace) { verifyOop(object); traceObject(trace, "-lock{stub}", object); MonitorExitStubCall.call(object); @@ -398,54 +401,45 @@ } } - public static class Templates extends AbstractTemplates { + public static class Templates extends AbstractTemplates { - private final ResolvedJavaMethod monitorenter; - private final ResolvedJavaMethod monitorexit; - private final ResolvedJavaMethod monitorenterStub; - private final ResolvedJavaMethod monitorexitStub; - private final ResolvedJavaMethod monitorenterEliminated; - private final ResolvedJavaMethod monitorexitEliminated; - private final ResolvedJavaMethod initCounter; - private final ResolvedJavaMethod checkCounter; + private final SnippetInfo monitorenter = snippet(MonitorSnippets.class, "monitorenter"); + private final SnippetInfo monitorexit = snippet(MonitorSnippets.class, "monitorexit"); + private final SnippetInfo monitorenterStub = snippet(MonitorSnippets.class, "monitorenterStub"); + private final SnippetInfo monitorexitStub = snippet(MonitorSnippets.class, "monitorexitStub"); + private final SnippetInfo monitorenterEliminated = snippet(MonitorSnippets.class, "monitorenterEliminated"); + private final SnippetInfo monitorexitEliminated = snippet(MonitorSnippets.class, "monitorexitEliminated"); + private final SnippetInfo initCounter = snippet(MonitorSnippets.class, "initCounter"); + private final SnippetInfo checkCounter = snippet(MonitorSnippets.class, "checkCounter"); + private final boolean useFastLocking; - public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target, boolean useFastLocking) { - super(runtime, assumptions, target, MonitorSnippets.class); - monitorenter = snippet("monitorenter", Object.class, boolean.class, boolean.class); - monitorexit = snippet("monitorexit", Object.class, boolean.class); - monitorenterStub = snippet("monitorenterStub", Object.class, boolean.class, boolean.class); - monitorexitStub = snippet("monitorexitStub", Object.class, boolean.class); - monitorenterEliminated = snippet("monitorenterEliminated"); - monitorexitEliminated = snippet("monitorexitEliminated"); - initCounter = snippet("initCounter"); - checkCounter = snippet("checkCounter", String.class); + public Templates(CodeCacheProvider runtime, Replacements replacements, TargetDescription target, boolean useFastLocking) { + super(runtime, replacements, target); this.useFastLocking = useFastLocking; } public void lower(MonitorEnterNode monitorenterNode, @SuppressWarnings("unused") LoweringTool tool) { StructuredGraph graph = (StructuredGraph) monitorenterNode.graph(); - checkBalancedMonitors(graph); - FrameState stateAfter = monitorenterNode.stateAfter(); - boolean eliminated = monitorenterNode.eliminated(); - ResolvedJavaMethod method = eliminated ? monitorenterEliminated : useFastLocking ? monitorenter : monitorenterStub; - boolean checkNull = !monitorenterNode.object().stamp().nonNull(); - Key key = new Key(method); - if (method != monitorenterEliminated) { - key.add("checkNull", checkNull); - } - if (!eliminated) { - key.add("trace", isTracingEnabledForType(monitorenterNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); + + Arguments args; + if (monitorenterNode.eliminated()) { + args = new Arguments(monitorenterEliminated); + } else { + if (useFastLocking) { + args = new Arguments(monitorenter); + } else { + args = new Arguments(monitorenterStub); + } + args.add("object", monitorenterNode.object()); + args.addConst("checkNull", !monitorenterNode.object().stamp().nonNull()); + args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); } - Arguments arguments = new Arguments(); - if (!eliminated) { - arguments.add("object", monitorenterNode.object()); - } - SnippetTemplate template = cache.get(key, assumptions); - Map nodes = template.instantiate(runtime, monitorenterNode, DEFAULT_REPLACER, arguments); + Map nodes = template(args).instantiate(runtime, monitorenterNode, DEFAULT_REPLACER, args); + for (Node n : nodes.values()) { if (n instanceof BeginLockScopeNode) { BeginLockScopeNode begin = (BeginLockScopeNode) n; @@ -460,18 +454,22 @@ public void lower(MonitorExitNode monitorexitNode, @SuppressWarnings("unused") LoweringTool tool) { StructuredGraph graph = (StructuredGraph) monitorexitNode.graph(); FrameState stateAfter = monitorexitNode.stateAfter(); - boolean eliminated = monitorexitNode.eliminated(); - ResolvedJavaMethod method = eliminated ? monitorexitEliminated : useFastLocking ? monitorexit : monitorexitStub; - Key key = new Key(method); - if (!eliminated) { - key.add("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); + + Arguments args; + if (monitorexitNode.eliminated()) { + args = new Arguments(monitorexitEliminated); + } else { + if (useFastLocking) { + args = new Arguments(monitorexit); + } else { + args = new Arguments(monitorexitStub); + } + args.add("object", monitorexitNode.object()); + args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(stateAfter.method()) || isTracingEnabledForMethod(graph.method())); } - Arguments arguments = new Arguments(); - if (!eliminated) { - arguments.add("object", monitorexitNode.object()); - } - SnippetTemplate template = cache.get(key, assumptions); - Map nodes = template.instantiate(runtime, monitorexitNode, DEFAULT_REPLACER, arguments); + + Map nodes = template(args).instantiate(runtime, monitorexitNode, DEFAULT_REPLACER, args); + for (Node n : nodes.values()) { if (n instanceof EndLockScopeNode) { EndLockScopeNode end = (EndLockScopeNode) n; @@ -521,26 +519,27 @@ NodeIterable nodes = graph.getNodes().filter(MonitorCounterNode.class); if (nodes.isEmpty()) { // Only insert the nodes if this is the first monitorenter being lowered. - JavaType returnType = initCounter.getSignature().getReturnType(initCounter.getDeclaringClass()); - MethodCallTargetNode callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, initCounter, new ValueNode[0], returnType)); + JavaType returnType = initCounter.getMethod().getSignature().getReturnType(initCounter.getMethod().getDeclaringClass()); + MethodCallTargetNode callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, initCounter.getMethod(), new ValueNode[0], returnType)); InvokeNode invoke = graph.add(new InvokeNode(callTarget, 0)); invoke.setStateAfter(graph.start().stateAfter()); graph.addAfterFixed(graph.start(), invoke); - StructuredGraph inlineeGraph = (StructuredGraph) initCounter.getCompilerStorage().get(Snippet.class); + + StructuredGraph inlineeGraph = replacements.getSnippet(initCounter.getMethod()); InliningUtil.inline(invoke, inlineeGraph, false); List rets = graph.getNodes().filter(ReturnNode.class).snapshot(); for (ReturnNode ret : rets) { - returnType = checkCounter.getSignature().getReturnType(checkCounter.getDeclaringClass()); + returnType = checkCounter.getMethod().getSignature().getReturnType(checkCounter.getMethod().getDeclaringClass()); Object msg = ((HotSpotRuntime) runtime).registerGCRoot("unbalanced monitors in " + MetaUtil.format("%H.%n(%p)", graph.method()) + ", count = %d"); ConstantNode errMsg = ConstantNode.forObject(msg, runtime, graph); - callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, checkCounter, new ValueNode[]{errMsg}, returnType)); + callTarget = graph.add(new MethodCallTargetNode(InvokeKind.Static, checkCounter.getMethod(), new ValueNode[]{errMsg}, returnType)); invoke = graph.add(new InvokeNode(callTarget, 0)); List stack = Collections.emptyList(); FrameState stateAfter = new FrameState(graph.method(), FrameState.AFTER_BCI, new ValueNode[0], stack, new ValueNode[0], false, false); invoke.setStateAfter(graph.add(stateAfter)); graph.addBeforeFixed(ret, invoke); - inlineeGraph = (StructuredGraph) checkCounter.getCompilerStorage().get(Snippet.class); + inlineeGraph = replacements.getSnippet(checkCounter.getMethod()); InliningUtil.inline(invoke, inlineeGraph, false); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Mon Apr 15 08:51:19 2013 +0200 @@ -26,9 +26,7 @@ import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; import static com.oracle.graal.nodes.extended.UnsafeArrayCastNode.*; import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; -import static com.oracle.graal.replacements.Snippet.Varargs.*; import static com.oracle.graal.replacements.SnippetTemplate.*; -import static com.oracle.graal.replacements.SnippetTemplate.Arguments.*; import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; import static com.oracle.graal.replacements.nodes.ExplodeLoopNode.*; @@ -43,7 +41,11 @@ import com.oracle.graal.nodes.type.*; import com.oracle.graal.phases.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.Snippet.ConstantParameter; +import com.oracle.graal.replacements.Snippet.VarargsParameter; +import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; import com.oracle.graal.replacements.nodes.*; import com.oracle.graal.word.*; @@ -52,15 +54,16 @@ */ public class NewObjectSnippets implements Snippets { - // @formatter:off - @Snippet - public static Word allocate(@Parameter("size") int size) { + public static Word allocate(int size) { Word thread = thread(); Word top = readTlabTop(thread); Word end = readTlabEnd(thread); Word newTop = top.add(size); - // this check might lead to problems if the TLAB is within 16GB of the address space end (checked in c++ code) + /* + * this check might lead to problems if the TLAB is within 16GB of the address space end + * (checked in c++ code) + */ if (newTop.belowOrEqual(end)) { probability(FAST_PATH_PROBABILITY); writeTlabTop(thread, newTop); @@ -70,13 +73,7 @@ } @Snippet - public static Object initializeObject( - @Parameter("memory") Word memory, - @Parameter("hub") Word hub, - @Parameter("prototypeMarkWord") Word prototypeMarkWord, - @ConstantParameter("size") int size, - @ConstantParameter("fillContents") boolean fillContents, - @ConstantParameter("locked") boolean locked) { + public static Object initializeObject(Word memory, Word hub, Word prototypeMarkWord, @ConstantParameter int size, @ConstantParameter boolean fillContents, @ConstantParameter boolean locked) { Object result; if (memory.equal(0)) { @@ -91,19 +88,17 @@ } result = memory.toObject(); } - return unsafeCast(verifyOop(result), StampFactory.forNodeIntrinsic()); + /* + * make sure that the unsafeCast is anchored after initialization, see ReadAfterCheckCast + * and CheckCastSnippets + */ + BeginNode anchorNode = BeginNode.anchor(StampFactory.forNodeIntrinsic()); + return unsafeCast(verifyOop(result), StampFactory.forNodeIntrinsic(), anchorNode); } @Snippet - public static Object initializeArray( - @Parameter("memory") Word memory, - @Parameter("hub") Word hub, - @Parameter("length") int length, - @Parameter("allocationSize") int allocationSize, - @Parameter("prototypeMarkWord") Word prototypeMarkWord, - @ConstantParameter("headerSize") int headerSize, - @ConstantParameter("fillContents") boolean fillContents, - @ConstantParameter("locked") boolean locked) { + public static Object initializeArray(Word memory, Word hub, int length, int allocationSize, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter boolean fillContents, + @ConstantParameter boolean locked) { if (locked) { return initializeArray(memory, hub, length, allocationSize, thread().or(biasedLockPattern()), headerSize, fillContents); } else { @@ -122,7 +117,8 @@ formatArray(hub, allocationSize, length, headerSize, memory, prototypeMarkWord, fillContents); result = memory.toObject(); } - return unsafeArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic()); + BeginNode anchorNode = BeginNode.anchor(StampFactory.forNodeIntrinsic()); + return unsafeArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic(), anchorNode); } /** @@ -131,13 +127,8 @@ public static final int MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH = 0x00FFFFFF; @Snippet - public static Object allocateArrayAndInitialize( - @Parameter("length") int length, - @ConstantParameter("alignment") int alignment, - @ConstantParameter("headerSize") int headerSize, - @ConstantParameter("log2ElementSize") int log2ElementSize, - @ConstantParameter("fillContents") boolean fillContents, - @ConstantParameter("type") ResolvedJavaType type) { + public static Object allocateArrayAndInitialize(int length, @ConstantParameter int alignment, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize, + @ConstantParameter boolean fillContents, @ConstantParameter ResolvedJavaType type) { if (!belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) { probability(DEOPT_PATH_PROBABILITY); // This handles both negative array sizes and very large array sizes @@ -149,9 +140,10 @@ } /** - * Computes the size of the memory chunk allocated for an array. This size accounts for the array - * header size, boy size and any padding after the last element to satisfy object alignment requirements. - * + * Computes the size of the memory chunk allocated for an array. This size accounts for the + * array header size, boy size and any padding after the last element to satisfy object + * alignment requirements. + * * @param length the number of elements in the array * @param alignment the object alignment requirement * @param headerSize the size of the array header @@ -167,10 +159,7 @@ * Calls the runtime stub for implementing MULTIANEWARRAY. */ @Snippet - public static Object newmultiarray( - @Parameter("hub") Word hub, - @ConstantParameter("rank") int rank, - @VarargsParameter("dimensions") int[] dimensions) { + public static Object newmultiarray(Word hub, @ConstantParameter int rank, @VarargsParameter int[] dimensions) { Word dims = DimensionsNode.allocaDimsArray(rank); ExplodeLoopNode.explodeLoop(); for (int i = 0; i < rank; i++) { @@ -180,9 +169,8 @@ } /** - * Maximum size of an object whose body is initialized by a sequence of - * zero-stores to its fields. Larger objects have their bodies initialized - * in a loop. + * Maximum size of an object whose body is initialized by a sequence of zero-stores to its + * fields. Larger objects have their bodies initialized in a loop. */ private static final int MAX_UNROLLED_OBJECT_ZEROING_SIZE = 10 * wordSize(); @@ -213,7 +201,10 @@ */ public static void formatArray(Word hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents) { memory.writeInt(arrayLengthOffset(), length, ANY_LOCATION); - // store hub last as the concurrent garbage collectors assume length is valid if hub field is not null + /* + * store hub last as the concurrent garbage collectors assume length is valid if hub field + * is not null + */ initializeObjectHeader(memory, prototypeMarkWord, hub); if (fillContents) { for (int offset = headerSize; offset < allocationSize; offset += wordSize()) { @@ -222,27 +213,19 @@ } } - // @formatter:on - - public static class Templates extends AbstractTemplates { + public static class Templates extends AbstractTemplates { - private final ResolvedJavaMethod allocate; - private final ResolvedJavaMethod initializeObject; - private final ResolvedJavaMethod initializeArray; - private final ResolvedJavaMethod allocateArrayAndInitialize; - private final ResolvedJavaMethod newmultiarray; - private final TargetDescription target; + private final SnippetInfo allocate = snippet(NewObjectSnippets.class, "allocate"); + private final SnippetInfo initializeObject = snippet(NewObjectSnippets.class, "initializeObject"); + private final SnippetInfo initializeArray = snippet(NewObjectSnippets.class, "initializeArray"); + private final SnippetInfo allocateArrayAndInitialize = snippet(NewObjectSnippets.class, "allocateArrayAndInitialize"); + private final SnippetInfo newmultiarray = snippet(NewObjectSnippets.class, "newmultiarray"); + private final boolean useTLAB; - public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target, boolean useTLAB) { - super(runtime, assumptions, target, NewObjectSnippets.class); - this.target = target; + public Templates(CodeCacheProvider runtime, Replacements replacements, TargetDescription target, boolean useTLAB) { + super(runtime, replacements, target); this.useTLAB = useTLAB; - allocate = snippet("allocate", int.class); - initializeObject = snippet("initializeObject", Word.class, Word.class, Word.class, int.class, boolean.class, boolean.class); - initializeArray = snippet("initializeArray", Word.class, Word.class, int.class, int.class, Word.class, int.class, boolean.class, boolean.class); - allocateArrayAndInitialize = snippet("allocateArrayAndInitialize", int.class, int.class, int.class, int.class, boolean.class, ResolvedJavaType.class); - newmultiarray = snippet("newmultiarray", Word.class, int.class, int[].class); } /** @@ -285,9 +268,10 @@ int log2ElementSize = CodeUtil.log2(target.sizeInBytes(elementKind)); if (!useTLAB) { ConstantNode zero = ConstantNode.defaultForKind(target.wordKind, graph); - // value for 'size' doesn't matter as it isn't used since a stub call will be made - // anyway - // for both allocation and initialization - it just needs to be non-null + /* + * value for 'size' doesn't matter as it isn't used since a stub call will be made + * anyway for both allocation and initialization - it just needs to be non-null + */ ConstantNode size = ConstantNode.forInt(-1, graph); InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(zero, lengthNode, size, arrayType, newArrayNode.fillContents(), newArrayNode.locked())); graph.replaceFixedWithFixed(newArrayNode, initializeNode); @@ -300,12 +284,17 @@ InitializeArrayNode initializeNode = graph.add(new InitializeArrayNode(tlabAllocateNode, lengthNode, sizeNode, arrayType, newArrayNode.fillContents(), newArrayNode.locked())); graph.replaceFixedWithFixed(newArrayNode, initializeNode); } else { - Key key = new Key(allocateArrayAndInitialize).add("alignment", alignment).add("headerSize", headerSize).add("log2ElementSize", log2ElementSize).add("fillContents", - newArrayNode.fillContents()).add("type", arrayType); - Arguments arguments = new Arguments().add("length", lengthNode); - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering allocateArrayAndInitialize in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, arguments); - template.instantiate(runtime, newArrayNode, DEFAULT_REPLACER, arguments); + Arguments args = new Arguments(allocateArrayAndInitialize); + args.add("length", lengthNode); + args.addConst("alignment", alignment); + args.addConst("headerSize", headerSize); + args.addConst("log2ElementSize", log2ElementSize); + args.addConst("fillContents", newArrayNode.fillContents()); + args.addConst("type", arrayType); + + SnippetTemplate template = template(args); + Debug.log("Lowering allocateArrayAndInitialize in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args); + template.instantiate(runtime, newArrayNode, DEFAULT_REPLACER, args); } } @@ -313,11 +302,11 @@ public void lower(TLABAllocateNode tlabAllocateNode, LoweringTool tool) { StructuredGraph graph = (StructuredGraph) tlabAllocateNode.graph(); ValueNode size = tlabAllocateNode.size(); - Key key = new Key(allocate); - Arguments arguments = arguments("size", size); - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering fastAllocate in %s: node=%s, template=%s, arguments=%s", graph, tlabAllocateNode, template, arguments); - template.instantiate(runtime, tlabAllocateNode, DEFAULT_REPLACER, arguments); + Arguments args = new Arguments(allocate).add("size", size); + + SnippetTemplate template = template(args); + Debug.log("Lowering fastAllocate in %s: node=%s, template=%s, arguments=%s", graph, tlabAllocateNode, template, args); + template.instantiate(runtime, tlabAllocateNode, DEFAULT_REPLACER, args); } @SuppressWarnings("unused") @@ -327,12 +316,18 @@ assert !type.isArray(); ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); int size = instanceSize(type); - Key key = new Key(initializeObject).add("size", size).add("fillContents", initializeNode.fillContents()).add("locked", initializeNode.locked()); ValueNode memory = initializeNode.memory(); - Arguments arguments = arguments("memory", memory).add("hub", hub).add("prototypeMarkWord", type.prototypeMarkWord()); - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering initializeObject in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, arguments); - template.instantiate(runtime, initializeNode, DEFAULT_REPLACER, arguments); + + Arguments args = new Arguments(initializeObject); + args.add("memory", memory); + args.add("hub", hub); + args.add("prototypeMarkWord", type.prototypeMarkWord()); + args.addConst("size", size).addConst("fillContents", initializeNode.fillContents()); + args.addConst("locked", initializeNode.locked()); + + SnippetTemplate template = template(args); + Debug.log("Lowering initializeObject in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, args); + template.instantiate(runtime, initializeNode, DEFAULT_REPLACER, args); } @SuppressWarnings("unused") @@ -344,13 +339,21 @@ ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); Kind elementKind = elementType.getKind(); final int headerSize = HotSpotRuntime.getArrayBaseOffset(elementKind); - Key key = new Key(initializeArray).add("headerSize", headerSize).add("fillContents", initializeNode.fillContents()).add("locked", initializeNode.locked()); ValueNode memory = initializeNode.memory(); - Arguments arguments = arguments("memory", memory).add("hub", hub).add("prototypeMarkWord", type.prototypeMarkWord()).add("allocationSize", initializeNode.allocationSize()).add("length", - initializeNode.length()); - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering initializeArray in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, arguments); - template.instantiate(runtime, initializeNode, DEFAULT_REPLACER, arguments); + + Arguments args = new Arguments(initializeArray); + args.add("memory", memory); + args.add("hub", hub); + args.add("length", initializeNode.length()); + args.add("allocationSize", initializeNode.allocationSize()); + args.add("prototypeMarkWord", type.prototypeMarkWord()); + args.addConst("headerSize", headerSize); + args.addConst("fillContents", initializeNode.fillContents()); + args.addConst("locked", initializeNode.locked()); + + SnippetTemplate template = template(args); + Debug.log("Lowering initializeArray in %s: node=%s, template=%s, arguments=%s", graph, initializeNode, template, args); + template.instantiate(runtime, initializeNode, DEFAULT_REPLACER, args); } @SuppressWarnings("unused") @@ -363,10 +366,12 @@ } HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newmultiarrayNode.type(); ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, graph); - Key key = new Key(newmultiarray).add("dimensions", vargargs(new int[rank], StampFactory.forKind(Kind.Int))).add("rank", rank); - Arguments arguments = arguments("dimensions", dims).add("hub", hub); - SnippetTemplate template = cache.get(key, assumptions); - template.instantiate(runtime, newmultiarrayNode, DEFAULT_REPLACER, arguments); + + Arguments args = new Arguments(newmultiarray); + args.add("hub", hub); + args.addConst("rank", rank); + args.addVarargs("dimensions", int.class, StampFactory.forKind(Kind.Int), dims); + template(args).instantiate(runtime, newmultiarrayNode, DEFAULT_REPLACER, args); } private static int instanceSize(HotSpotResolvedObjectType type) { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -32,7 +32,6 @@ import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; -import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.nodes.*; public class ObjectCloneNode extends MacroNode implements VirtualizableAllocation, ArrayLengthProvider { @@ -70,7 +69,8 @@ method = ObjectCloneSnippets.instanceCloneMethod; } ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(method); - StructuredGraph snippetGraph = (StructuredGraph) snippetMethod.getCompilerStorage().get(Snippet.class); + Replacements replacements = tool.getReplacements(); + StructuredGraph snippetGraph = replacements.getSnippet(snippetMethod); assert snippetGraph != null : "ObjectCloneSnippets should be installed"; return snippetGraph; diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Mon Apr 15 08:51:19 2013 +0200 @@ -58,7 +58,7 @@ memory = Word.fromObject(result); for (int offset = 2 * wordSize(); offset < instanceSize; offset += wordSize()) { - memory.writeWord(offset, Word.fromObject(src).readWord(offset, UNKNOWN_LOCATION), ANY_LOCATION); + memory.writeWord(offset, Word.fromObject(src).readWord(offset, ANY_LOCATION), ANY_LOCATION); } return result; @@ -76,7 +76,7 @@ memory = Word.fromObject(result); for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) { - memory.writeWord(offset, Word.fromObject(src).readWord(offset, UNKNOWN_LOCATION), ANY_LOCATION); + memory.writeWord(offset, Word.fromObject(src).readWord(offset, ANY_LOCATION), ANY_LOCATION); } return result; } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java Mon Apr 15 08:51:19 2013 +0200 @@ -28,7 +28,7 @@ import com.oracle.graal.api.replacements.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; -import com.oracle.graal.replacements.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.word.*; /** diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemSubstitutions.java Mon Apr 15 08:51:19 2013 +0200 @@ -30,7 +30,7 @@ import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.replacements.*; +import com.oracle.graal.nodes.spi.*; /** * Substitutions for {@link java.lang.System} methods. diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ThreadSubstitutions.java Mon Apr 15 08:51:19 2013 +0200 @@ -45,7 +45,7 @@ Object thread = javaThread.readObject(threadObjectOffset(), FINAL_LOCATION); if (thisObject == thread) { Word osThread = javaThread.readWord(osThreadOffset(), FINAL_LOCATION); - boolean interrupted = osThread.readInt(osThreadInterruptedOffset(), UNKNOWN_LOCATION) != 0; + boolean interrupted = osThread.readInt(osThreadInterruptedOffset(), ANY_LOCATION) != 0; if (!interrupted || !clearInterrupted) { return interrupted; } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/TypeCheckSnippetUtils.java Mon Apr 15 08:51:19 2013 +0200 @@ -25,6 +25,8 @@ import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; +import java.util.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; @@ -98,12 +100,45 @@ return false; } - static ConstantNode[] createHints(TypeCheckHints hints, MetaAccessProvider runtime, Graph graph) { - ConstantNode[] hintHubs = new ConstantNode[hints.types.length]; - for (int i = 0; i < hintHubs.length; i++) { - hintHubs[i] = ConstantNode.forConstant(((HotSpotResolvedObjectType) hints.types[i]).klass(), runtime, graph); + /** + * A set of type check hints ordered by decreasing probabilities. + */ + public static class Hints { + + /** + * The hubs of the hint types. + */ + public final ConstantNode[] hubs; + + /** + * A predicate over {@link #hubs} specifying whether the corresponding hint type is a + * sub-type of the checked type. + */ + public final boolean[] isPositive; + + Hints(ConstantNode[] hints, boolean[] hintIsPositive) { + this.hubs = hints; + this.isPositive = hintIsPositive; } - return hintHubs; + } + + static Hints createHints(TypeCheckHints hints, MetaAccessProvider runtime, boolean positiveOnly, Graph graph) { + ConstantNode[] hubs = new ConstantNode[hints.hints.length]; + boolean[] isPositive = new boolean[hints.hints.length]; + int index = 0; + for (int i = 0; i < hubs.length; i++) { + if (!positiveOnly || hints.hints[i].positive) { + hubs[index] = ConstantNode.forConstant(((HotSpotResolvedObjectType) hints.hints[i].type).klass(), runtime, graph); + isPositive[index] = hints.hints[i].positive; + index++; + } + } + if (positiveOnly && index != hubs.length) { + assert index < hubs.length; + hubs = Arrays.copyOf(hubs, index); + isPositive = Arrays.copyOf(isPositive, index); + } + return new Hints(hubs, isPositive); } static Word loadSecondarySupersElement(Word metaspaceArray, int index) { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/WriteBarrierSnippets.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 @@ -28,100 +28,27 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.hotspot.nodes.*; +import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.Snippet.ConstantParameter; -import com.oracle.graal.replacements.Snippet.Parameter; import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; import com.oracle.graal.replacements.SnippetTemplate.Arguments; -import com.oracle.graal.replacements.SnippetTemplate.Key; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; +import com.oracle.graal.replacements.nodes.*; import com.oracle.graal.word.*; public class WriteBarrierSnippets implements Snippets { @Snippet - public static void g1PreWriteBarrier(@Parameter("object") Object obj, @Parameter("expectedObject") Object expobj, @Parameter("location") Object location, - @ConstantParameter("doLoad") boolean doLoad) { - Word thread = thread(); + public static void serialArrayWriteBarrier(Object obj, Object location, @ConstantParameter boolean usePrecise) { Object object = FixedValueAnchorNode.getObject(obj); - Object expectedObject = FixedValueAnchorNode.getObject(expobj); - Word field = (Word) Word.fromArray(object, location); - Word previousOop = (Word) Word.fromObject(expectedObject); - byte markingValue = thread.readByte(HotSpotSnippetUtils.g1SATBQueueMarkingOffset()); - - Word bufferAddress = thread.readWord(HotSpotSnippetUtils.g1SATBQueueBufferOffset()); - Word indexAddress = thread.add(HotSpotSnippetUtils.g1SATBQueueIndexOffset()); - Word indexValue = indexAddress.readWord(0); - - if (markingValue != (byte) 0) { - if (doLoad) { - previousOop = field.readWord(0); - } - if (previousOop.notEqual(Word.zero())) { - if (indexValue.notEqual(Word.zero())) { - Word nextIndex = indexValue.subtract(HotSpotSnippetUtils.wordSize()); - Word logAddress = bufferAddress.add(nextIndex); - logAddress.writeWord(0, previousOop); - indexAddress.writeWord(0, nextIndex); - } else { - WriteBarrierPreStubCall.call(previousOop); - - } - } - } - } - - @Snippet - public static void g1PostWriteBarrier(@Parameter("object") Object obj, @Parameter("value") Object value, @Parameter("location") Object location, @ConstantParameter("usePrecise") boolean usePrecise) { - Word thread = thread(); - Object object = FixedValueAnchorNode.getObject(obj); - Object wrObject = FixedValueAnchorNode.getObject(value); - Word oop = (Word) Word.fromObject(object); - Word field; + Pointer oop; if (usePrecise) { - field = (Word) Word.fromArray(object, location); + oop = Word.fromArray(object, location); } else { - field = oop; - } - Word writtenValue = (Word) Word.fromObject(wrObject); - Word bufferAddress = thread.readWord(HotSpotSnippetUtils.g1CardQueueBufferOffset()); - Word indexAddress = thread.add(HotSpotSnippetUtils.g1CardQueueIndexOffset()); - Word indexValue = thread.readWord(HotSpotSnippetUtils.g1CardQueueIndexOffset()); - Word xorResult = (field.xor(writtenValue)).unsignedShiftRight(HotSpotSnippetUtils.logOfHRGrainBytes()); - - // Card Table - Word cardBase = field.unsignedShiftRight(cardTableShift()); - long startAddress = cardTableStart(); - int displacement = 0; - if (((int) startAddress) == startAddress) { - displacement = (int) startAddress; - } else { - cardBase = cardBase.add(Word.unsigned(cardTableStart())); + oop = Word.fromObject(object); } - Word cardAddress = cardBase.add(displacement); - - if (xorResult.notEqual(Word.zero())) { - if (writtenValue.notEqual(Word.zero())) { - byte cardByte = cardAddress.readByte(0); - if (cardByte != (byte) 0) { - cardAddress.writeByte(0, (byte) 0); // smash zero into card - if (indexValue.notEqual(Word.zero())) { - Word nextIndex = indexValue.subtract(HotSpotSnippetUtils.wordSize()); - Word logAddress = bufferAddress.add(nextIndex); - logAddress.writeWord(0, cardAddress); - indexAddress.writeWord(0, nextIndex); - } else { - WriteBarrierPostStubCall.call(object, cardAddress); - } - } - } - } - } - - @Snippet - public static void serialFieldWriteBarrier(@Parameter("object") Object obj) { - Object object = FixedValueAnchorNode.getObject(obj); - Pointer oop = Word.fromObject(object); Word base = (Word) oop.unsignedShiftRight(cardTableShift()); long startAddress = cardTableStart(); int displacement = 0; @@ -134,77 +61,44 @@ } @Snippet - public static void serialArrayWriteBarrier(@Parameter("object") Object obj, @Parameter("location") Object location) { - Object object = FixedValueAnchorNode.getObject(obj); - Pointer oop = Word.fromArray(object, location); - Word base = (Word) oop.unsignedShiftRight(cardTableShift()); - long startAddress = cardTableStart(); - int displacement = 0; - if (((int) startAddress) == startAddress) { - displacement = (int) startAddress; - } else { - base = base.add(Word.unsigned(cardTableStart())); + public static void serialArrayRangeWriteBarrier(Object object, int startIndex, int length) { + Object dest = FixedValueAnchorNode.getObject(object); + int cardShift = cardTableShift(); + long cardStart = cardTableStart(); + final int scale = arrayIndexScale(Kind.Object); + int header = arrayBaseOffset(Kind.Object); + long dstAddr = GetObjectAddressNode.get(dest); + long start = (dstAddr + header + (long) startIndex * scale) >>> cardShift; + long end = (dstAddr + header + ((long) startIndex + length - 1) * scale) >>> cardShift; + long count = end - start + 1; + while (count-- > 0) { + DirectStoreNode.store((start + cardStart) + count, false, Kind.Boolean); } - base.writeByte(displacement, (byte) 0); } - public static class Templates extends AbstractTemplates { - - private final ResolvedJavaMethod serialFieldWriteBarrier; - private final ResolvedJavaMethod serialArrayWriteBarrier; - private final ResolvedJavaMethod g1PreWriteBarrier; - private final ResolvedJavaMethod g1PostWriteBarrier; + public static class Templates extends AbstractTemplates { - public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) { - super(runtime, assumptions, target, WriteBarrierSnippets.class); - serialFieldWriteBarrier = snippet("serialFieldWriteBarrier", Object.class); - serialArrayWriteBarrier = snippet("serialArrayWriteBarrier", Object.class, Object.class); - g1PreWriteBarrier = snippet("g1PreWriteBarrier", Object.class, Object.class, Object.class, boolean.class); - g1PostWriteBarrier = snippet("g1PostWriteBarrier", Object.class, Object.class, Object.class, boolean.class); + private final SnippetInfo serialArrayWriteBarrier = snippet(WriteBarrierSnippets.class, "serialArrayWriteBarrier"); + private final SnippetInfo serialArrayRangeWriteBarrier = snippet(WriteBarrierSnippets.class, "serialArrayRangeWriteBarrier"); + + public Templates(CodeCacheProvider runtime, Replacements replacements, TargetDescription target) { + super(runtime, replacements, target); } - public void lower(ArrayWriteBarrier arrayWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) { - ResolvedJavaMethod method = serialArrayWriteBarrier; - Key key = new Key(method); - Arguments arguments = new Arguments(); - arguments.add("object", arrayWriteBarrier.getObject()); - arguments.add("location", arrayWriteBarrier.getLocation()); - SnippetTemplate template = cache.get(key, assumptions); - template.instantiate(runtime, arrayWriteBarrier, DEFAULT_REPLACER, arguments); - } - - public void lower(FieldWriteBarrier fieldWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) { - ResolvedJavaMethod method = serialFieldWriteBarrier; - Key key = new Key(method); - Arguments arguments = new Arguments(); - arguments.add("object", fieldWriteBarrier.getObject()); - SnippetTemplate template = cache.get(key, assumptions); - template.instantiate(runtime, fieldWriteBarrier, DEFAULT_REPLACER, arguments); + public void lower(SerialWriteBarrier arrayWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) { + Arguments args = new Arguments(serialArrayWriteBarrier); + args.add("obj", arrayWriteBarrier.getObject()); + args.add("location", arrayWriteBarrier.getLocation()); + args.addConst("usePrecise", arrayWriteBarrier.usePrecise()); + template(args).instantiate(runtime, arrayWriteBarrier, DEFAULT_REPLACER, args); } - public void lower(WriteBarrierPre writeBarrierPre, @SuppressWarnings("unused") LoweringTool tool) { - ResolvedJavaMethod method = g1PreWriteBarrier; - Key key = new Key(method); - key.add("doLoad", writeBarrierPre.doLoad()); - Arguments arguments = new Arguments(); - arguments.add("object", writeBarrierPre.getObject()); - arguments.add("expectedObject", writeBarrierPre.getExpectedObject()); - arguments.add("location", writeBarrierPre.getLocation()); - SnippetTemplate template = cache.get(key, assumptions); - template.instantiate(runtime, writeBarrierPre, DEFAULT_REPLACER, arguments); + public void lower(SerialArrayRangeWriteBarrier arrayRangeWriteBarrier, @SuppressWarnings("unused") LoweringTool tool) { + Arguments args = new Arguments(serialArrayRangeWriteBarrier); + args.add("object", arrayRangeWriteBarrier.getObject()); + args.add("startIndex", arrayRangeWriteBarrier.getStartIndex()); + args.add("length", arrayRangeWriteBarrier.getLength()); + template(args).instantiate(runtime, arrayRangeWriteBarrier, DEFAULT_REPLACER, args); } - - public void lower(WriteBarrierPost writeBarrierPost, @SuppressWarnings("unused") LoweringTool tool) { - ResolvedJavaMethod method = g1PostWriteBarrier; - Key key = new Key(method); - key.add("usePrecise", writeBarrierPost.usePrecise()); - Arguments arguments = new Arguments(); - arguments.add("object", writeBarrierPost.getObject()); - arguments.add("location", writeBarrierPost.getLocation()); - arguments.add("value", writeBarrierPost.getValue()); - SnippetTemplate template = cache.get(key, assumptions); - template.instantiate(runtime, writeBarrierPost, DEFAULT_REPLACER, arguments); - } - } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Mon Apr 15 08:51:19 2013 +0200 @@ -27,13 +27,15 @@ import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; +import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.replacements.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.Snippet.*; -import com.oracle.graal.replacements.SnippetTemplate.*; +import com.oracle.graal.replacements.Snippet.ConstantParameter; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; import com.oracle.graal.word.*; /** @@ -44,15 +46,20 @@ */ public class NewArrayStub extends Stub { - public NewArrayStub(final HotSpotRuntime runtime, Assumptions assumptions, TargetDescription target) { - super(runtime, assumptions, target, NewArrayStubCall.NEW_ARRAY); + public NewArrayStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage, "newArray"); } @Override - protected void populateKey(Key key) { + protected Arguments makeArguments(SnippetInfo stub) { HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) runtime.lookupJavaType(int[].class); - Constant intArrayHub = intArrayType.klass(); - key.add("intArrayHub", intArrayHub).add("log", Boolean.getBoolean("graal.logNewArrayStub")); + + Arguments args = new Arguments(stub); + args.add("hub", null); + args.add("length", null); + args.addConst("intArrayHub", intArrayType.klass()); + args.addConst("log", Boolean.getBoolean("graal.logNewArrayStub")); + return args; } /** @@ -65,7 +72,7 @@ * @param log specifies if logging is enabled */ @Snippet - private static Object newArray(@Parameter("hub") Word hub, @Parameter("length") int length, @ConstantParameter("intArrayHub") Word intArrayHub, @ConstantParameter("log") boolean log) { + private static Object newArray(Word hub, int length, @ConstantParameter Word intArrayHub, @ConstantParameter boolean log) { int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION); int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Mon Apr 15 08:51:19 2013 +0200 @@ -23,18 +23,21 @@ package com.oracle.graal.hotspot.stubs; import static com.oracle.graal.hotspot.nodes.DirectCompareAndSwapNode.*; -import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*; import static com.oracle.graal.hotspot.replacements.HotSpotSnippetUtils.*; import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.replacements.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.Snippet.*; -import com.oracle.graal.replacements.SnippetTemplate.*; +import com.oracle.graal.replacements.Snippet.ConstantParameter; +import com.oracle.graal.replacements.Snippet.Fold; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; import com.oracle.graal.word.*; /** @@ -45,15 +48,19 @@ */ public class NewInstanceStub extends Stub { - public NewInstanceStub(final HotSpotRuntime runtime, Assumptions assumptions, TargetDescription target) { - super(runtime, assumptions, target, NEW_INSTANCE); + public NewInstanceStub(final HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage) { + super(runtime, replacements, target, linkage, "newInstance"); } @Override - protected void populateKey(Key key) { + protected Arguments makeArguments(SnippetInfo stub) { HotSpotResolvedObjectType intArrayType = (HotSpotResolvedObjectType) runtime.lookupJavaType(int[].class); - Constant intArrayHub = intArrayType.klass(); - key.add("intArrayHub", intArrayHub).add("log", Boolean.getBoolean("graal.logNewInstanceStub")); + + Arguments args = new Arguments(stub); + args.add("hub", null); + args.addConst("intArrayHub", intArrayType.klass()); + args.addConst("log", Boolean.getBoolean("graal.logNewInstanceStub")); + return args; } /** @@ -64,7 +71,7 @@ * @param intArrayHub the hub for {@code int[].class} */ @Snippet - private static Object newInstance(@Parameter("hub") Word hub, @ConstantParameter("intArrayHub") Word intArrayHub, @ConstantParameter("log") boolean log) { + private static Object newInstance(Word hub, @ConstantParameter Word intArrayHub, @ConstantParameter boolean log) { int sizeInBytes = hub.readInt(klassInstanceSizeOffset(), FINAL_LOCATION); if (!forceSlowPath() && inlineContiguousAllocationSupported()) { if (hub.readInt(klassStateOffset(), CLASS_STATE_LOCATION) == klassStateFullyInitialized()) { @@ -92,9 +99,6 @@ * operation was unsuccessful */ static Word refillAllocate(Word intArrayHub, int sizeInBytes, boolean log) { - if (useG1GC()) { - return Word.zero(); - } if (!useTLAB()) { return edenAllocate(Word.unsigned(sizeInBytes), log); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,13 +22,9 @@ */ package com.oracle.graal.hotspot.stubs; -import static java.lang.reflect.Modifier.*; - -import java.lang.reflect.*; import java.util.concurrent.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.target.*; @@ -37,26 +33,28 @@ import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.PhasePlan.PhasePosition; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.Snippet.ConstantParameter; import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; -import com.oracle.graal.replacements.SnippetTemplate.Key; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; /** * Base class for implementing some low level code providing the out-of-line slow path for a * snippet. A concrete stub is defined a subclass of this class. *

* Implementation detail: The stub classes re-use some of the functionality for {@link Snippet}s - * purely for convenience (e.g., can re-use the {@link ReplacementsInstaller}). + * purely for convenience (e.g., can re-use the {@link ReplacementsImpl}). */ public abstract class Stub extends AbstractTemplates implements Snippets { /** * The method implementing the stub. */ - protected final HotSpotResolvedJavaMethod stubMethod; + protected final SnippetInfo stubInfo; /** * The linkage information for the stub. @@ -69,23 +67,22 @@ protected InstalledCode stubCode; /** - * Creates a new stub container. The new stub still needs to be {@linkplain #install(Backend) - * installed}. + * Creates a new stub container. The new stub still needs to be + * {@linkplain #getAddress(Backend) installed}. * - * @param descriptor linkage details for a call to the stub + * @param linkage linkage details for a call to the stub */ - @SuppressWarnings("unchecked") - public Stub(HotSpotRuntime runtime, Assumptions assumptions, TargetDescription target, Descriptor descriptor) { - super(runtime, assumptions, target, null); - stubMethod = findStubMethod(runtime, getClass()); - linkage = runtime.registerStub(descriptor, this); - assert linkage != null; + public Stub(HotSpotRuntime runtime, Replacements replacements, TargetDescription target, HotSpotRuntimeCallTarget linkage, String methodName) { + super(runtime, replacements, target); + this.stubInfo = snippet(getClass(), methodName); + this.linkage = linkage; + } /** * Adds the {@linkplain ConstantParameter constant} arguments of this stub. */ - protected abstract void populateKey(Key key); + protected abstract Arguments makeArguments(SnippetInfo stub); protected HotSpotRuntime runtime() { return (HotSpotRuntime) runtime; @@ -95,7 +92,7 @@ * Gets the method implementing this stub. */ public ResolvedJavaMethod getMethod() { - return stubMethod; + return stubInfo.getMethod(); } public HotSpotRuntimeCallTarget getLinkage() { @@ -103,53 +100,37 @@ } /** - * Compiles the code for this stub, installs it and initializes the address used for calls to - * it. + * Ensures the code for this stub is installed. + * + * @return the entry point address for calls to this stub */ - public void install(Backend backend) { - StructuredGraph graph = (StructuredGraph) stubMethod.getCompilerStorage().get(Snippet.class); + public synchronized long getAddress(Backend backend) { + if (stubCode == null) { + Arguments args = makeArguments(stubInfo); + SnippetTemplate template = template(args); + StructuredGraph graph = template.copySpecializedGraph(); - Key key = new Key(stubMethod); - populateKey(key); - SnippetTemplate template = cache.get(key, assumptions); - graph = template.copySpecializedGraph(); - - PhasePlan phasePlan = new PhasePlan(); - GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL); - phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase); - final CompilationResult compResult = GraalCompiler.compileMethod(runtime(), backend, runtime().getTarget(), stubMethod, graph, null, phasePlan, OptimisticOptimizations.ALL, - new SpeculationLog()); - - stubCode = Debug.scope("CodeInstall", new Object[]{runtime(), stubMethod}, new Callable() { + PhasePlan phasePlan = new PhasePlan(); + GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL); + phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase); + final CompilationResult compResult = GraalCompiler.compileMethod(runtime(), replacements, backend, runtime().getTarget(), getMethod(), graph, null, phasePlan, OptimisticOptimizations.ALL, + new SpeculationLog()); - @Override - public InstalledCode call() { - InstalledCode installedCode = runtime().addMethod(stubMethod, compResult); - assert installedCode != null : "error installing stub " + stubMethod; - if (Debug.isDumpEnabled()) { - Debug.dump(new Object[]{compResult, installedCode}, "After code installation"); - } - return installedCode; - } - }); - - assert stubCode != null : "error installing stub " + stubMethod; - linkage.setAddress(stubCode.getStart()); - } + stubCode = Debug.scope("CodeInstall", new Object[]{runtime(), getMethod()}, new Callable() { - /** - * Finds the static method annotated with {@link Snippet} in a given class of which there must - * be exactly one. - */ - private static HotSpotResolvedJavaMethod findStubMethod(HotSpotRuntime runtime, Class stubClass) { - HotSpotResolvedJavaMethod m = null; - for (Method candidate : stubClass.getDeclaredMethods()) { - if (isStatic(candidate.getModifiers()) && candidate.getAnnotation(Snippet.class) != null) { - assert m == null : "more than one method annotated with @" + Snippet.class.getSimpleName() + " in " + stubClass; - m = (HotSpotResolvedJavaMethod) runtime.lookupJavaMethod(candidate); - } + @Override + public InstalledCode call() { + InstalledCode installedCode = runtime().addMethod(getMethod(), compResult); + assert installedCode != null : "error installing stub " + getMethod(); + if (Debug.isDumpEnabled()) { + Debug.dump(new Object[]{compResult, installedCode}, "After code installation"); + } + return installedCode; + } + }); + + assert stubCode != null : "error installing stub " + getMethod(); } - assert m != null : "no static method annotated with @" + Snippet.class.getSimpleName() + " in " + stubClass; - return m; + return stubCode.getStart(); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeDisassembler.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeDisassembler.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeDisassembler.java Mon Apr 15 08:51:19 2013 +0200 @@ -102,6 +102,13 @@ buf.append(String.format("#%-10s // %s", cpi + ", " + stream.readUByte(bci + 3), calleeDesc)); break; } + case INVOKEDYNAMIC: { + int cpi = stream.readCPI4(); + JavaMethod callee = cp.lookupMethod(cpi, opcode); + String calleeDesc = callee.getDeclaringClass().getName().equals(method.getDeclaringClass().getName()) ? MetaUtil.format("%n:(%P)%R", callee) : MetaUtil.format("%H.%n:(%P)%R", callee); + buf.append(String.format("#%-10d // %s", cpi, calleeDesc)); + break; + } case LDC : case LDC_W : case LDC2_W : { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,6 +23,7 @@ package com.oracle.graal.java; import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; public class GraphBuilderConfiguration { @@ -30,6 +31,13 @@ private final boolean omitAllExceptionEdges; private ResolvedJavaType[] skippedExceptionTypes; + /** + * When the graph builder is in eager infopoint mode, it inserts {@link InfopointNode}s in + * places where no safepoints would be inserted: inlining boundaries, and line number switches. + * This is relevant when code is to be generated for native, machine-code level debugging. + */ + private boolean eagerInfopointMode; + protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges) { this.eagerResolving = eagerResolving; this.omitAllExceptionEdges = omitAllExceptionEdges; @@ -39,6 +47,10 @@ this.skippedExceptionTypes = skippedExceptionTypes; } + public void setEagerInfopointMode(boolean eagerInfopointMode) { + this.eagerInfopointMode = eagerInfopointMode; + } + public ResolvedJavaType[] getSkippedExceptionTypes() { return skippedExceptionTypes; } @@ -51,6 +63,10 @@ return omitAllExceptionEdges; } + public boolean eagerInfopointMode() { + return eagerInfopointMode; + } + public static GraphBuilderConfiguration getDefault() { return new GraphBuilderConfiguration(false, false); } @@ -64,9 +80,9 @@ } /** - * Returns {@code true} if it is an error for a class/field/method resolution to fail. - * The default is the same result as returned by {@link #eagerResolving()}. - * However, it may be overridden to allow failure even when {@link #eagerResolving} is {@code true}. + * Returns {@code true} if it is an error for a class/field/method resolution to fail. The + * default is the same result as returned by {@link #eagerResolving()}. However, it may be + * overridden to allow failure even when {@link #eagerResolving} is {@code true}. */ public boolean unresolvedIsError() { return eagerResolving; diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -23,6 +23,7 @@ package com.oracle.graal.java; import static com.oracle.graal.api.code.DeoptimizationAction.*; +import static com.oracle.graal.api.code.TypeCheckHints.*; import static com.oracle.graal.api.meta.DeoptimizationReason.*; import static com.oracle.graal.bytecode.Bytecodes.*; import static java.lang.reflect.Modifier.*; @@ -74,6 +75,10 @@ */ public static final int TRACELEVEL_STATE = 2; + private LineNumberTable lnt; + private int previousLineNumber; + private int currentLineNumber; + protected StructuredGraph currentGraph; private final MetaAccessProvider runtime; @@ -140,6 +145,10 @@ @Override protected void run(StructuredGraph graph) { method = graph.method(); + if (graphBuilderConfig.eagerInfopointMode()) { + lnt = method.getLineNumberTable(); + previousLineNumber = -1; + } entryBCI = graph.getEntryBCI(); profilingInfo = method.getProfilingInfo(); assert method.getCode() != null : "method must contain bytecodes: " + method; @@ -192,6 +201,13 @@ } frameState.clearNonLiveLocals(blockMap.startBlock.localsLiveIn); + if (graphBuilderConfig.eagerInfopointMode()) { + ((StateSplit) lastInstr).setStateAfter(frameState.create(0)); + InfopointNode ipn = currentGraph.add(new InfopointNode(InfopointReason.METHOD_START)); + lastInstr.setNext(ipn); + lastInstr = ipn; + } + // finish the start block ((StateSplit) lastInstr).setStateAfter(frameState.create(0)); @@ -771,12 +787,12 @@ } private JavaTypeProfile getProfileForTypeCheck(ResolvedJavaType type) { - if (!optimisticOpts.useTypeCheckHints() || TypeCheckHints.canHaveSubtype(type)) { + if (!optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) { return null; } else { ResolvedJavaType uniqueSubtype = type.findUniqueConcreteSubtype(); if (uniqueSubtype != null) { - return new JavaTypeProfile(0.0D, new ProfiledType(uniqueSubtype, 1.0D)); + return new JavaTypeProfile(profilingInfo.getNullSeen(bci()), 0.0D, new ProfiledType(uniqueSubtype, 1.0D)); } else { return profilingInfo.getTypeProfile(bci()); } @@ -960,7 +976,7 @@ protected void emitExplicitExceptions(ValueNode receiver, ValueNode outOfBoundsIndex) { assert receiver != null; - if (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE) { + if (graphBuilderConfig.omitAllExceptionEdges() || (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE)) { return; } @@ -1053,10 +1069,35 @@ } } + private void genInvokeDynamic(JavaMethod target) { + if (target instanceof ResolvedJavaMethod) { + Object appendix = constantPool.lookupAppendix(stream.readCPI4(), Bytecodes.INVOKEDYNAMIC); + if (appendix != null) { + frameState.apush(ConstantNode.forObject(appendix, runtime, currentGraph)); + } + ValueNode[] args = frameState.popArguments(target.getSignature().getParameterSlots(false), target.getSignature().getParameterCount(false)); + appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args); + } else { + handleUnresolvedInvoke(target, InvokeKind.Static); + } + } + private void genInvokeVirtual(JavaMethod target) { if (target instanceof ResolvedJavaMethod) { - ValueNode[] args = frameState.popArguments(target.getSignature().getParameterSlots(true), target.getSignature().getParameterCount(true)); - genInvokeIndirect(InvokeKind.Virtual, (ResolvedJavaMethod) target, args); + // Special handling for runtimes that rewrite an invocation of MethodHandle.invoke(...) + // or MethodHandle.invokeExact(...) to a static adapter. HotSpot does this - see + // https://wikis.oracle.com/display/HotSpotInternals/Method+handles+and+invokedynamic + boolean hasReceiver = !isStatic(((ResolvedJavaMethod) target).getModifiers()); + Object appendix = constantPool.lookupAppendix(stream.readCPI(), Bytecodes.INVOKEVIRTUAL); + if (appendix != null) { + frameState.apush(ConstantNode.forObject(appendix, runtime, currentGraph)); + } + ValueNode[] args = frameState.popArguments(target.getSignature().getParameterSlots(hasReceiver), target.getSignature().getParameterCount(hasReceiver)); + if (hasReceiver) { + genInvokeIndirect(InvokeKind.Virtual, (ResolvedJavaMethod) target, args); + } else { + appendInvoke(InvokeKind.Static, (ResolvedJavaMethod) target, args); + } } else { handleUnresolvedInvoke(target, InvokeKind.Virtual); } @@ -1492,7 +1533,7 @@ } private void processBlock(Block block) { - // Ignore blocks that have no predecessors by the time it their bytecodes are parsed + // Ignore blocks that have no predecessors by the time their bytecodes are parsed if (block == null || block.firstInstruction == null) { Debug.log("Ignoring block %s", block); return; @@ -1573,6 +1614,12 @@ } ReturnNode returnNode = currentGraph.add(new ReturnNode(x)); + if (graphBuilderConfig.eagerInfopointMode()) { + InfopointNode ipn = currentGraph.add(new InfopointNode(InfopointReason.METHOD_END)); + ipn.setStateAfter(frameState.create(FrameState.AFTER_BCI)); + append(ipn); + } + append(returnNode); } @@ -1683,6 +1730,16 @@ BytecodesParsed.add(block.endBci - bci); while (bci < endBCI) { + if (graphBuilderConfig.eagerInfopointMode() && lnt != null) { + currentLineNumber = lnt.getLineNumber(bci); + if (currentLineNumber != previousLineNumber) { + InfopointNode ipn = currentGraph.add(new InfopointNode(InfopointReason.LINE_NUMBER)); + ipn.setStateAfter(frameState.create(bci)); + append(ipn); + previousLineNumber = currentLineNumber; + } + } + // read the opcode int opcode = stream.currentBC(); traceState(); @@ -1936,6 +1993,7 @@ case INVOKESPECIAL : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break; case INVOKESTATIC : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break; case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break; + case INVOKEDYNAMIC : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break; case NEW : genNewInstance(stream.readCPI()); break; case NEWARRAY : genNewPrimitiveArray(stream.readLocalIndex()); break; case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_setOut.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_setOut.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_setOut.java Mon Apr 15 08:51:19 2013 +0200 @@ -46,6 +46,7 @@ return sum; } + // CheckStyle: stop system..print check private static void doPrint(int n) { for (int i = 0; i < n; i++) { System.out.print('x'); @@ -56,6 +57,8 @@ System.out.println(test(10000)); } + // CheckStyle: resume system..print check + @LongTest public void run0() throws Throwable { runTest("test", 10000); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java Mon Apr 15 08:51:19 2013 +0200 @@ -35,43 +35,14 @@ public class AMD64Call { - @Opcode("CALL_DIRECT") - public static class DirectCallOp extends AMD64LIRInstruction implements StandardOp.CallOp { + public abstract static class CallOp extends AMD64LIRInstruction { @Def({REG, ILLEGAL}) protected Value result; @Use({REG, STACK}) protected Value[] parameters; @Temp protected Value[] temps; @State protected LIRFrameState state; - protected final ResolvedJavaMethod callTarget; - - public DirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { - this.callTarget = callTarget; - this.result = result; - this.parameters = parameters; - this.state = state; - this.temps = temps; - assert temps != null; - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - directCall(tasm, masm, callTarget, null, true, state); - } - } - - @Opcode("CALL_NEAR_RUNTIME") - public static class DirectNearRuntimeCallOp extends AMD64LIRInstruction implements StandardOp.CallOp { - - @Def({REG, ILLEGAL}) protected Value result; - @Use({REG, STACK}) protected Value[] parameters; - @Temp protected Value[] temps; - @State protected LIRFrameState state; - - protected final RuntimeCallTarget callTarget; - - public DirectNearRuntimeCallOp(RuntimeCallTarget callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { - this.callTarget = callTarget; + public CallOp(Value result, Value[] parameters, Value[] temps, LIRFrameState state) { this.result = result; this.parameters = parameters; this.state = state; @@ -80,57 +51,43 @@ } @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - directCall(tasm, masm, callTarget, null, false, state); + public boolean hasCall() { + return true; } } - @Opcode("CALL_FAR_RUNTIME") - public static class DirectFarRuntimeCallOp extends AMD64LIRInstruction implements StandardOp.CallOp { + public abstract static class MethodCallOp extends CallOp { - @Def({REG, ILLEGAL}) protected Value result; - @Use({REG, STACK}) protected Value[] parameters; - @Temp protected Value[] temps; - @State protected LIRFrameState state; - @Temp({REG}) protected AllocatableValue callTemp; + protected final ResolvedJavaMethod callTarget; - protected final RuntimeCallTarget callTarget; - - public DirectFarRuntimeCallOp(LIRGeneratorTool gen, RuntimeCallTarget callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + public MethodCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(result, parameters, temps, state); this.callTarget = callTarget; - this.result = result; - this.parameters = parameters; - this.state = state; - this.temps = temps; - assert temps != null; - callTemp = gen.newVariable(Kind.Long); + } + + } + + @Opcode("CALL_DIRECT") + public static class DirectCallOp extends MethodCallOp { + + public DirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(callTarget, result, parameters, temps, state); } @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - directCall(tasm, masm, callTarget, ((RegisterValue) callTemp).getRegister(), false, state); + directCall(tasm, masm, callTarget, null, true, state); } } @Opcode("CALL_INDIRECT") - public static class IndirectCallOp extends AMD64LIRInstruction implements StandardOp.CallOp { + public static class IndirectCallOp extends MethodCallOp { - @Def({REG, ILLEGAL}) protected Value result; - @Use({REG, STACK}) protected Value[] parameters; @Use({REG}) protected Value targetAddress; - @Temp protected Value[] temps; - @State protected LIRFrameState state; - protected final InvokeTarget callTarget; - - public IndirectCallOp(InvokeTarget callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, LIRFrameState state) { - this.callTarget = callTarget; - this.result = result; - this.parameters = parameters; + public IndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, LIRFrameState state) { + super(callTarget, result, parameters, temps, state); this.targetAddress = targetAddress; - this.state = state; - this.temps = temps; - assert temps != null; } @Override @@ -145,6 +102,50 @@ } } + public abstract static class RuntimeCallOp extends CallOp { + + protected final RuntimeCallTarget callTarget; + + public RuntimeCallOp(RuntimeCallTarget callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(result, parameters, temps, state); + this.callTarget = callTarget; + } + + @Override + public boolean hasCall() { + return !callTarget.preservesRegisters(); + } + } + + @Opcode("CALL_NEAR_RUNTIME") + public static class DirectNearRuntimeCallOp extends RuntimeCallOp { + + public DirectNearRuntimeCallOp(RuntimeCallTarget callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(callTarget, result, parameters, temps, state); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + directCall(tasm, masm, callTarget, null, false, state); + } + } + + @Opcode("CALL_FAR_RUNTIME") + public static class DirectFarRuntimeCallOp extends RuntimeCallOp { + + @Temp({REG}) protected AllocatableValue callTemp; + + public DirectFarRuntimeCallOp(LIRGeneratorTool gen, RuntimeCallTarget callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + super(callTarget, result, parameters, temps, state); + callTemp = gen.newVariable(Kind.Long); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + directCall(tasm, masm, callTarget, ((RegisterValue) callTemp).getRegister(), false, state); + } + } + public static void directCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, InvokeTarget callTarget, Register scratch, boolean align, LIRFrameState info) { if (align) { emitAlignmentForDirectCall(tasm, masm); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXArithmetic.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXArithmetic.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXArithmetic.java Mon Apr 15 08:51:19 2013 +0200 @@ -36,9 +36,9 @@ public enum PTXArithmetic { IADD, ISUB, IMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR, LADD, LSUB, LMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR, - FADD, FSUB, FMUL, FDIV, FAND, FOR, FXOR, - DADD, DSUB, DMUL, DDIV, DAND, DOR, DXOR, - INEG, LNEG, + FADD, FSUB, FMUL, FDIV, FREM, FAND, FOR, FXOR, + DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR, + INEG, LNEG, FNEG, DNEG, I2L, L2I, I2B, I2C, I2S, F2D, D2F, I2F, I2D, F2I, D2I, @@ -46,6 +46,47 @@ MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L; + /** + * Unary operation with separate source and destination operand. + */ + public static class Unary2Op extends PTXLIRInstruction { + @Opcode private final PTXArithmetic opcode; + @Def({REG}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + + public Unary2Op(PTXArithmetic opcode, AllocatableValue result, AllocatableValue x) { + this.opcode = opcode; + this.result = result; + this.x = x; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + PTXMove.move(tasm, masm, result, x); + emit(tasm, masm, opcode, result, x, null); + } + } + + /** + * Unary operation with single operand for source and destination. + */ + public static class Unary1Op extends PTXLIRInstruction { + @Opcode private final PTXArithmetic opcode; + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + + public Unary1Op(PTXArithmetic opcode, AllocatableValue result, AllocatableValue x) { + this.opcode = opcode; + this.result = result; + this.x = x; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + emit(tasm, masm, opcode, result); + } + } + public static class Op1Reg extends PTXLIRInstruction { @Opcode private final PTXArithmetic opcode; @Def({REG, HINT}) protected Value result; @@ -213,23 +254,70 @@ } } - - @SuppressWarnings("unused") - protected static void emit(TargetMethodAssembler tasm, PTXAssembler masm, PTXArithmetic opcode, Value result) { + protected static void emit(@SuppressWarnings("unused") TargetMethodAssembler tasm, + PTXAssembler masm, PTXArithmetic opcode, Value result) { switch (opcode) { - default: throw GraalInternalError.shouldNotReachHere(); + case L2I: masm.and_b32(asIntReg(result), asIntReg(result), 0xFFFFFFFF); break; + case I2C: masm.and_b16(asIntReg(result), asIntReg(result), (short) 0xFFFF); break; + default: + throw GraalInternalError.shouldNotReachHere("missing: " + opcode); } } public static void emit(TargetMethodAssembler tasm, PTXAssembler masm, PTXArithmetic opcode, Value dst, Value src, LIRFrameState info) { int exceptionOffset = -1; if (isRegister(src)) { - Register a = asIntReg(src); - Register d = asIntReg(dst); switch (opcode) { - case INEG: masm.neg_s32(d, a); break; + case INEG: + masm.neg_s32(asIntReg(dst), asIntReg(src)); + break; + case I2L: + masm.cvt_s64_s32(asLongReg(dst), asIntReg(src)); + break; + case I2C: + masm.cvt_b16_s32(asIntReg(dst), asIntReg(src)); + break; + case I2B: + masm.cvt_s8_s32(asIntReg(dst), asIntReg(src)); + break; + case I2F: + masm.cvt_f32_s32(asFloatReg(dst), asIntReg(src)); + break; + case I2D: + masm.cvt_f64_s32(asDoubleReg(dst), asIntReg(src)); + break; + case FNEG: + masm.neg_f32(asFloatReg(dst), asFloatReg(src)); + break; + case DNEG: + masm.neg_f64(asDoubleReg(dst), asDoubleReg(src)); + break; + case F2I: + masm.cvt_s32_f32(asIntReg(dst), asFloatReg(src)); + break; + case F2L: + masm.cvt_s64_f32(asLongReg(dst), asFloatReg(src)); + break; + case F2D: + masm.cvt_f64_f32(asDoubleReg(dst), asFloatReg(src)); + break; + case D2I: + masm.cvt_s32_f64(asIntReg(dst), asDoubleReg(src)); + break; + case D2L: + masm.cvt_s64_f64(asLongReg(dst), asDoubleReg(src)); + break; + case D2F: + masm.cvt_f32_f64(asFloatReg(dst), asDoubleReg(src)); + break; + case LSHL: + masm.shl_s64(asLongReg(dst), asLongReg(dst), asIntReg(src)); + break; + case LSHR: + masm.shr_s64(asLongReg(dst), asLongReg(dst), asIntReg(src)); + break; default: - throw GraalInternalError.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere("missing: " + opcode); } } else if (isConstant(src)) { switch (opcode) { @@ -252,33 +340,74 @@ public static void emit(TargetMethodAssembler tasm, PTXAssembler masm, PTXArithmetic opcode, Value dst, Value src1, Value src2, LIRFrameState info) { int exceptionOffset = -1; if (isConstant(src1)) { - int a = tasm.asIntConst(src1); - Register b = asIntReg(src2); - Register d = asIntReg(dst); switch (opcode) { - case ISUB: masm.sub_s32(d, a, b); break; - case IAND: masm.and_b32(d, b, a); break; - default: throw GraalInternalError.shouldNotReachHere(); + case ISUB: masm.sub_s32(asIntReg(dst), tasm.asIntConst(src1), asIntReg(src2)); break; + case IAND: masm.and_b32(asIntReg(dst), asIntReg(src2), tasm.asIntConst(src1)); break; + case IDIV: masm.div_s32(asIntReg(dst), tasm.asIntConst(src1), asIntReg(src2)); break; + case FSUB: masm.sub_f32(asFloatReg(dst), tasm.asFloatConst(src1), asFloatReg(src2)); break; + case FDIV: masm.div_f32(asFloatReg(dst), tasm.asFloatConst(src1), asFloatReg(src2)); break; + case DSUB: masm.sub_f64(asDoubleReg(dst), tasm.asDoubleConst(src1), asDoubleReg(src2)); break; + case DDIV: masm.div_f64(asDoubleReg(dst), tasm.asDoubleConst(src1), asDoubleReg(src2)); break; + default: + throw GraalInternalError.shouldNotReachHere(); } } else if (isConstant(src2)) { - Register a = asIntReg(src1); - int b = tasm.asIntConst(src2); - Register d = asIntReg(dst); switch (opcode) { - case IADD: masm.add_s32(d, a, b); break; - case IAND: masm.and_b32(d, a, b); break; - case IUSHR: masm.shr_u32(d, a, b); break; - default: throw GraalInternalError.shouldNotReachHere(); + case IADD: masm.add_s32(asIntReg(dst), asIntReg(src1), tasm.asIntConst(src2)); break; + case ISUB: masm.sub_s32(asIntReg(dst), asIntReg(src1), tasm.asIntConst(src2)); break; + case IMUL: masm.mul_s32(asIntReg(dst), asIntReg(src1), tasm.asIntConst(src2)); break; + case IAND: masm.and_b32(asIntReg(dst), asIntReg(src1), tasm.asIntConst(src2)); break; + case ISHL: masm.shl_s32(asIntReg(dst), asIntReg(src1), tasm.asIntConst(src2)); break; + case ISHR: masm.shr_s32(asIntReg(dst), asIntReg(src1), tasm.asIntConst(src2)); break; + case IUSHR: masm.shr_u32(asIntReg(dst), asIntReg(src1), tasm.asIntConst(src2)); break; + case IXOR: masm.xor_b32(asIntReg(dst), asIntReg(src1), tasm.asIntConst(src2)); break; + case LXOR: masm.xor_b64(asLongReg(dst), asLongReg(src1), tasm.asLongConst(src2)); break; + case LUSHR: masm.shr_u64(asLongReg(dst), asLongReg(src1), tasm.asLongConst(src2)); break; + case FADD: masm.add_f32(asFloatReg(dst), asFloatReg(src1), tasm.asFloatConst(src2)); break; + case FMUL: masm.mul_f32(asFloatReg(dst), asFloatReg(src1), tasm.asFloatConst(src2)); break; + case FDIV: masm.div_f32(asFloatReg(dst), asFloatReg(src1), tasm.asFloatConst(src2)); break; + case DADD: masm.add_f64(asDoubleReg(dst), asDoubleReg(src1), tasm.asDoubleConst(src2)); break; + case DMUL: masm.mul_f64(asDoubleReg(dst), asDoubleReg(src1), tasm.asDoubleConst(src2)); break; + case DDIV: masm.div_f64(asDoubleReg(dst), asDoubleReg(src1), tasm.asDoubleConst(src2)); break; + default: + throw GraalInternalError.shouldNotReachHere(); } } else { - Register a = asIntReg(src1); - Register b = asIntReg(src2); - Register d = asIntReg(dst); switch (opcode) { - case IADD: masm.add_s32(d, a, b); break; - case ISUB: masm.sub_s32(d, a, b); break; - case IMUL: masm.mul_s32(d, a, b); break; - default: throw GraalInternalError.shouldNotReachHere(); + case IADD: masm.add_s32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; + case ISUB: masm.sub_s32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; + case IMUL: masm.mul_s32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; + case IDIV: masm.div_s32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; + case IAND: masm.and_b32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; + case IOR: masm.or_b32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; + case IXOR: masm.xor_b32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; + case ISHL: masm.shl_s32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; + case ISHR: masm.shr_s32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; + case IUSHR: masm.shr_u32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; + case IREM: masm.rem_s32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; + case LADD: masm.add_s64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; + case LSUB: masm.sub_s64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; + case LMUL: masm.mul_s64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; + case LDIV: masm.div_s64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; + case LAND: masm.and_b64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; + case LOR: masm.or_b64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; + case LXOR: masm.xor_b64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; + case LSHL: masm.shl_s64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; + case LSHR: masm.shr_s64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; + case LUSHR: masm.shr_u64(asLongReg(dst), asLongReg(src1), asIntReg(src2)); break; + case LREM: masm.rem_s64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; + case FADD: masm.add_f32(asFloatReg(dst), asFloatReg(src1), asFloatReg(src2)); break; + case FSUB: masm.sub_f32(asFloatReg(dst), asFloatReg(src1), asFloatReg(src2)); break; + case FMUL: masm.mul_f32(asFloatReg(dst), asFloatReg(src1), asFloatReg(src2)); break; + case FDIV: masm.div_f32(asFloatReg(dst), asFloatReg(src1), asFloatReg(src2)); break; + case FREM: masm.div_f32(asFloatReg(dst), asFloatReg(src1), asFloatReg(src2)); break; + case DADD: masm.add_f64(asDoubleReg(dst), asDoubleReg(src1), asDoubleReg(src2)); break; + case DSUB: masm.sub_f64(asDoubleReg(dst), asDoubleReg(src1), asDoubleReg(src2)); break; + case DMUL: masm.mul_f64(asDoubleReg(dst), asDoubleReg(src1), asDoubleReg(src2)); break; + case DDIV: masm.div_f64(asDoubleReg(dst), asDoubleReg(src1), asDoubleReg(src2)); break; + case DREM: masm.div_f64(asDoubleReg(dst), asDoubleReg(src1), asDoubleReg(src2)); break; + default: + throw GraalInternalError.shouldNotReachHere("missing: " + opcode); } } @@ -289,9 +418,11 @@ } private static void verifyKind(PTXArithmetic opcode, Value result, Value x, Value y) { - assert (opcode.name().startsWith("I") && result.getKind() == Kind.Int && x.getKind().getStackKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) + if (((opcode.name().startsWith("I") && result.getKind() == Kind.Int && x.getKind().getStackKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) || (opcode.name().startsWith("L") && result.getKind() == Kind.Long && x.getKind() == Kind.Long && y.getKind() == Kind.Long) || (opcode.name().startsWith("F") && result.getKind() == Kind.Float && x.getKind() == Kind.Float && y.getKind() == Kind.Float) - || (opcode.name().startsWith("D") && result.getKind() == Kind.Double && x.getKind() == Kind.Double && y.getKind() == Kind.Double); + || (opcode.name().startsWith("D") && result.getKind() == Kind.Double && x.getKind() == Kind.Double && y.getKind() == Kind.Double)) == false) { + throw GraalInternalError.shouldNotReachHere("opcode: " + opcode.name() + " x: " + x.getKind() + " y: " + y.getKind()); + } } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXCompare.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXCompare.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXCompare.java Mon Apr 15 08:51:19 2013 +0200 @@ -65,11 +65,15 @@ public static void emit(TargetMethodAssembler tasm, PTXAssembler masm, PTXCompare opcode, Condition condition, Value x, Value y) { if (isConstant(x)) { - int a = tasm.asIntConst(x); - Register b = asIntReg(y); switch (opcode) { case ICMP: - emitCompareConstReg(masm, condition, a, b); + emitCompareConstReg(masm, condition, tasm.asIntConst(x), asIntReg(y)); + break; + case FCMP: + emitCompareConstReg(masm, condition, tasm.asFloatConst(x), asFloatReg(y)); + break; + case DCMP: + emitCompareConstReg(masm, condition, tasm.asDoubleConst(x), asDoubleReg(y)); break; default: throw GraalInternalError.shouldNotReachHere(); @@ -101,18 +105,75 @@ throw GraalInternalError.shouldNotReachHere(); } } else { - Register a = asIntReg(x); - Register b = asIntReg(y); switch (opcode) { case ICMP: - emitCompareRegReg(masm, condition, a, b); + emitCompareRegReg(masm, condition, asIntReg(x), asIntReg(y)); + break; + case LCMP: + emitCompareRegReg(masm, condition, asLongReg(x), asLongReg(y)); + break; + case FCMP: + emitCompareRegReg(masm, condition, asFloatReg(x), asFloatReg(y)); + break; + case DCMP: + emitCompareRegReg(masm, condition, asDoubleReg(x), asDoubleReg(y)); break; default: - throw GraalInternalError.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere("missing: " + opcode); } } } + private static void emitCompareConstReg(PTXAssembler masm, Condition condition, float a, Register b) { + switch (condition) { + case EQ: + masm.setp_eq_f32(a, b); + break; + case NE: + masm.setp_ne_f32(a, b); + break; + case LT: + masm.setp_lt_f32(a, b); + break; + case LE: + masm.setp_le_f32(a, b); + break; + case GT: + masm.setp_gt_f32(a, b); + break; + case GE: + masm.setp_ge_f32(a, b); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + private static void emitCompareConstReg(PTXAssembler masm, Condition condition, double a, Register b) { + switch (condition) { + case EQ: + masm.setp_eq_f64(a, b); + break; + case NE: + masm.setp_ne_f64(a, b); + break; + case LT: + masm.setp_lt_f64(a, b); + break; + case LE: + masm.setp_le_f64(a, b); + break; + case GT: + masm.setp_gt_f64(a, b); + break; + case GE: + masm.setp_ge_f64(a, b); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + private static void emitCompareConstReg(PTXAssembler masm, Condition condition, int a, Register b) { switch (condition) { case EQ: diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,14 +22,28 @@ */ package com.oracle.graal.lir.ptx; +import static com.oracle.graal.api.code.ValueUtil.asIntReg; +import static com.oracle.graal.api.code.ValueUtil.asLongReg; +import static com.oracle.graal.api.code.ValueUtil.asObjectReg; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.*; -import com.oracle.graal.asm.ptx.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; -import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.api.code.Register; +import com.oracle.graal.api.code.CompilationResult.JumpTable; +import com.oracle.graal.api.meta.Constant; +import com.oracle.graal.api.meta.Kind; +import com.oracle.graal.api.meta.Value; +import com.oracle.graal.asm.Buffer; +import com.oracle.graal.asm.Label; +import com.oracle.graal.asm.NumUtil; +import com.oracle.graal.asm.ptx.AbstractPTXAssembler; +import com.oracle.graal.asm.ptx.PTXAssembler; +import com.oracle.graal.graph.GraalInternalError; +import com.oracle.graal.lir.LabelRef; +import com.oracle.graal.lir.StandardOp; +import com.oracle.graal.lir.StandardOp.FallThroughOp; +import com.oracle.graal.lir.Variable; +import com.oracle.graal.lir.asm.TargetMethodAssembler; +import com.oracle.graal.nodes.calc.Condition; public class PTXControlFlow { @@ -64,7 +78,7 @@ public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { masm.at(); Label l = destination.label(); - l.addPatchAt(tasm.asm.codeBuffer.position()); + // l.addPatchAt(tasm.asm.codeBuffer.position()); String target = l.isBound() ? "L" + l.toString() : AbstractPTXAssembler.UNBOUND_TARGET; masm.bra(target); } @@ -80,4 +94,176 @@ condition = condition.negate(); } } + + @SuppressWarnings("unused") + public static class CondMoveOp extends PTXLIRInstruction { + @Def({REG, HINT}) protected Value result; + @Alive({REG}) protected Value trueValue; + @Use({REG, STACK, CONST}) protected Value falseValue; + private final Condition condition; + + public CondMoveOp(Variable result, Condition condition, Variable trueValue, Value falseValue) { + this.result = result; + this.condition = condition; + this.trueValue = trueValue; + this.falseValue = falseValue; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + // cmove(tasm, masm, result, false, condition, false, trueValue, falseValue); + // see 8.3 Predicated Execution p. 61 of PTX ISA 3.1 + throw new InternalError("NYI"); + } + } + + @SuppressWarnings("unused") + public static class FloatCondMoveOp extends PTXLIRInstruction { + @Def({REG}) protected Value result; + @Alive({REG}) protected Value trueValue; + @Alive({REG}) protected Value falseValue; + private final Condition condition; + private final boolean unorderedIsTrue; + + public FloatCondMoveOp(Variable result, Condition condition, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) { + this.result = result; + this.condition = condition; + this.unorderedIsTrue = unorderedIsTrue; + this.trueValue = trueValue; + this.falseValue = falseValue; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + // cmove(tasm, masm, result, true, condition, unorderedIsTrue, trueValue, falseValue); + // see 8.3 Predicated Execution p. 61 of PTX ISA 3.1 + throw new InternalError("NYI"); + } + } + + public static class SequentialSwitchOp extends PTXLIRInstruction implements FallThroughOp { + @Use({CONST}) protected Constant[] keyConstants; + private final LabelRef[] keyTargets; + private LabelRef defaultTarget; + @Alive({REG}) protected Value key; + @Temp({REG, ILLEGAL}) protected Value scratch; + + public SequentialSwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, + Value key, Value scratch) { + assert keyConstants.length == keyTargets.length; + this.keyConstants = keyConstants; + this.keyTargets = keyTargets; + this.defaultTarget = defaultTarget; + this.key = key; + this.scratch = scratch; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + if (key.getKind() == Kind.Int) { + Register intKey = asIntReg(key); + for (int i = 0; i < keyConstants.length; i++) { + if (tasm.runtime.needsDataPatch(keyConstants[i])) { + tasm.recordDataReferenceInCode(keyConstants[i], 0, true); + } + long lc = keyConstants[i].asLong(); + assert NumUtil.isInt(lc); + masm.setp_eq_s32((int) lc, intKey); + masm.at(); + Label l = keyTargets[i].label(); + l.addPatchAt(tasm.asm.codeBuffer.position()); + String target = l.isBound() ? "L" + l.toString() : AbstractPTXAssembler.UNBOUND_TARGET; + masm.bra(target); + } + } else if (key.getKind() == Kind.Long) { + Register longKey = asLongReg(key); + for (int i = 0; i < keyConstants.length; i++) { + masm.setp_eq_s64(tasm.asLongConst(keyConstants[i]), longKey); + masm.at(); + Label l = keyTargets[i].label(); + l.addPatchAt(tasm.asm.codeBuffer.position()); + String target = l.isBound() ? "L" + l.toString() : AbstractPTXAssembler.UNBOUND_TARGET; + masm.bra(target); + } + } else if (key.getKind() == Kind.Object) { + Register intKey = asObjectReg(key); + Register temp = asObjectReg(scratch); + for (int i = 0; i < keyConstants.length; i++) { + PTXMove.move(tasm, masm, temp.asValue(Kind.Object), keyConstants[i]); + masm.setp_eq_u32(intKey, temp); + masm.at(); + masm.bra(keyTargets[i].label().toString()); + } + } else { + throw new GraalInternalError("sequential switch only supported for int, long and object"); + } + if (defaultTarget != null) { + masm.jmp(defaultTarget.label()); + } else { + // masm.hlt(); + } + } + + @Override + public LabelRef fallThroughTarget() { + return defaultTarget; + } + + @Override + public void setFallThroughTarget(LabelRef target) { + defaultTarget = target; + } + } + + public static class TableSwitchOp extends PTXLIRInstruction { + private final int lowKey; + private final LabelRef defaultTarget; + private final LabelRef[] targets; + @Alive protected Value index; + @Temp protected Value scratch; + + public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, + Variable index, Variable scratch) { + this.lowKey = lowKey; + this.defaultTarget = defaultTarget; + this.targets = targets; + this.index = index; + this.scratch = scratch; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + tableswitch(tasm, masm, lowKey, defaultTarget, targets, asIntReg(index), asLongReg(scratch)); + } + } + + @SuppressWarnings("unused") + private static void tableswitch(TargetMethodAssembler tasm, PTXAssembler masm, int lowKey, + LabelRef defaultTarget, LabelRef[] targets, + Register value, Register scratch) { + Buffer buf = masm.codeBuffer; + // Compare index against jump table bounds + int highKey = lowKey + targets.length - 1; + if (lowKey != 0) { + // subtract the low value from the switch value + masm.sub_s32(value, value, lowKey); + masm.setp_gt_s32(value, highKey - lowKey); + } else { + masm.setp_gt_s32(value, highKey); + } + + // Jump to default target if index is not within the jump table + if (defaultTarget != null) { + masm.at(); + masm.bra(defaultTarget.label().toString()); + } + + // address of jump table + int tablePos = buf.position(); + + JumpTable jt = new JumpTable(tablePos, lowKey, highKey, 4); + tasm.compilationResult.addAnnotation(jt); + + // PTX: unimp: tableswitch extract + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java Mon Apr 15 08:51:19 2013 +0200 @@ -133,9 +133,27 @@ public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { PTXAddress addr = address.toAddress(); switch (address.getKind()) { + case Byte: + masm.ld_global_s8(asRegister(result), addr.getBase(), addr.getDisplacement()); + break; + case Short: + masm.ld_global_s16(asRegister(result), addr.getBase(), addr.getDisplacement()); + break; + case Char: + masm.ld_global_u16(asRegister(result), addr.getBase(), addr.getDisplacement()); + break; case Int: masm.ld_global_s32(asRegister(result), addr.getBase(), addr.getDisplacement()); break; + case Long: + masm.ld_global_s64(asRegister(result), addr.getBase(), addr.getDisplacement()); + break; + case Float: + masm.ld_global_f32(asRegister(result), addr.getBase(), addr.getDisplacement()); + break; + case Double: + masm.ld_global_f64(asRegister(result), addr.getBase(), addr.getDisplacement()); + break; case Object: masm.ld_global_u32(asRegister(result), addr.getBase(), addr.getDisplacement()); break; @@ -162,11 +180,29 @@ assert isRegister(input); PTXAddress addr = address.toAddress(); switch (address.getKind()) { + case Byte: + masm.st_global_s8(addr.getBase(), addr.getDisplacement(), asRegister(input)); + break; + case Short: + masm.st_global_s8(addr.getBase(), addr.getDisplacement(), asRegister(input)); + break; case Int: masm.st_global_s32(addr.getBase(), addr.getDisplacement(), asRegister(input)); break; + case Long: + masm.st_global_s64(addr.getBase(), addr.getDisplacement(), asRegister(input)); + break; + case Float: + masm.st_global_f32(addr.getBase(), addr.getDisplacement(), asRegister(input)); + break; + case Double: + masm.st_global_f64(addr.getBase(), addr.getDisplacement(), asRegister(input)); + break; + case Object: + masm.st_global_s32(addr.getBase(), addr.getDisplacement(), asRegister(input)); + break; default: - throw GraalInternalError.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere("missing: " + address.getKind()); } } } @@ -250,11 +286,20 @@ case Int: masm.mov_s32(asRegister(result), asRegister(input)); break; + case Long: + masm.mov_s64(asRegister(result), asRegister(input)); + break; + case Float: + masm.mov_f32(asRegister(result), asRegister(input)); + break; + case Double: + masm.mov_f64(asRegister(result), asRegister(input)); + break; case Object: masm.mov_u64(asRegister(result), asRegister(input)); break; default: - throw GraalInternalError.shouldNotReachHere("kind=" + result.getKind()); + throw GraalInternalError.shouldNotReachHere("missing: " + input.getKind()); } } @@ -266,8 +311,24 @@ } masm.mov_s32(asRegister(result), input.asInt()); break; + case Long: + if (tasm.runtime.needsDataPatch(input)) { + tasm.recordDataReferenceInCode(input, 0, true); + } + masm.mov_s64(asRegister(result), input.asLong()); + break; + case Object: + if (input.isNull()) { + masm.mov_u64(asRegister(result), 0x0L); + } else if (tasm.target.inlineObjects) { + tasm.recordDataReferenceInCode(input, 0, true); + masm.mov_u64(asRegister(result), 0xDEADDEADDEADDEADL); + } else { + masm.mov_u64(asRegister(result), tasm.recordDataReferenceInCode(input, 0, false)); + } + break; default: - throw GraalInternalError.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere("missing: " + input.getKind()); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InfopointOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InfopointOp.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,49 @@ +/* + * 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.graal.lir; + +import static com.oracle.graal.lir.LIRInstruction.Opcode; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.lir.asm.*; + +/** + * Emits an infopoint (only mark the position). + */ +@Opcode("INFOPOINT") +public class InfopointOp extends LIRInstruction { + + @State protected LIRFrameState state; + + private final InfopointReason reason; + + public InfopointOp(LIRFrameState state, InfopointReason reason) { + this.state = state; + this.reason = reason; + } + + @Override + public void emitCode(TargetMethodAssembler tasm) { + tasm.recordInfopoint(tasm.asm.codeBuffer.position(), state, reason); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java Mon Apr 15 08:51:19 2013 +0200 @@ -260,8 +260,8 @@ * Returns true when this instruction is a call instruction that destroys all caller-saved * registers. */ - public final boolean hasCall() { - return this instanceof StandardOp.CallOp; + public boolean hasCall() { + return false; } public final void forEachInput(ValueProcedure proc) { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Mon Apr 15 08:51:19 2013 +0200 @@ -118,13 +118,6 @@ } /** - * Marker interface for a LIR operation that calls a method, i.e., destroys all caller-saved - * registers. - */ - public interface CallOp { - } - - /** * Meta-operation that defines the incoming method parameters. In the LIR, every register and * variable must be defined before it is used. This operation is the definition point of method * parameters, but is otherwise a no-op. In particular, it is not the actual method prologue. diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -101,7 +101,7 @@ Debug.metric("TargetMethods").increment(); Debug.metric("CodeBytesEmitted").add(compilationResult.getTargetCodeSize()); - Debug.metric("SafepointsEmitted").add(compilationResult.getSafepoints().size()); + Debug.metric("SafepointsEmitted").add(compilationResult.getInfopoints().size()); Debug.metric("DataPatches").add(compilationResult.getDataReferences().size()); Debug.metric("ExceptionHandlersEmitted").add(compilationResult.getExceptionHandlers().size()); Debug.log("Finished target method %s, isStub %b", name, isStub); @@ -122,7 +122,7 @@ public void recordImplicitException(int pcOffset, LIRFrameState info) { // record an implicit exception point if (info != null) { - compilationResult.recordSafepoint(pcOffset, info.debugInfo()); + compilationResult.recordInfopoint(pcOffset, info.debugInfo(), InfopointReason.IMPLICIT_EXCEPTION); assert info.exceptionEdge == null; } } @@ -137,10 +137,10 @@ compilationResult.recordCall(posBefore, posAfter - posBefore, callTarget, debugInfo, false); } - public void recordSafepoint(int pos, LIRFrameState info) { - // safepoints always need debug info + public void recordInfopoint(int pos, LIRFrameState info, InfopointReason reason) { + // infopoints always need debug info DebugInfo debugInfo = info.debugInfo(); - compilationResult.recordSafepoint(pos, debugInfo); + compilationResult.recordInfopoint(pos, debugInfo, reason); } public AbstractAddress recordDataReferenceInCode(Constant data, int alignment, boolean inlined) { @@ -167,6 +167,36 @@ } /** + * Returns the float value of any constant that can be represented by a 32-bit float value. + */ + public float asFloatConst(Value value) { + assert (value.getKind().getStackKind() == Kind.Float && isConstant(value)); + Constant constant = (Constant) value; + assert !runtime.needsDataPatch(constant) : constant + " should be in a DataPatch"; + return constant.asFloat(); + } + + /** + * Returns the long value of any constant that can be represented by a 64-bit long value. + */ + public long asLongConst(Value value) { + assert (value.getKind().getStackKind() == Kind.Long && isConstant(value)); + Constant constant = (Constant) value; + assert !runtime.needsDataPatch(constant) : constant + " should be in a DataPatch"; + return constant.asLong(); + } + + /** + * Returns the double value of any constant that can be represented by a 64-bit float value. + */ + public double asDoubleConst(Value value) { + assert (value.getKind().getStackKind() == Kind.Double && isConstant(value)); + Constant constant = (Constant) value; + assert !runtime.needsDataPatch(constant) : constant + " should be in a DataPatch"; + return constant.asDouble(); + } + + /** * Returns the address of a float constant that is embedded as a data references into the code. */ public AbstractAddress asFloatConstRef(Value value) { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java Mon Apr 15 08:51:19 2013 +0200 @@ -60,7 +60,7 @@ while (!loopBegin.isDeleted()) { int mark = graph.getMark(); peel(loop); - new CanonicalizerPhase(runtime, assumptions, mark, null).apply(graph); + new CanonicalizerPhase.Instance(runtime, assumptions, mark, null).apply(graph); if (iterations++ > UNROLL_LIMIT || graph.getNodeCount() > GraalOptions.MaximumDesiredSize * 3) { throw new BailoutException("FullUnroll : Graph seems to grow out of proportion"); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,31 +22,21 @@ */ package com.oracle.graal.loop.phases; -import com.oracle.graal.api.code.*; import com.oracle.graal.debug.*; import com.oracle.graal.loop.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; +import com.oracle.graal.phases.tiers.*; -public class LoopFullUnrollPhase extends Phase { +public class LoopFullUnrollPhase extends BasePhase { private static final DebugMetric FULLY_UNROLLED_LOOPS = Debug.metric("FullUnrolls"); - private final GraalCodeCacheProvider runtime; - private final Assumptions assumptions; - private int unrollCount; - public LoopFullUnrollPhase(GraalCodeCacheProvider runtime, Assumptions assumptions) { - this.runtime = runtime; - this.assumptions = assumptions; - } - - public int getUnrollCount() { - return unrollCount; + public LoopFullUnrollPhase() { } @Override - protected void run(StructuredGraph graph) { + protected void run(StructuredGraph graph, HighTierContext context) { if (graph.hasLoops()) { boolean peeled; do { @@ -56,11 +46,10 @@ for (LoopEx loop : dataCounted.countedLoops()) { if (LoopPolicies.shouldFullUnroll(loop)) { Debug.log("FullUnroll %s", loop); - LoopTransformations.fullUnroll(loop, runtime, assumptions); + LoopTransformations.fullUnroll(loop, context.getRuntime(), context.getAssumptions()); FULLY_UNROLLED_LOOPS.increment(); Debug.dump(graph, "After fullUnroll %s", loop); peeled = true; - unrollCount++; break; } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -186,5 +186,5 @@ } @NodeIntrinsic - public static native T anchor(@ConstantNodeParameter Stamp stamp); + public static native BeginNode anchor(@ConstantNodeParameter Stamp stamp); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -29,7 +29,9 @@ import com.oracle.graal.nodes.type.*; @NodeInfo(shortName = "Deopt", nameTemplate = "Deopt {p#reason/s}") -public class DeoptimizeNode extends ControlSinkNode implements Node.IterableNodeType, LIRLowerable { +public class DeoptimizeNode extends ControlSinkNode implements Node.IterableNodeType, Lowerable, LIRLowerable, DeoptimizingNode { + + @Input private FrameState deoptState; private final DeoptimizationAction action; private final DeoptimizationReason reason; @@ -49,10 +51,41 @@ } @Override + public void lower(LoweringTool tool) { + tool.getRuntime().lower(this, tool); + } + + @Override public void generate(LIRGeneratorTool gen) { - gen.emitDeoptimize(action, reason); + gen.emitDeoptimize(action, this); } @NodeIntrinsic public static native void deopt(@ConstantNodeParameter DeoptimizationAction action, @ConstantNodeParameter DeoptimizationReason reason); + + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public FrameState getDeoptimizationState() { + return deoptState; + } + + @Override + public void setDeoptimizationState(FrameState f) { + updateUsages(deoptState, f); + deoptState = f; + } + + @Override + public DeoptimizationReason getDeoptimizationReason() { + return reason; + } + + @Override + public boolean isCallSiteDeoptimization() { + return false; + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013, 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.graal.nodes; + +import java.util.*; + +import com.oracle.graal.nodes.type.*; + +public abstract class DeoptimizingFixedWithNextNode extends FixedWithNextNode implements DeoptimizingNode { + + @Input private FrameState deoptState; + + public DeoptimizingFixedWithNextNode(Stamp stamp) { + super(stamp); + } + + public DeoptimizingFixedWithNextNode(Stamp stamp, List dependencies) { + super(stamp, dependencies); + } + + public DeoptimizingFixedWithNextNode(Stamp stamp, ValueNode... dependencies) { + super(stamp, dependencies); + } + + @Override + public FrameState getDeoptimizationState() { + return deoptState; + } + + @Override + public void setDeoptimizationState(FrameState f) { + updateUsages(deoptState, f); + deoptState = f; + } + + @Override + public boolean isCallSiteDeoptimization() { + return false; + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013, 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.graal.nodes; + +import com.oracle.graal.api.meta.*; + +/** + * Interface that needs to be implemented by nodes which need deoptimization information. + * + */ +public interface DeoptimizingNode { + + /** + * Returns true if this particular instance needs deoptimization information. + * + * @return true if this particular instance needs deoptimization information + */ + boolean canDeoptimize(); + + /** + * Returns the deoptimization information associated with this node if any. + * + * @return the deoptimization information associated with this node if any. + */ + FrameState getDeoptimizationState(); + + /** + * Set the deoptimization information associated with this node. + * + * @param state the FrameState which represents the deoptimization information. + */ + void setDeoptimizationState(FrameState state); + + /** + * Returns the reason for deoptimization triggered by this node. If deoptimization at this point + * can happen for external reasons (i.e. not explicitely triggered by this node) this method can + * return null. + * + * @return the reason for deoptimization triggered by this node. + */ + DeoptimizationReason getDeoptimizationReason(); + + /** + * Returns true if this node needs deoptimization information for stack-walking purposes because + * it is a call-site. While most other nodes use deoptimization information representing a state + * that happened before them, these nodes use a state that is valid during the call itself. + * + * @return true if this node needs deoptimization information for stack-walking purposes. + */ + boolean isCallSiteDeoptimization(); +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Mon Apr 15 08:51:19 2013 +0200 @@ -239,7 +239,7 @@ copy.remove(copy.size() - 1); } ValueNode lastSlot = copy.get(copy.size() - 1); - assert lastSlot.kind().getStackKind() == popKind.getStackKind() || (lastSlot instanceof BoxedVirtualObjectNode && popKind == Kind.Object); + assert lastSlot.kind().getStackKind() == popKind.getStackKind(); copy.remove(copy.size() - 1); } Collections.addAll(copy, pushedValues); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GenericArrayRangeWriteBarrier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GenericArrayRangeWriteBarrier.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,56 @@ +/* + * 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.graal.nodes; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.type.*; + +public final class GenericArrayRangeWriteBarrier extends FixedWithNextNode implements Node.IterableNodeType { + + @Input private ValueNode dstObject; + @Input private ValueNode dstPos; + @Input private ValueNode length; + + public ValueNode getDstObject() { + return dstObject; + } + + public ValueNode getDstPos() { + return dstPos; + } + + public ValueNode getLength() { + return length; + } + + public GenericArrayRangeWriteBarrier(ValueNode dstObject, ValueNode dstPos, ValueNode length) { + super(StampFactory.forVoid()); + this.dstObject = dstObject; + this.dstPos = dstPos; + this.length = length; + + } + + @NodeIntrinsic + public static native void insertWriteBarrier(Object dstObject, int dstPos, int length); +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,62 @@ +/* + * 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.graal.nodes; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.Node.IterableNodeType; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * Nodes of this type are inserted into the graph to denote points of interest to debugging. + */ +public class InfopointNode extends AbstractStateSplit implements LIRLowerable, IterableNodeType { + + public final InfopointReason reason; + + public InfopointNode(InfopointReason reason) { + super(StampFactory.forVoid()); + this.reason = reason; + } + + @Override + public void generate(LIRGeneratorTool generator) { + generator.visitInfopointNode(this); + } + + @Override + public boolean hasSideEffect() { + return false; + } + + @Override + public void setStateAfter(FrameState state) { + // shield this node from frame state removal + // TODO turn InfopointNode into a FixedWithNextNode subclass with a self-maintained + // FrameState that is correctly dealt with by scheduling and partial escape analysis + if (state != null) { + super.setStateAfter(state); + } + } + +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java Mon Apr 15 08:51:19 2013 +0200 @@ -26,7 +26,7 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; -public interface Invoke extends StateSplit, Lowerable { +public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode { FixedNode next(); @@ -41,7 +41,7 @@ int bci(); - FixedNode node(); + FixedNode asNode(); FrameState stateDuring(); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -38,6 +38,7 @@ public final class InvokeNode extends AbstractStateSplit implements StateSplit, Node.IterableNodeType, Invoke, LIRLowerable, MemoryCheckpoint { @Input private final CallTargetNode callTarget; + @Input private FrameState deoptState; private final int bci; private boolean polymorphic; private boolean useForInlining; @@ -139,13 +140,16 @@ } @Override - public FixedNode node() { + public FixedNode asNode() { return this; } @Override public FrameState stateDuring() { FrameState stateAfter = stateAfter(); + if (stateAfter == null) { + return null; + } FrameState stateDuring = stateAfter.duplicateModified(bci(), stateAfter.rethrowException(), kind()); stateDuring.setDuringCall(true); return stateDuring; @@ -175,4 +179,34 @@ stateAfter.safeDelete(); } } + + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public DeoptimizationReason getDeoptimizationReason() { + return null; + } + + @Override + public FrameState getDeoptimizationState() { + if (deoptState == null) { + FrameState stateDuring = stateDuring(); + updateUsages(deoptState, stateDuring); + deoptState = stateDuring; + } + return deoptState; + } + + @Override + public void setDeoptimizationState(FrameState f) { + throw new IllegalStateException(); + } + + @Override + public boolean isCallSiteDeoptimization() { + return true; + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -37,6 +37,7 @@ @Successor private BeginNode next; @Successor private DispatchBeginNode exceptionEdge; @Input private final CallTargetNode callTarget; + @Input private FrameState deoptState; @Input private FrameState stateAfter; private final int bci; private boolean polymorphic; @@ -125,7 +126,7 @@ } @Override - public FixedNode node() { + public FixedNode asNode() { return this; } @@ -221,4 +222,34 @@ public double probability(BeginNode successor) { return successor == next ? 1 - EXCEPTION_PROBA : EXCEPTION_PROBA; } + + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public DeoptimizationReason getDeoptimizationReason() { + return null; + } + + @Override + public FrameState getDeoptimizationState() { + if (deoptState == null) { + FrameState stateDuring = stateDuring(); + updateUsages(deoptState, stateDuring); + deoptState = stateDuring; + } + return deoptState; + } + + @Override + public void setDeoptimizationState(FrameState f) { + throw new IllegalStateException(); + } + + @Override + public boolean isCallSiteDeoptimization() { + return true; + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.nodes; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -30,23 +31,23 @@ * A node that changes the type of its input, usually narrowing it. For example, a PI node refines * the type of a receiver during type-guarded inlining to be the type tested by the guard. */ -public class PiNode extends FloatingNode implements LIRLowerable, Virtualizable { +public class PiNode extends FloatingNode implements LIRLowerable, Virtualizable, Node.IterableNodeType { @Input private ValueNode object; - @Input(notDataflow = true) private final FixedNode anchor; public ValueNode object() { return object; } - public FixedNode anchor() { - return anchor; + public PiNode(ValueNode object, Stamp stamp) { + super(stamp); + this.object = object; } - public PiNode(ValueNode object, FixedNode anchor, Stamp stamp) { - super(stamp); + public PiNode(ValueNode object, Stamp stamp, ValueNode anchor) { + super(stamp, anchor); + assert anchor instanceof FixedNode; this.object = object; - this.anchor = anchor; } @Override diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SafepointNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SafepointNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SafepointNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.nodes; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -29,7 +30,7 @@ /** * Marks a position in the graph where a safepoint should be emitted. */ -public class SafepointNode extends FixedWithNextNode implements LIRLowerable, Node.IterableNodeType { +public class SafepointNode extends DeoptimizingFixedWithNextNode implements LIRLowerable, Node.IterableNodeType { public SafepointNode() { this(StampFactory.forVoid()); @@ -43,4 +44,14 @@ public void generate(LIRGeneratorTool gen) { gen.visitSafepointNode(this); } + + @Override + public DeoptimizationReason getDeoptimizationReason() { + return null; + } + + @Override + public boolean canDeoptimize() { + return true; + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialArrayRangeWriteBarrier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialArrayRangeWriteBarrier.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,58 @@ +/* + * 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.graal.nodes; + +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public final class SerialArrayRangeWriteBarrier extends FixedWithNextNode implements Lowerable { + + @Input private ValueNode object; + @Input private ValueNode startIndex; + @Input private ValueNode length; + + public ValueNode getObject() { + return object; + } + + public ValueNode getStartIndex() { + return startIndex; + } + + public ValueNode getLength() { + return length; + } + + public SerialArrayRangeWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) { + super(StampFactory.forVoid()); + this.object = object; + this.startIndex = startIndex; + this.length = length; + + } + + public void lower(LoweringTool generator) { + generator.getRuntime().lower(this, generator); + } + +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialWriteBarrier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SerialWriteBarrier.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,58 @@ +/* + * 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.graal.nodes; + +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public final class SerialWriteBarrier extends FixedWithNextNode implements Lowerable { + + @Input private ValueNode object; + @Input private LocationNode location; + private final boolean precise; + + public ValueNode getObject() { + return object; + } + + public LocationNode getLocation() { + return location; + } + + public boolean usePrecise() { + return precise; + } + + public SerialWriteBarrier(ValueNode object, LocationNode location, boolean precise) { + super(StampFactory.forVoid()); + this.object = object; + this.location = location; + this.precise = precise; + } + + @Override + public void lower(LoweringTool generator) { + generator.getRuntime().lower(this, generator); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -172,5 +172,15 @@ } @NodeIntrinsic - public static native S convert(@ConstantNodeParameter Op op, T value); + public static native float convert(@ConstantNodeParameter Op op, int value); + + @NodeIntrinsic + public static native int convert(@ConstantNodeParameter Op op, float value); + + @NodeIntrinsic + public static native double convert(@ConstantNodeParameter Op op, long value); + + @NodeIntrinsic + public static native long convert(@ConstantNodeParameter Op op, double value); + } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FixedBinaryNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FixedBinaryNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FixedBinaryNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -23,12 +23,10 @@ package com.oracle.graal.nodes.calc; import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; -@NodeInfo(shortName = "/") -public class FixedBinaryNode extends FixedWithNextNode { +public abstract class FixedBinaryNode extends DeoptimizingFixedWithNextNode { @Input private ValueNode x; @Input private ValueNode y; @@ -46,4 +44,9 @@ this.x = x; this.y = y; } + + @Override + public DeoptimizationReason getDeoptimizationReason() { + return DeoptimizationReason.ArithmeticException; + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -53,6 +53,6 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitDiv(gen.operand(x()), gen.operand(y()))); + gen.setResult(this, gen.emitDiv(gen.operand(x()), gen.operand(y()), null)); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -49,6 +49,6 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitRem(gen.operand(x()), gen.operand(y()))); + gen.setResult(this, gen.emitRem(gen.operand(x()), gen.operand(y()), null)); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -109,6 +109,11 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitDiv(gen.operand(x()), gen.operand(y()))); + gen.setResult(this, gen.emitDiv(gen.operand(x()), gen.operand(y()), this)); + } + + @Override + public boolean canDeoptimize() { + return y().integerStamp().contains(0); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -66,6 +66,11 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitRem(gen.operand(x()), gen.operand(y()))); + gen.setResult(this, gen.emitRem(gen.operand(x()), gen.operand(y()), this)); + } + + @Override + public boolean canDeoptimize() { + return y().integerStamp().contains(0); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -29,7 +29,7 @@ /** * An IsNullNode will be true if the supplied value is null, and false if it is non-null. */ -public final class IsNullNode extends LogicNode implements Canonicalizable, LIRLowerable, Virtualizable { +public final class IsNullNode extends LogicNode implements Canonicalizable, LIRLowerable, Virtualizable, PiPushable { @Input private ValueNode object; @@ -78,4 +78,10 @@ tool.replaceWithValue(LogicConstantNode.contradiction(graph())); } } + + @Override + public boolean push(PiNode parent) { + replaceFirstInput(parent, parent.object()); + return true; + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -81,8 +81,35 @@ // one of them is virtual: they can never be the same objects tool.replaceWithValue(LogicConstantNode.contradiction(graph())); } else if (xVirtual && yVirtual) { - // both are virtual: check if they refer to the same object - tool.replaceWithValue(LogicConstantNode.forBoolean(stateX == stateY, graph())); + boolean xIdentity = stateX.getVirtualObject().hasIdentity(); + boolean yIdentity = stateY.getVirtualObject().hasIdentity(); + if (xIdentity ^ yIdentity) { + /* + * One of the two objects has identity, the other doesn't. In code, this looks like + * "Integer.valueOf(a) == new Integer(b)", which is always false. + * + * In other words: an object created via valueOf can never be equal to one created + * by new in the same compilation unit. + */ + tool.replaceWithValue(LogicConstantNode.contradiction(graph())); + } else if (!xIdentity && !yIdentity) { + // both are virtual without identity: check contents + assert stateX.getVirtualObject().entryCount() == 1 && stateY.getVirtualObject().entryCount() == 1; + assert stateX.getVirtualObject().type() == stateY.getVirtualObject().type(); + assert stateX.getVirtualObject().entryKind(0) == Kind.Int || stateX.getVirtualObject().entryKind(0) == Kind.Long; + final IntegerEqualsNode equals = new IntegerEqualsNode(stateX.getEntry(0), stateY.getEntry(0)); + tool.customAction(new Runnable() { + + @Override + public void run() { + graph().add(equals); + } + }); + tool.replaceWithValue(equals); + } else { + // both are virtual with identity: check if they refer to the same object + tool.replaceWithValue(LogicConstantNode.forBoolean(stateX == stateY, graph())); + } } } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -67,6 +67,11 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitUDiv(gen.operand(x()), gen.operand(y()))); + gen.setResult(this, gen.emitUDiv(gen.operand(x()), gen.operand(y()), this)); + } + + @Override + public boolean canDeoptimize() { + return y().integerStamp().contains(0); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -66,6 +66,11 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitURem(gen.operand(x()), gen.operand(y()))); + gen.setResult(this, gen.emitURem(gen.operand(x()), gen.operand(y()), this)); + } + + @Override + public boolean canDeoptimize() { + return y().integerStamp().contains(0); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -121,6 +121,9 @@ @Override public void lower(LoweringTool tool) { + if (!enabled) { + throw new GraalInternalError("counter nodes shouldn't exist when not enabled"); + } StructuredGraph graph = (StructuredGraph) graph(); if (excludedClassPrefix == null || !graph.method().getDeclaringClass().getName().startsWith(excludedClassPrefix)) { int index = addContext ? getIndex(name + " @ " + MetaUtil.format("%h.%n", ((StructuredGraph) graph()).method())) : getIndex(name); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/Access.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/Access.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/Access.java Mon Apr 15 08:51:19 2013 +0200 @@ -25,7 +25,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -public interface Access { +public interface Access extends DeoptimizingNode { ValueNode object(); @@ -33,5 +33,5 @@ void setNullCheck(boolean check); - Node node(); + Node asNode(); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -24,6 +24,7 @@ import java.util.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; @@ -33,7 +34,7 @@ * {@linkplain #nullCheckLocation() location}. The access does not include a null check on the * object. */ -public abstract class AccessNode extends FixedWithNextNode implements Access { +public abstract class AccessNode extends DeoptimizingFixedWithNextNode implements Access { @Input private ValueNode object; @Input private ValueNode location; @@ -78,7 +79,17 @@ } @Override - public Node node() { + public Node asNode() { return this; } + + @Override + public boolean canDeoptimize() { + return nullCheck; + } + + @Override + public DeoptimizationReason getDeoptimizationReason() { + return DeoptimizationReason.NullCheckException; + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,80 +23,84 @@ package com.oracle.graal.nodes.extended; import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; - -public final class BoxNode extends AbstractStateSplit implements StateSplit, Node.IterableNodeType, Canonicalizable { +import com.oracle.graal.nodes.virtual.*; - @Input private ValueNode source; - private final int bci; - private final Kind sourceKind; +/** + * This node represents the boxing of a primitive value. This corresponds to a call to the valueOf + * methods in Integer, Long, etc. + */ +public class BoxNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Canonicalizable { - public BoxNode(ValueNode value, ResolvedJavaType type, Kind sourceKind, int bci) { - super(StampFactory.exactNonNull(type)); - this.source = value; - this.bci = bci; - this.sourceKind = sourceKind; - assert value.kind() != Kind.Object : "can only box from primitive type"; + @Input private ValueNode value; + private final Kind boxingKind; + + public BoxNode(ValueNode value, ResolvedJavaType resultType, Kind boxingKind) { + super(StampFactory.exactNonNull(resultType)); + this.value = value; + this.boxingKind = boxingKind; } - public ValueNode source() { - return source; - } - - public Kind getSourceKind() { - return sourceKind; + public Kind getBoxingKind() { + return boxingKind; } - public void expand(BoxingMethodPool pool) { - ResolvedJavaMethod boxingMethod = pool.getBoxingMethod(sourceKind); - MethodCallTargetNode callTarget = graph().add( - new MethodCallTargetNode(InvokeKind.Static, boxingMethod, new ValueNode[]{source}, boxingMethod.getSignature().getReturnType(boxingMethod.getDeclaringClass()))); - InvokeNode invokeNode = graph().add(new InvokeNode(callTarget, bci)); - invokeNode.setProbability(this.probability()); - invokeNode.setStateAfter(stateAfter()); - ((StructuredGraph) graph()).replaceFixedWithFixed(this, invokeNode); + public ValueNode getValue() { + return value; + } + + @Override + public void lower(LoweringTool tool) { + tool.getRuntime().lower(this, tool); } @Override public ValueNode canonical(CanonicalizerTool tool) { + /* + * Constant values are not canonicalized into their constant boxing objects because this + * would mean that the information that they came from a valueOf is lost. + */ + if (usages().isEmpty()) { + return null; + } + return this; + } - if (source.isConstant()) { - Constant sourceConstant = source.asConstant(); - switch (sourceKind) { - case Boolean: - return ConstantNode.forObject(Boolean.valueOf(sourceConstant.asBoolean()), tool.runtime(), graph()); - case Byte: - return ConstantNode.forObject(Byte.valueOf((byte) sourceConstant.asInt()), tool.runtime(), graph()); - case Char: - return ConstantNode.forObject(Character.valueOf((char) sourceConstant.asInt()), tool.runtime(), graph()); - case Short: - return ConstantNode.forObject(Short.valueOf((short) sourceConstant.asInt()), tool.runtime(), graph()); - case Int: - return ConstantNode.forObject(Integer.valueOf(sourceConstant.asInt()), tool.runtime(), graph()); - case Long: - return ConstantNode.forObject(Long.valueOf(sourceConstant.asLong()), tool.runtime(), graph()); - case Float: - return ConstantNode.forObject(Float.valueOf(sourceConstant.asFloat()), tool.runtime(), graph()); - case Double: - return ConstantNode.forObject(Double.valueOf(sourceConstant.asDouble()), tool.runtime(), graph()); - default: - assert false : "Unexpected source kind for boxing"; - break; + @Override + public void virtualize(VirtualizerTool tool) { + ValueNode v = tool.getReplacedValue(getValue()); + ResolvedJavaType type = objectStamp().type(); + + VirtualBoxingNode newVirtual = new VirtualBoxingNode(type, boxingKind); + assert newVirtual.getFields().length == 1; + + tool.createVirtualObject(newVirtual, new ValueNode[]{v}, 0); + tool.replaceWithVirtual(newVirtual); + } + + @NodeIntrinsic + public static native Boolean box(boolean value, @ConstantNodeParameter Class clazz, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native Byte box(byte value, @ConstantNodeParameter Class clazz, @ConstantNodeParameter Kind kind); - } - } + @NodeIntrinsic + public static native Character box(char value, @ConstantNodeParameter Class clazz, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native Double box(double value, @ConstantNodeParameter Class clazz, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native Float box(float value, @ConstantNodeParameter Class clazz, @ConstantNodeParameter Kind kind); - for (Node usage : usages()) { - if (usage != stateAfter()) { - return this; - } - } - replaceAtUsages(null); - return null; - } + @NodeIntrinsic + public static native Integer box(int value, @ConstantNodeParameter Class clazz, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native Long box(long value, @ConstantNodeParameter Class clazz, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native Short box(short value, @ConstantNodeParameter Class clazz, @ConstantNodeParameter Kind kind); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxingMethodPool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxingMethodPool.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * Copyright (c) 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. - */ -package com.oracle.graal.nodes.extended; - -import java.util.*; - -import com.oracle.graal.api.meta.*; - -public class BoxingMethodPool { - - private final Set specialMethods = new HashSet<>(); - private final MetaAccessProvider runtime; - private final ResolvedJavaMethod[] boxingMethods = new ResolvedJavaMethod[Kind.values().length]; - private final ResolvedJavaMethod[] unboxingMethods = new ResolvedJavaMethod[Kind.values().length]; - private final ResolvedJavaField[] boxFields = new ResolvedJavaField[Kind.values().length]; - - public BoxingMethodPool(MetaAccessProvider runtime) { - this.runtime = runtime; - - try { - initialize(Kind.Boolean, Boolean.class, "booleanValue"); - initialize(Kind.Byte, Byte.class, "byteValue"); - initialize(Kind.Char, Character.class, "charValue"); - initialize(Kind.Short, Short.class, "shortValue"); - initialize(Kind.Int, Integer.class, "intValue"); - initialize(Kind.Long, Long.class, "longValue"); - initialize(Kind.Float, Float.class, "floatValue"); - initialize(Kind.Double, Double.class, "doubleValue"); - } catch (SecurityException | NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - private void initialize(Kind kind, Class type, String unboxMethod) throws SecurityException, NoSuchMethodException { - // Get boxing method from runtime. - ResolvedJavaMethod boxingMethod = runtime.lookupJavaMethod(type.getDeclaredMethod("valueOf", kind.toJavaClass())); - specialMethods.add(boxingMethod); - boxingMethods[kind.ordinal()] = boxingMethod; - - // Get unboxing method from runtime. - ResolvedJavaMethod unboxingMethod = runtime.lookupJavaMethod(type.getDeclaredMethod(unboxMethod)); - unboxingMethods[kind.ordinal()] = unboxingMethod; - specialMethods.add(unboxingMethod); - - // Get the field that contains the boxed value. - ResolvedJavaField[] fields = runtime.lookupJavaType(type).getInstanceFields(false); - ResolvedJavaField boxField = fields[0]; - assert fields.length == 1 && boxField.getKind() == kind; - boxFields[kind.ordinal()] = boxField; - } - - public boolean isSpecialMethod(ResolvedJavaMethod method) { - return specialMethods.contains(method); - } - - public boolean isBoxingMethod(ResolvedJavaMethod method) { - return isSpecialMethod(method) && method.getSignature().getReturnKind() == Kind.Object; - } - - public boolean isUnboxingMethod(ResolvedJavaMethod method) { - return isSpecialMethod(method) && method.getSignature().getReturnKind() != Kind.Object; - } - - public ResolvedJavaMethod getBoxingMethod(Kind kind) { - return boxingMethods[kind.ordinal()]; - } - - public ResolvedJavaMethod getUnboxingMethod(Kind kind) { - return unboxingMethods[kind.ordinal()]; - } - - public ResolvedJavaField getBoxField(Kind kind) { - return boxFields[kind.ordinal()]; - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -24,6 +24,7 @@ import java.util.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; @@ -33,6 +34,7 @@ @Input private ValueNode object; @Input private LocationNode location; + @Input private FrameState deoptState; private boolean nullCheck; public ValueNode object() { @@ -74,9 +76,35 @@ } @Override - public Node node() { + public Node asNode() { return this; } + @Override + public boolean canDeoptimize() { + return nullCheck; + } + + @Override + public DeoptimizationReason getDeoptimizationReason() { + return DeoptimizationReason.NullCheckException; + } + + @Override + public FrameState getDeoptimizationState() { + return deoptState; + } + + @Override + public void setDeoptimizationState(FrameState f) { + updateUsages(deoptState, f); + deoptState = f; + } + + @Override + public boolean isCallSiteDeoptimization() { + return false; + } + public abstract Access asFixedNode(); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -53,7 +53,7 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, location().generateLoad(gen, object(), getNullCheck())); + gen.setResult(this, location().generateLoad(gen, object(), this)); } @Override diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -86,12 +86,12 @@ } @Override - public Value generateLoad(LIRGeneratorTool gen, ValueNode base, boolean canTrap) { - return gen.emitLoad(getValueKind(), gen.operand(base), displacement(), gen.operand(index()), indexScaling(), canTrap); + public Value generateLoad(LIRGeneratorTool gen, ValueNode base, DeoptimizingNode deopting) { + return gen.emitLoad(getValueKind(), gen.operand(base), displacement(), gen.operand(index()), indexScaling(), deopting); } @Override - public void generateStore(LIRGeneratorTool gen, ValueNode base, ValueNode value, boolean canTrap) { - gen.emitStore(getValueKind(), gen.operand(base), displacement(), gen.operand(index()), indexScaling(), gen.operand(value), canTrap); + public void generateStore(LIRGeneratorTool gen, ValueNode base, ValueNode value, DeoptimizingNode deopting) { + gen.emitStore(getValueKind(), gen.operand(base), displacement(), gen.operand(index()), indexScaling(), gen.operand(value), deopting); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -60,17 +60,12 @@ /** * Denotes any location. A write to such a location kills all values in a memory map during an - * analysis of memory accesses in a graph. + * analysis of memory accesses in a graph. A read from this location cannot be moved or + * coalesced with other reads because its interaction with other reads is not known. */ public static final Object ANY_LOCATION = createLocation("ANY_LOCATION"); /** - * Denotes an unknown location. A read from this location cannot be moved or coalesced with - * other reads because its interaction with other reads is not known. - */ - public static final Object UNKNOWN_LOCATION = createLocation("UNKNOWN_LOCATION"); - - /** * Denotes the location of a value that is guaranteed to be final. */ public static final Object FINAL_LOCATION = createLocation("FINAL_LOCATION"); @@ -112,11 +107,11 @@ return gen.emitLea(gen.operand(base), displacement(), Value.ILLEGAL, 0); } - public Value generateLoad(LIRGeneratorTool gen, ValueNode base, boolean canTrap) { - return gen.emitLoad(getValueKind(), gen.operand(base), displacement(), Value.ILLEGAL, 0, canTrap); + public Value generateLoad(LIRGeneratorTool gen, ValueNode base, DeoptimizingNode deopting) { + return gen.emitLoad(getValueKind(), gen.operand(base), displacement(), Value.ILLEGAL, 0, deopting); } - public void generateStore(LIRGeneratorTool gen, ValueNode base, ValueNode value, boolean canTrap) { - gen.emitStore(getValueKind(), gen.operand(base), displacement(), Value.ILLEGAL, 0, gen.operand(value), canTrap); + public void generateStore(LIRGeneratorTool gen, ValueNode base, ValueNode value, DeoptimizingNode deopting) { + gen.emitStore(getValueKind(), gen.operand(base), displacement(), Value.ILLEGAL, 0, gen.operand(value), deopting); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,11 +22,12 @@ */ package com.oracle.graal.nodes.extended; +import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -public class NullCheckNode extends FixedWithNextNode implements LIRLowerable { +public class NullCheckNode extends DeoptimizingFixedWithNextNode implements LIRLowerable { @Input public ValueNode object; @@ -41,6 +42,16 @@ @Override public void generate(LIRGeneratorTool generator) { - generator.emitNullCheck(object); + generator.emitNullCheck(object, this); + } + + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public DeoptimizationReason getDeoptimizationReason() { + return DeoptimizationReason.NullCheckException; } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -33,7 +33,7 @@ /** * Reads an {@linkplain AccessNode accessed} value. */ -public final class ReadNode extends FloatableAccessNode implements Node.IterableNodeType, LIRLowerable, Canonicalizable { +public final class ReadNode extends FloatableAccessNode implements Node.IterableNodeType, LIRLowerable, Canonicalizable, PiPushable { public ReadNode(ValueNode object, ValueNode location, Stamp stamp) { super(object, location, stamp); @@ -57,7 +57,7 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, location().generateLoad(gen, object(), getNullCheck())); + gen.setResult(this, location().generateLoad(gen, object(), this)); } @Override @@ -98,6 +98,21 @@ return read; } + @Override + public boolean push(PiNode parent) { + Object locId = location().locationIdentity(); + if (locId instanceof ResolvedJavaField) { + ResolvedJavaType fieldType = ((ResolvedJavaField) locId).getDeclaringClass(); + ResolvedJavaType beforePiType = parent.object().objectStamp().type(); + + if (beforePiType != null && fieldType.isAssignableFrom(beforePiType)) { + replaceFirstInput(parent, parent.object()); + return true; + } + } + return false; + } + /** * Reads a value from memory. * diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -30,9 +30,10 @@ import com.oracle.graal.nodes.type.*; @NodeInfo(nameTemplate = "RuntimeCall#{p#descriptor/s}") -public final class RuntimeCallNode extends AbstractCallNode implements LIRLowerable { +public final class RuntimeCallNode extends AbstractCallNode implements LIRLowerable, DeoptimizingNode { private final Descriptor descriptor; + @Input private FrameState deoptState; public RuntimeCallNode(Descriptor descriptor, ValueNode... arguments) { super(StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())), arguments); @@ -65,4 +66,43 @@ } return super.toString(verbosity); } + + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public FrameState getDeoptimizationState() { + if (deoptState != null) { + return deoptState; + } else if (stateAfter() != null) { + FrameState stateDuring = stateAfter(); + if ((stateDuring.stackSize() > 0 && stateDuring.stackAt(stateDuring.stackSize() - 1) == this) || (stateDuring.stackSize() > 1 && stateDuring.stackAt(stateDuring.stackSize() - 2) == this)) { + stateDuring = stateDuring.duplicateModified(stateDuring.bci, stateDuring.rethrowException(), this.kind()); + } + updateUsages(deoptState, stateDuring); + return deoptState = stateDuring; + } + return null; + } + + @Override + public void setDeoptimizationState(FrameState f) { + if (deoptState != null) { + throw new IllegalStateException(); + } + updateUsages(deoptState, f); + deoptState = f; + } + + @Override + public DeoptimizationReason getDeoptimizationReason() { + return null; + } + + @Override + public boolean isCallSiteDeoptimization() { + return stateAfter() != null; + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,47 +23,49 @@ package com.oracle.graal.nodes.extended; import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -public final class UnboxNode extends FixedWithNextNode implements Node.IterableNodeType, Canonicalizable { +public class UnboxNode extends FixedWithNextNode implements Virtualizable, Lowerable, Canonicalizable { - @Input private ValueNode source; - private Kind destinationKind; + @Input private ValueNode value; + private final Kind boxingKind; - public UnboxNode(Kind kind, ValueNode source) { - super(StampFactory.forKind(kind)); - this.source = source; - this.destinationKind = kind; - assert kind != Kind.Object : "can only unbox to primitive"; - assert source.kind() == Kind.Object : "can only unbox objects"; + public UnboxNode(ValueNode value, Kind boxingKind) { + super(StampFactory.forKind(boxingKind.getStackKind())); + this.value = value; + this.boxingKind = boxingKind; + } + + public Kind getBoxingKind() { + return boxingKind; } - public ValueNode source() { - return source; + public ValueNode getValue() { + return value; } - public Kind destinationKind() { - return destinationKind; + @Override + public void lower(LoweringTool tool) { + tool.getRuntime().lower(this, tool); } - public void expand(BoxingMethodPool pool) { - ResolvedJavaField field = pool.getBoxField(kind()); - LoadFieldNode loadField = graph().add(new LoadFieldNode(source, field)); - loadField.setProbability(probability()); - ((StructuredGraph) graph()).replaceFixedWithFixed(this, loadField); + @Override + public void virtualize(VirtualizerTool tool) { + State state = tool.getObjectState(value); + if (state != null && state.getState() == EscapeState.Virtual) { + tool.replaceWithValue(state.getEntry(0)); + } } @Override public ValueNode canonical(CanonicalizerTool tool) { - if (source.isConstant()) { - Constant constant = source.asConstant(); + if (value.isConstant()) { + Constant constant = value.asConstant(); Object o = constant.asObject(); if (o != null) { - switch (destinationKind) { + switch (boxingKind) { case Boolean: return ConstantNode.forBoolean((Boolean) o, graph()); case Byte: @@ -84,7 +86,36 @@ ValueNodeUtil.shouldNotReachHere(); } } + } else if (value instanceof BoxNode) { + return ((BoxNode) value).getValue(); + } + if (usages().isEmpty()) { + return null; } return this; } + + @NodeIntrinsic + public static native boolean unbox(Boolean value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native byte unbox(Byte value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native char unbox(Character value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native double unbox(Double value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native float unbox(Float value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native int unbox(Integer value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native long unbox(Long value, @ConstantNodeParameter Kind kind); + + @NodeIntrinsic + public static native short unbox(Short value, @ConstantNodeParameter Kind kind); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeArrayCastNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeArrayCastNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeArrayCastNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -37,8 +37,8 @@ return length; } - public UnsafeArrayCastNode(ValueNode object, ValueNode length, Stamp stamp) { - super(object, stamp); + public UnsafeArrayCastNode(ValueNode object, ValueNode length, Stamp stamp, ValueNode anchor) { + super(object, stamp, anchor); this.length = length; } @@ -51,5 +51,5 @@ } @NodeIntrinsic - public static native T unsafeArrayCast(Object object, int length, @ConstantNodeParameter Stamp stamp); + public static native T unsafeArrayCast(Object object, int length, @ConstantNodeParameter Stamp stamp, Object anchor); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -24,29 +24,20 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; /** * The {@code UnsafeCastNode} produces the same value as its input, but with a different type. */ -public class UnsafeCastNode extends FloatingNode implements Canonicalizable, LIRLowerable { - - @Input private ValueNode object; - - public ValueNode object() { - return object; - } +public class UnsafeCastNode extends PiNode implements Canonicalizable, LIRLowerable { public UnsafeCastNode(ValueNode object, Stamp stamp) { - super(stamp); - this.object = object; + super(object, stamp); } public UnsafeCastNode(ValueNode object, Stamp stamp, ValueNode anchor) { - super(stamp, anchor); - this.object = object; + super(object, stamp, anchor); } public UnsafeCastNode(ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) { @@ -72,13 +63,13 @@ @Override public ValueNode canonical(CanonicalizerTool tool) { - if (kind() != object.kind()) { + if (kind() != object().kind()) { return this; } if (kind() == Kind.Object) { ObjectStamp my = objectStamp(); - ObjectStamp other = object.objectStamp(); + ObjectStamp other = object().objectStamp(); if (my.type() == null || other.type() == null) { return this; @@ -93,21 +84,21 @@ return this; } } - return object; + return object(); } @Override public void generate(LIRGeneratorTool generator) { - if (kind() != object.kind()) { - assert generator.target().sizeInBytes(kind()) == generator.target().sizeInBytes(object.kind()) : "unsafe cast cannot be used to change the size of a value"; + if (kind() != object().kind()) { + assert generator.target().sizeInBytes(kind()) == generator.target().sizeInBytes(object().kind()) : "unsafe cast cannot be used to change the size of a value"; Value result = generator.newVariable(kind()); - generator.emitMove(result, generator.operand(object)); + generator.emitMove(result, generator.operand(object())); generator.setResult(this, result); } else { // The LIR only cares about the kind of an operand, not the actual type of an object. So // we do not have to // introduce a new operand when the kind is the same. - generator.setResult(this, generator.operand(object)); + generator.setResult(this, generator.operand(object())); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -25,14 +25,34 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.graph.*; /** * Writes a given {@linkplain #value() value} a {@linkplain AccessNode memory location}. */ -public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint { +public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint, Node.IterableNodeType { @Input private ValueNode value; @Input(notDataflow = true) private FrameState stateAfter; + private final WriteBarrierType barrierType; + + /* + * The types of write barriers attached to stores. + */ + public enum WriteBarrierType { + /* + * Primitive stores which do not necessitate write barriers. + */ + NONE, + /* + * Array object stores which necessitate precise write barriers. + */ + PRECISE, + /* + * Field object stores which necessitate imprecise write barriers. + */ + IMPRECISE + } public FrameState stateAfter() { return stateAfter; @@ -52,18 +72,23 @@ return value; } - public WriteNode(ValueNode object, ValueNode value, ValueNode location) { + public WriteBarrierType getWriteBarrierType() { + return barrierType; + } + + public WriteNode(ValueNode object, ValueNode value, ValueNode location, WriteBarrierType barrierType) { super(object, location, StampFactory.forVoid()); this.value = value; + this.barrierType = barrierType; } @Override public void generate(LIRGeneratorTool gen) { - location().generateStore(gen, object(), value(), getNullCheck()); + location().generateStore(gen, object(), value(), this); } @NodeIntrinsic - public static native void writeMemory(Object object, Object value, Object location); + public static native void writeMemory(Object object, Object value, Object location, @ConstantNodeParameter boolean usePreciseWriteBarriers); @Override public Object[] getLocationIdentities() { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -28,6 +28,7 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.virtual.*; /** * The {@code AccessMonitorNode} is the base class of both monitor acquisition and release. @@ -72,7 +73,7 @@ @Override public void virtualize(VirtualizerTool tool) { State state = tool.getObjectState(object); - if (state != null && state.getState() == EscapeState.Virtual) { + if (state != null && state.getState() == EscapeState.Virtual && state.getVirtualObject().getClass() == VirtualInstanceNode.class) { Debug.log("monitor operation %s on %s\n", this, state); int newLockCount = state.getLockCount() + (this instanceof MonitorEnterNode ? 1 : -1); state.setLockCount(newLockCount); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -41,7 +41,7 @@ * @param object the instruction producing the object */ public CheckCastDynamicNode(ValueNode type, ValueNode object) { - super(StampFactory.object()); + super(object.stamp()); this.type = type; this.object = object; } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -102,7 +102,9 @@ public void virtualize(VirtualizerTool tool) { State state = tool.getObjectState(object); if (state != null && state.getState() == EscapeState.Virtual) { - tool.replaceWithVirtual(state.getVirtualObject()); + if (type.isAssignableFrom(state.getVirtualObject().type())) { + tool.replaceWithVirtual(state.getVirtualObject()); + } } } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -25,8 +25,10 @@ import static com.oracle.graal.graph.UnsafeAccess.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.WriteNode.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -34,13 +36,14 @@ * Represents an atomic compare-and-swap operation The result is a boolean that contains whether the * value matched the expected value. */ -public class CompareAndSwapNode extends AbstractStateSplit implements StateSplit, LIRLowerable, Lowerable, MemoryCheckpoint { +public class CompareAndSwapNode extends AbstractStateSplit implements StateSplit, LIRLowerable, Lowerable, MemoryCheckpoint, Node.IterableNodeType { @Input private ValueNode object; @Input private ValueNode offset; @Input private ValueNode expected; @Input private ValueNode newValue; private final int displacement; + private WriteBarrierType barrierType; public ValueNode object() { return object; @@ -62,6 +65,14 @@ return displacement; } + public WriteBarrierType getWriteBarrierType() { + return barrierType; + } + + public void setWriteBarrierType(WriteBarrierType type) { + this.barrierType = type; + } + public CompareAndSwapNode(ValueNode object, int displacement, ValueNode offset, ValueNode expected, ValueNode newValue) { super(StampFactory.forKind(Kind.Boolean.getStackKind())); assert expected.kind() == newValue.kind(); @@ -70,6 +81,7 @@ this.expected = expected; this.newValue = newValue; this.displacement = displacement; + this.barrierType = WriteBarrierType.NONE; } @Override diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -29,16 +29,13 @@ import com.oracle.graal.nodes.type.*; /** - * The {@code ExceptionObject} instruction represents the incoming exception object to an exception - * handler. + * The entry to an exception handler with the exception coming from a call (as opposed to a local + * throw instruction or implicit exception). */ -public class ExceptionObjectNode extends DispatchBeginNode implements Lowerable, LIRLowerable, MemoryCheckpoint { +public class ExceptionObjectNode extends DispatchBeginNode implements Lowerable, MemoryCheckpoint { - /** - * Constructs a new ExceptionObject instruction. - */ public ExceptionObjectNode(MetaAccessProvider runtime) { - super(StampFactory.declared(runtime.lookupJavaType(Throwable.class))); + super(StampFactory.declaredNonNull(runtime.lookupJavaType(Throwable.class))); } @Override @@ -47,23 +44,35 @@ } @Override - public void generate(LIRGeneratorTool gen) { - gen.visitExceptionObject(this); + public void simplify(SimplifierTool tool) { + // + } + + private boolean isLowered() { + return (stamp() == StampFactory.forVoid()); } @Override public void lower(LoweringTool tool) { - tool.getRuntime().lower(this, tool); - } - - @Override - public void simplify(SimplifierTool tool) { - // + if (isLowered()) { + return; + } + StructuredGraph graph = (StructuredGraph) graph(); + LoadExceptionObjectNode loadException = graph.add(new LoadExceptionObjectNode(stamp())); + loadException.setStateAfter(stateAfter()); + replaceAtUsages(loadException); + graph.addAfterFixed(this, loadException); + tool.setLastFixedNode(loadException); + setStateAfter(null); + setStamp(StampFactory.forVoid()); } @Override public boolean verify() { - assertTrue(stateAfter() != null, "an exception handler needs a frame state"); + if (isLowered()) { + return true; + } + assertTrue(stateAfter() != null || stamp() == StampFactory.forVoid(), "an exception handler needs a frame state"); return super.verify(); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009, 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. + */ +package com.oracle.graal.nodes.java; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * Loads an exception object passed by the runtime from a callee to an exception handler in a + * caller. The node is only produced when lowering an {@link ExceptionObjectNode}. + */ +public class LoadExceptionObjectNode extends AbstractStateSplit implements Lowerable { + + public LoadExceptionObjectNode(Stamp stamp) { + super(stamp); + } + + @Override + public void lower(LoweringTool tool) { + tool.getRuntime().lower(this, tool); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -24,6 +24,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -32,10 +33,11 @@ * This node is used to perform the finalizer registration at the end of the java.lang.Object * constructor. */ -public final class RegisterFinalizerNode extends AbstractStateSplit implements StateSplit, Canonicalizable, LIRLowerable, Virtualizable { +public final class RegisterFinalizerNode extends AbstractStateSplit implements StateSplit, Canonicalizable, LIRLowerable, Virtualizable, DeoptimizingNode { public static final Descriptor REGISTER_FINALIZER = new Descriptor("registerFinalizer", true, void.class, Object.class); + @Input private FrameState deoptState; @Input private ValueNode object; public ValueNode object() { @@ -50,7 +52,7 @@ @Override public void generate(LIRGeneratorTool gen) { RuntimeCallTarget call = gen.getRuntime().lookupRuntimeCall(REGISTER_FINALIZER); - gen.emitCall(call, call.getCallingConvention(), true, gen.operand(object())); + gen.emitCall(call, call.getCallingConvention(), this, gen.operand(object())); } @Override @@ -63,7 +65,8 @@ } else if (stamp.type() != null && !stamp.type().hasFinalizableSubclass()) { // if either the declared type of receiver or the holder // can be assumed to have no finalizers - if (tool.assumptions().useOptimisticAssumptions() && tool.assumptions().recordNoFinalizableSubclassAssumption(stamp.type())) { + if (tool.assumptions().useOptimisticAssumptions()) { + tool.assumptions().recordNoFinalizableSubclassAssumption(stamp.type()); needsCheck = false; } } @@ -83,6 +86,32 @@ } } + @Override + public boolean canDeoptimize() { + return true; + } + + @Override + public FrameState getDeoptimizationState() { + return deoptState; + } + + @Override + public void setDeoptimizationState(FrameState f) { + updateUsages(deoptState, f); + deoptState = f; + } + + @Override + public DeoptimizationReason getDeoptimizationReason() { + return null; + } + + @Override + public boolean isCallSiteDeoptimization() { + return false; + } + @SuppressWarnings("unused") @NodeIntrinsic public static void register(Object thisObj) { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/GraalCodeCacheProvider.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/GraalCodeCacheProvider.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/GraalCodeCacheProvider.java Mon Apr 15 08:51:19 2013 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.nodes.spi; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; /** @@ -30,5 +31,17 @@ */ public interface GraalCodeCacheProvider extends CodeCacheProvider { + /** + * Adds the given compilation result as an implementation of the given method without making it + * the default implementation. The graph might be inlined later on. + * + * @param method a method to which the executable code is begin added + * @param compResult the compilation result to be added + * @param graph the graph that represents the method + * @return a reference to the compiled and ready-to-run code or null if the code installation + * failed + */ + InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, Graph graph); + void lower(Node n, LoweringTool tool); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Mon Apr 15 08:51:19 2013 +0200 @@ -57,9 +57,9 @@ public abstract void emitMove(Value dst, Value src); - public abstract Value emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap); + public abstract Value emitLoad(Kind kind, Value base, int displacement, Value index, int scale, DeoptimizingNode deopting); - public abstract void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value input, boolean canTrap); + public abstract void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value input, DeoptimizingNode deopting); public abstract Value emitLea(Value base, int displacement, Value index, int scale); @@ -73,13 +73,13 @@ public abstract Value emitMul(Value a, Value b); - public abstract Value emitDiv(Value a, Value b); + public abstract Value emitDiv(Value a, Value b, DeoptimizingNode deopting); - public abstract Value emitRem(Value a, Value b); + public abstract Value emitRem(Value a, Value b, DeoptimizingNode deopting); - public abstract Value emitUDiv(Value a, Value b); + public abstract Value emitUDiv(Value a, Value b, DeoptimizingNode deopting); - public abstract Value emitURem(Value a, Value b); + public abstract Value emitURem(Value a, Value b, DeoptimizingNode deopting); public abstract Value emitAnd(Value a, Value b); @@ -97,11 +97,11 @@ public abstract void emitMembar(int barriers); - public abstract void emitDeoptimize(DeoptimizationAction action, DeoptimizationReason reason); + public abstract void emitDeoptimize(DeoptimizationAction action, DeoptimizingNode deopting); - public abstract void emitNullCheck(ValueNode v); + public abstract void emitNullCheck(ValueNode v, DeoptimizingNode deopting); - public abstract Value emitCall(RuntimeCallTarget callTarget, CallingConvention cc, boolean canTrap, Value... args); + public abstract Value emitCall(RuntimeCallTarget callTarget, CallingConvention cc, DeoptimizingNode info, Value... args); public abstract void emitIf(IfNode i); @@ -123,7 +123,6 @@ public abstract void visitCompareAndSwap(CompareAndSwapNode i); // These methods define the contract a runtime specific backend must provide. - public abstract void visitExceptionObject(ExceptionObjectNode i); public abstract void visitReturn(ReturnNode i); @@ -138,4 +137,6 @@ */ public void beforeRegisterAllocation() { } + + public abstract void visitInfopointNode(InfopointNode i); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java Mon Apr 15 08:51:19 2013 +0200 @@ -34,6 +34,8 @@ GraalCodeCacheProvider getRuntime(); + Replacements getReplacements(); + ValueNode createNullCheckGuard(ValueNode object); ValueNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MacroSubstitution.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MacroSubstitution.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,85 @@ +/* + * 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.graal.nodes.spi; + +import java.lang.annotation.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; + +/** + * Denotes a macro substitute method. This replaces a method invocation with an instance of the + * specified node class. + * + * A macro substitution can be combined with a normal substitution, so that the macro node can be + * replaced with the actual substitution code during lowering. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface MacroSubstitution { + + /** + * Gets the name of the substituted method. + *

+ * If the default value is specified for this element, then the name of the substituted method + * is same as the substitute method. + */ + String value() default ""; + + /** + * Determines if the substituted method is static. + */ + boolean isStatic() default true; + + /** + * Gets the {@linkplain MetaUtil#signatureToMethodDescriptor signature} of the substituted + * method. + *

+ * If the default value is specified for this element, then the signature of the substituted + * method is the same as the substitute method. + */ + String signature() default ""; + + /** + * Determines if the substitution is for a method that may not be part of the runtime. For + * example, a method introduced in a later JDK version. Substitutions for such methods are + * omitted if the original method cannot be found. + */ + boolean optional() default false; + + /** + * The node class with which the method invocation should be replaced. It needs to be a subclass + * of {@link FixedWithNextNode}, and it is expected to provide a public constructor that takes + * an {@link InvokeNode} as a parameter. + */ + Class macro(); + + /** + * Determines if this method should be substituted in all cases, even if inlining thinks it is + * not important. + * + * Not that this is still depending on whether inlining sees the correct call target, so it's + * only a hard guarantee for static and special invocations. + */ + boolean forced() default false; +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/PiPushable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/PiPushable.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,38 @@ +/* + * 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.graal.nodes.spi; + +import com.oracle.graal.nodes.*; + +/** + * This interface marks nodes, which are able to be pushed through a PiNode. + */ +public interface PiPushable { + + /** + * + * @param parent PiNode + * @return true if node was moved + */ + boolean push(PiNode parent); +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,81 @@ +/* + * 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.graal.nodes.spi; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.nodes.*; + +/** + * Interface for managing replacements. + */ +public interface Replacements { + + /** + * Gets the snippet graph derived from a given method. + * + * @return the snippet graph, if any, that is derived from {@code method} + */ + StructuredGraph getSnippet(ResolvedJavaMethod method); + + /** + * Gets the graph that is a substitution for a given method. + * + * @return the graph, if any, that is a substitution for {@code method} + */ + StructuredGraph getMethodSubstitution(ResolvedJavaMethod method); + + /** + * Gets the node class with which a method invocation should be replaced. + * + * @param method target of an invocation + * @return the {@linkplain MacroSubstitution#macro() macro node class} associated with + * {@code method} or null if there is no such association + */ + Class getMacroSubstitution(ResolvedJavaMethod method); + + /** + * Gets the assumptions with which replacement graphs are preprocessed. + */ + Assumptions getAssumptions(); + + /** + * Registers all the {@linkplain MethodSubstitution method} and {@linkplain MacroSubstitution + * macro} substitutions defined by a given class. + */ + void registerSubstitutions(Class substitutions); + + /** + * Returns all methods that are currently registered as method/macro substitution or as a + * snippet. + */ + Collection getAllReplacements(); + + /** + * Determines whether the replacement of this method is flagged as being inlined always. + */ + boolean isForcedSubstitution(ResolvedJavaMethod methodAt); +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ReplacementsProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ReplacementsProvider.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,31 @@ +/* + * 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.graal.nodes.spi; + +/** + * Interface for service providers that register replacements with the compiler. + */ +public interface ReplacementsProvider { + + void registerReplacements(Replacements replacements); +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java Mon Apr 15 08:51:19 2013 +0200 @@ -23,12 +23,15 @@ package com.oracle.graal.nodes.type; import com.oracle.graal.api.code.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.type.GenericStamp.GenericStampType; public class StampFactory { + // JaCoCo Exclude + private static final Stamp[] stampCache = new Stamp[Kind.values().length]; private static final Stamp objectStamp = new ObjectStamp(null, false, false, false); private static final Stamp objectNonNullStamp = new ObjectStamp(null, false, true, false); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Mon Apr 15 08:51:19 2013 +0200 @@ -202,7 +202,7 @@ while (n != null) { if (n instanceof MethodCallTargetNode) { elements.add(((MethodCallTargetNode) n).targetMethod().asStackTraceElement(-1)); - n = ((MethodCallTargetNode) n).invoke().node(); + n = ((MethodCallTargetNode) n).invoke().asNode(); } if (n instanceof StateSplit) { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2011, 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. - */ -package com.oracle.graal.nodes.virtual; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; - -public class BoxedVirtualObjectNode extends VirtualObjectNode implements LIRLowerable, Node.ValueNumberable { - - @Input ValueNode unboxedValue; - private final ResolvedJavaType type; - private final Kind kind; - - public BoxedVirtualObjectNode(ResolvedJavaType type, Kind kind, ValueNode unboxedValue) { - this.type = type; - this.kind = kind; - this.unboxedValue = unboxedValue; - } - - public ValueNode getUnboxedValue() { - return unboxedValue; - } - - @Override - public ResolvedJavaType type() { - return type; - } - - @Override - public int entryCount() { - return 1; - } - - @Override - public String fieldName(int index) { - assert index == 0; - return "value"; - } - - @Override - public int entryIndexForOffset(long constantOffset) { - // (lstadler) unsafe access to a newly created boxing object should only ever touch the - // value field - return 0; - } - - @Override - public Kind entryKind(int index) { - return kind; - } - - @Override - public BoxedVirtualObjectNode duplicate() { - return new BoxedVirtualObjectNode(type, kind, unboxedValue); - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,10 +22,14 @@ */ package com.oracle.graal.nodes.virtual; +import java.util.*; + import sun.misc.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; @NodeInfo(nameTemplate = "VirtualArray {p#componentType/s}[{p#length}]") @@ -137,4 +141,19 @@ public VirtualArrayNode duplicate() { return new VirtualArrayNode(componentType, length); } + + @Override + public void materializeAt(FixedWithNextNode materializeNode, List values, boolean defaultValuesOnly, int lockCount) { + StructuredGraph graph = (StructuredGraph) graph(); + ResolvedJavaType element = componentType(); + NewArrayNode newArray = graph.add(new NewArrayNode(element, ConstantNode.forInt(entryCount(), graph), defaultValuesOnly, lockCount > 0)); + materializeNode.replaceAtUsages(newArray); + graph.addBeforeFixed(materializeNode, newArray); + if (!defaultValuesOnly) { + for (int i = 0; i < entryCount(); i++) { + graph.addBeforeFixed(materializeNode, graph.add(new StoreIndexedNode(newArray, ConstantNode.forInt(i, graph), element.getKind(), values.get(i)))); + } + } + graph.removeFixed(materializeNode); + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,58 @@ +/* + * 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.graal.nodes.virtual; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; + +public class VirtualBoxingNode extends VirtualInstanceNode { + + private final Kind boxingKind; + + public VirtualBoxingNode(ResolvedJavaType type, Kind boxingKind) { + super(type); + this.boxingKind = boxingKind; + } + + @Override + public VirtualBoxingNode duplicate() { + return new VirtualBoxingNode(type(), boxingKind); + } + + @Override + public boolean hasIdentity() { + return false; + } + + @Override + public void materializeAt(FixedWithNextNode materializeNode, List values, boolean defaultValuesOnly, int lockCount) { + assert values.size() == 1; + assert lockCount == 0; + StructuredGraph graph = (StructuredGraph) graph(); + BoxNode valueOf = graph.add(new BoxNode(values.get(0), type(), boxingKind)); + graph.replaceFixedWithFixed(materializeNode, valueOf); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,8 +22,12 @@ */ package com.oracle.graal.nodes.virtual; +import java.util.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; @NodeInfo(nameTemplate = "VirtualInstance {p#type}") public class VirtualInstanceNode extends VirtualObjectNode { @@ -93,4 +97,18 @@ public VirtualInstanceNode duplicate() { return new VirtualInstanceNode(type); } + + @Override + public void materializeAt(FixedWithNextNode materializeNode, List values, boolean defaultValuesOnly, int lockCount) { + StructuredGraph graph = (StructuredGraph) graph(); + NewInstanceNode newInstance = graph.add(new NewInstanceNode(type(), defaultValuesOnly, lockCount > 0)); + materializeNode.replaceAtUsages(newInstance); + graph.addBeforeFixed(materializeNode, newInstance); + if (!defaultValuesOnly) { + for (int i = 0; i < entryCount(); i++) { + graph.addBeforeFixed(materializeNode, graph.add(new StoreFieldNode(newInstance, field(i), values.get(i)))); + } + } + graph.removeFixed(materializeNode); + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes.virtual; +import java.util.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; @@ -46,13 +48,15 @@ public abstract String fieldName(int i); - public void materializeAt(@SuppressWarnings("unused") FixedNode fixed) { - // nothing to do in here - this method allows subclasses to respond to materialization - } + public abstract void materializeAt(FixedWithNextNode materializeNode, List values, boolean defaultValuesOnly, int lockCount); public abstract int entryIndexForOffset(long constantOffset); public abstract Kind entryKind(int index); public abstract VirtualObjectNode duplicate(); + + public boolean hasIdentity() { + return true; + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/BoxingEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/BoxingEliminationPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,142 +0,0 @@ -/* - * Copyright (c) 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. - */ -package com.oracle.graal.phases.common; - -import static com.oracle.graal.graph.iterators.NodePredicates.*; - -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.virtual.*; -import com.oracle.graal.phases.*; - -public class BoxingEliminationPhase extends Phase { - - private final MetaAccessProvider metaAccess; - - public BoxingEliminationPhase(MetaAccessProvider metaAccess) { - this.metaAccess = metaAccess; - } - - @Override - protected void run(StructuredGraph graph) { - if (graph.getNodes(UnboxNode.class).isNotEmpty()) { - - Map phiReplacements = new HashMap<>(); - for (UnboxNode unboxNode : graph.getNodes(UnboxNode.class)) { - tryEliminate(graph, unboxNode, phiReplacements); - } - - new DeadCodeEliminationPhase().apply(graph); - - for (BoxNode boxNode : graph.getNodes(BoxNode.class)) { - tryEliminate(boxNode); - } - } - } - - private void tryEliminate(StructuredGraph graph, UnboxNode unboxNode, Map phiReplacements) { - ValueNode unboxedValue = unboxedValue(unboxNode.source(), unboxNode.destinationKind(), phiReplacements); - if (unboxedValue != null) { - assert unboxedValue.kind() == unboxNode.kind(); - unboxNode.replaceAtUsages(unboxedValue); - graph.removeFixed(unboxNode); - } - } - - private PhiNode getReplacementPhi(PhiNode phiNode, Kind kind, Map phiReplacements) { - if (!phiReplacements.containsKey(phiNode)) { - PhiNode result = null; - ObjectStamp stamp = phiNode.objectStamp(); - if (stamp.nonNull() && stamp.isExactType()) { - ResolvedJavaType type = stamp.type(); - if (type != null && type.equals(metaAccess.lookupJavaType(kind.toBoxedJavaClass()))) { - StructuredGraph graph = (StructuredGraph) phiNode.graph(); - result = graph.add(new PhiNode(kind, phiNode.merge())); - phiReplacements.put(phiNode, result); - virtualizeUsages(phiNode, result, type, kind); - int i = 0; - for (ValueNode n : phiNode.values()) { - ValueNode unboxedValue = unboxedValue(n, kind, phiReplacements); - if (unboxedValue != null) { - assert unboxedValue.kind() == kind; - result.addInput(unboxedValue); - } else { - UnboxNode unboxNode = graph.add(new UnboxNode(kind, n)); - FixedNode pred = phiNode.merge().phiPredecessorAt(i); - graph.addBeforeFixed(pred, unboxNode); - result.addInput(unboxNode); - } - ++i; - } - } - } - } - return phiReplacements.get(phiNode); - } - - private ValueNode unboxedValue(ValueNode n, Kind kind, Map phiReplacements) { - if (n instanceof BoxNode) { - BoxNode boxNode = (BoxNode) n; - return boxNode.source(); - } else if (n instanceof PhiNode) { - PhiNode phiNode = (PhiNode) n; - return getReplacementPhi(phiNode, kind, phiReplacements); - } else { - return null; - } - } - - private static void tryEliminate(BoxNode boxNode) { - - assert boxNode.objectStamp().isExactType(); - virtualizeUsages(boxNode, boxNode.source(), boxNode.objectStamp().type(), boxNode.getSourceKind()); - - if (boxNode.usages().filter(isNotA(VirtualState.class)).isNotEmpty()) { - // Elimination failed, because boxing object escapes. - return; - } - - FrameState stateAfter = boxNode.stateAfter(); - boxNode.setStateAfter(null); - stateAfter.safeDelete(); - - ((StructuredGraph) boxNode.graph()).removeFixed(boxNode); - } - - private static void virtualizeUsages(ValueNode boxNode, ValueNode replacement, ResolvedJavaType exactType, Kind sourceKind) { - ValueNode virtualValueNode = null; - VirtualObjectNode virtualObjectNode = null; - for (Node n : boxNode.usages().filter(NodePredicates.isA(VirtualState.class)).snapshot()) { - if (virtualValueNode == null) { - virtualObjectNode = n.graph().unique(new BoxedVirtualObjectNode(exactType, sourceKind, replacement)); - } - n.replaceFirstInput(boxNode, virtualObjectNode); - } - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -36,8 +36,9 @@ import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; +import com.oracle.graal.phases.tiers.*; -public class CanonicalizerPhase extends Phase { +public class CanonicalizerPhase extends BasePhase { private static final int MAX_ITERATION_PER_NODE = 10; private static final DebugMetric METRIC_CANONICALIZED_NODES = Debug.metric("CanonicalizedNodes"); @@ -47,155 +48,161 @@ private static final DebugMetric METRIC_SIMPLIFICATION_CONSIDERED_NODES = Debug.metric("SimplificationConsideredNodes"); public static final DebugMetric METRIC_GLOBAL_VALUE_NUMBERING_HITS = Debug.metric("GlobalValueNumberingHits"); - private final int newNodesMark; - private final Assumptions assumptions; - private final MetaAccessProvider runtime; - private final CustomCanonicalizer customCanonicalizer; - private final Iterable initWorkingSet; - - private NodeWorkList workList; - private Tool tool; - private List snapshotTemp; - public interface CustomCanonicalizer { - ValueNode canonicalize(Node node); - } - - public CanonicalizerPhase(MetaAccessProvider runtime, Assumptions assumptions) { - this(runtime, assumptions, null, 0, null); - } - - /** - * @param runtime - * @param assumptions - * @param workingSet the initial working set of nodes on which the canonicalizer works, should - * be an auto-grow node bitmap - * @param customCanonicalizer - */ - public CanonicalizerPhase(MetaAccessProvider runtime, Assumptions assumptions, Iterable workingSet, CustomCanonicalizer customCanonicalizer) { - this(runtime, assumptions, workingSet, 0, customCanonicalizer); - } - - /** - * @param newNodesMark only the {@linkplain Graph#getNewNodes(int) new nodes} specified by this - * mark are processed otherwise all nodes in the graph are processed - */ - public CanonicalizerPhase(MetaAccessProvider runtime, Assumptions assumptions, int newNodesMark, CustomCanonicalizer customCanonicalizer) { - this(runtime, assumptions, null, newNodesMark, customCanonicalizer); - } - - public CanonicalizerPhase(MetaAccessProvider runtime, Assumptions assumptions, Iterable workingSet, int newNodesMark, CustomCanonicalizer customCanonicalizer) { - this.newNodesMark = newNodesMark; - this.assumptions = assumptions; - this.runtime = runtime; - this.customCanonicalizer = customCanonicalizer; - this.initWorkingSet = workingSet; - this.snapshotTemp = new ArrayList<>(); + ValueNode canonicalize(ValueNode node); } @Override - protected void run(StructuredGraph graph) { - if (initWorkingSet == null) { - workList = graph.createNodeWorkList(newNodesMark == 0, MAX_ITERATION_PER_NODE); - } else { - workList = graph.createNodeWorkList(false, MAX_ITERATION_PER_NODE); - workList.addAll(initWorkingSet); - } - if (newNodesMark > 0) { - workList.addAll(graph.getNewNodes(newNodesMark)); - } - tool = new Tool(workList, runtime, assumptions); - processWorkSet(graph); + protected void run(StructuredGraph graph, PhaseContext context) { + new Instance(context.getRuntime(), context.getAssumptions()).run(graph); } - private void processWorkSet(StructuredGraph graph) { - graph.trackInputChange(new InputChangedListener() { + public static class Instance extends Phase { + + private final int newNodesMark; + private final Assumptions assumptions; + private final MetaAccessProvider runtime; + private final CustomCanonicalizer customCanonicalizer; + private final Iterable initWorkingSet; + + private NodeWorkList workList; + private Tool tool; + private List snapshotTemp; + + public Instance(MetaAccessProvider runtime, Assumptions assumptions) { + this(runtime, assumptions, null, 0, null); + } - @Override - public void inputChanged(Node node) { - workList.addAgain(node); - } - }); + /** + * @param runtime + * @param assumptions + * @param workingSet the initial working set of nodes on which the canonicalizer works, + * should be an auto-grow node bitmap + * @param customCanonicalizer + */ + public Instance(MetaAccessProvider runtime, Assumptions assumptions, Iterable workingSet, CustomCanonicalizer customCanonicalizer) { + this(runtime, assumptions, workingSet, 0, customCanonicalizer); + } - for (Node n : workList) { - processNode(n, graph); + /** + * @param newNodesMark only the {@linkplain Graph#getNewNodes(int) new nodes} specified by + * this mark are processed otherwise all nodes in the graph are processed + */ + public Instance(MetaAccessProvider runtime, Assumptions assumptions, int newNodesMark, CustomCanonicalizer customCanonicalizer) { + this(runtime, assumptions, null, newNodesMark, customCanonicalizer); + } + + public Instance(MetaAccessProvider runtime, Assumptions assumptions, Iterable workingSet, int newNodesMark, CustomCanonicalizer customCanonicalizer) { + super("Canonicalizer"); + this.newNodesMark = newNodesMark; + this.assumptions = assumptions; + this.runtime = runtime; + this.customCanonicalizer = customCanonicalizer; + this.initWorkingSet = workingSet; + this.snapshotTemp = new ArrayList<>(); } - graph.stopTrackingInputChange(); - } - - private void processNode(Node node, StructuredGraph graph) { - if (node.isAlive()) { - METRIC_PROCESSED_NODES.increment(); - - if (tryGlobalValueNumbering(node, graph)) { - return; + @Override + protected void run(StructuredGraph graph) { + if (initWorkingSet == null) { + workList = graph.createNodeWorkList(newNodesMark == 0, MAX_ITERATION_PER_NODE); + } else { + workList = graph.createNodeWorkList(false, MAX_ITERATION_PER_NODE); + workList.addAll(initWorkingSet); + } + if (newNodesMark > 0) { + workList.addAll(graph.getNewNodes(newNodesMark)); } - int mark = graph.getMark(); - if (!tryKillUnused(node)) { - node.inputs().filter(GraphUtil.isFloatingNode()).snapshotTo(snapshotTemp); - if (!tryCanonicalize(node, graph)) { - tryInferStamp(node, graph); - } else { - for (Node in : snapshotTemp) { - if (in.isAlive() && in.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(in); + tool = new Tool(workList, runtime, assumptions); + processWorkSet(graph); + } + + private void processWorkSet(StructuredGraph graph) { + graph.trackInputChange(new InputChangedListener() { + + @Override + public void inputChanged(Node node) { + workList.addAgain(node); + } + }); + + for (Node n : workList) { + processNode(n, graph); + } + + graph.stopTrackingInputChange(); + } + + private void processNode(Node node, StructuredGraph graph) { + if (node.isAlive()) { + METRIC_PROCESSED_NODES.increment(); + + if (tryGlobalValueNumbering(node, graph)) { + return; + } + int mark = graph.getMark(); + if (!tryKillUnused(node)) { + node.inputs().filter(GraphUtil.isFloatingNode()).snapshotTo(snapshotTemp); + if (!tryCanonicalize(node, graph)) { + tryInferStamp(node, graph); + } else { + for (Node in : snapshotTemp) { + if (in.isAlive() && in.usages().isEmpty()) { + GraphUtil.killWithUnusedFloatingInputs(in); + } } } + snapshotTemp.clear(); } - snapshotTemp.clear(); - } - for (Node newNode : graph.getNewNodes(mark)) { - workList.add(newNode); + for (Node newNode : graph.getNewNodes(mark)) { + workList.add(newNode); + } } } - } - private static boolean tryKillUnused(Node node) { - if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(node); - return true; - } - return false; - } - - public static boolean tryGlobalValueNumbering(Node node, StructuredGraph graph) { - if (node.getNodeClass().valueNumberable()) { - Node newNode = graph.findDuplicate(node); - if (newNode != null) { - assert !(node instanceof FixedNode || newNode instanceof FixedNode); - node.replaceAtUsages(newNode); - node.safeDelete(); - METRIC_GLOBAL_VALUE_NUMBERING_HITS.increment(); - Debug.log("GVN applied and new node is %1s", newNode); + private static boolean tryKillUnused(Node node) { + if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.usages().isEmpty()) { + GraphUtil.killWithUnusedFloatingInputs(node); return true; } + return false; } - return false; - } - public boolean tryCanonicalize(final Node node, final StructuredGraph graph) { - boolean result = baseTryCanonicalize(node, graph); - if (!result && customCanonicalizer != null) { - ValueNode canonical = customCanonicalizer.canonicalize(node); - if (canonical == node && customCanonicalizer != null) { - canonical = customCanonicalizer.canonicalize(node); + public static boolean tryGlobalValueNumbering(Node node, StructuredGraph graph) { + if (node.getNodeClass().valueNumberable()) { + Node newNode = graph.findDuplicate(node); + if (newNode != null) { + assert !(node instanceof FixedNode || newNode instanceof FixedNode); + node.replaceAtUsages(newNode); + node.safeDelete(); + METRIC_GLOBAL_VALUE_NUMBERING_HITS.increment(); + Debug.log("GVN applied and new node is %1s", newNode); + return true; + } } - result = performReplacement(node, graph, canonical); + return false; } - return result; - } - public boolean baseTryCanonicalize(final Node node, final StructuredGraph graph) { - if (node instanceof Canonicalizable) { - assert !(node instanceof Simplifiable); - METRIC_CANONICALIZATION_CONSIDERED_NODES.increment(); - return Debug.scope("CanonicalizeNode", node, new Callable() { + public boolean tryCanonicalize(final Node node, final StructuredGraph graph) { + boolean result = baseTryCanonicalize(node, graph); + if (!result && customCanonicalizer != null && node instanceof ValueNode) { + ValueNode valueNode = (ValueNode) node; + ValueNode canonical = customCanonicalizer.canonicalize(valueNode); + result = performReplacement(node, graph, canonical); + } + return result; + } - public Boolean call() { - ValueNode canonical = ((Canonicalizable) node).canonical(tool); + public boolean baseTryCanonicalize(final Node node, final StructuredGraph graph) { + if (node instanceof Canonicalizable) { + assert !(node instanceof Simplifiable); + METRIC_CANONICALIZATION_CONSIDERED_NODES.increment(); + return Debug.scope("CanonicalizeNode", node, new Callable() { + + public Boolean call() { + ValueNode canonical = ((Canonicalizable) node).canonical(tool); // @formatter:off // cases: original node: // |Floating|Fixed-unconnected|Fixed-connected| @@ -211,137 +218,139 @@ // X: must not happen (checked with assertions) // @formatter:on - return performReplacement(node, graph, canonical); - } - }); - } else if (node instanceof Simplifiable) { - Debug.log("Canonicalizer: simplifying %s", node); - METRIC_SIMPLIFICATION_CONSIDERED_NODES.increment(); - Debug.scope("SimplifyNode", node, new Runnable() { + return performReplacement(node, graph, canonical); + } + }); + } else if (node instanceof Simplifiable) { + Debug.log("Canonicalizer: simplifying %s", node); + METRIC_SIMPLIFICATION_CONSIDERED_NODES.increment(); + Debug.scope("SimplifyNode", node, new Runnable() { - public void run() { - ((Simplifiable) node).simplify(tool); - } - }); + public void run() { + ((Simplifiable) node).simplify(tool); + } + }); + } + return node.isDeleted(); } - return node.isDeleted(); - } - private boolean performReplacement(final Node node, final StructuredGraph graph, ValueNode canonical) { - if (canonical == node) { - Debug.log("Canonicalizer: work on %s", node); - return false; - } else { - Debug.log("Canonicalizer: replacing %s with %s", node, canonical); - METRIC_CANONICALIZED_NODES.increment(); - if (node instanceof FloatingNode) { - if (canonical == null) { - // case 1 - graph.removeFloating((FloatingNode) node); + private boolean performReplacement(final Node node, final StructuredGraph graph, ValueNode canonical) { + if (canonical == node) { + Debug.log("Canonicalizer: work on %s", node); + return false; + } else { + Debug.log("Canonicalizer: replacing %s with %s", node, canonical); + METRIC_CANONICALIZED_NODES.increment(); + if (node instanceof FloatingNode) { + if (canonical == null) { + // case 1 + graph.removeFloating((FloatingNode) node); + } else { + // case 2 + assert !(canonical instanceof FixedNode) || (canonical.predecessor() != null || canonical instanceof StartNode || canonical instanceof MergeNode) : node + " -> " + canonical + + " : replacement should be floating or fixed and connected"; + graph.replaceFloating((FloatingNode) node, canonical); + } } else { - // case 2 - assert !(canonical instanceof FixedNode) || (canonical.predecessor() != null || canonical instanceof StartNode || canonical instanceof MergeNode) : node + " -> " + canonical + - " : replacement should be floating or fixed and connected"; - graph.replaceFloating((FloatingNode) node, canonical); - } - } else { - assert node instanceof FixedWithNextNode && node.predecessor() != null : node + " -> " + canonical + " : node should be fixed & connected (" + node.predecessor() + ")"; - FixedWithNextNode fixedWithNext = (FixedWithNextNode) node; + assert node instanceof FixedWithNextNode && node.predecessor() != null : node + " -> " + canonical + " : node should be fixed & connected (" + node.predecessor() + ")"; + FixedWithNextNode fixedWithNext = (FixedWithNextNode) node; - // When removing a fixed node, new canonicalization opportunities for its successor - // may arise - assert fixedWithNext.next() != null; - tool.addToWorkList(fixedWithNext.next()); + // When removing a fixed node, new canonicalization opportunities for its +// successor + // may arise + assert fixedWithNext.next() != null; + tool.addToWorkList(fixedWithNext.next()); - if (canonical == null) { - // case 3 - graph.removeFixed(fixedWithNext); - } else if (canonical instanceof FloatingNode) { - // case 4 - graph.replaceFixedWithFloating(fixedWithNext, (FloatingNode) canonical); - } else { - assert canonical instanceof FixedNode; - if (canonical.predecessor() == null) { - assert !canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " shouldn't have successors"; - // case 5 - graph.replaceFixedWithFixed(fixedWithNext, (FixedWithNextNode) canonical); + if (canonical == null) { + // case 3 + graph.removeFixed(fixedWithNext); + } else if (canonical instanceof FloatingNode) { + // case 4 + graph.replaceFixedWithFloating(fixedWithNext, (FloatingNode) canonical); } else { - assert canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " should have successors"; - // case 6 - node.replaceAtUsages(canonical); - graph.removeFixed(fixedWithNext); + assert canonical instanceof FixedNode; + if (canonical.predecessor() == null) { + assert !canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " shouldn't have successors"; + // case 5 + graph.replaceFixedWithFixed(fixedWithNext, (FixedWithNextNode) canonical); + } else { + assert canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " should have successors"; + // case 6 + node.replaceAtUsages(canonical); + graph.removeFixed(fixedWithNext); + } } } + return true; } - return true; } - } - /** - * Calls {@link ValueNode#inferStamp()} on the node and, if it returns true (which means that - * the stamp has changed), re-queues the node's usages . If the stamp has changed then this - * method also checks if the stamp now describes a constant integer value, in which case the - * node is replaced with a constant. - */ - private void tryInferStamp(Node node, StructuredGraph graph) { - if (node.isAlive() && node instanceof ValueNode) { - ValueNode valueNode = (ValueNode) node; - METRIC_INFER_STAMP_CALLED.increment(); - if (valueNode.inferStamp()) { - METRIC_STAMP_CHANGED.increment(); - if (valueNode.stamp() instanceof IntegerStamp && valueNode.integerStamp().lowerBound() == valueNode.integerStamp().upperBound()) { - ValueNode replacement = ConstantNode.forIntegerKind(valueNode.kind(), valueNode.integerStamp().lowerBound(), graph); - Debug.log("Canonicalizer: replacing %s with %s (inferStamp)", valueNode, replacement); - valueNode.replaceAtUsages(replacement); - } else { - for (Node usage : valueNode.usages()) { - workList.addAgain(usage); + /** + * Calls {@link ValueNode#inferStamp()} on the node and, if it returns true (which means + * that the stamp has changed), re-queues the node's usages . If the stamp has changed then + * this method also checks if the stamp now describes a constant integer value, in which + * case the node is replaced with a constant. + */ + private void tryInferStamp(Node node, StructuredGraph graph) { + if (node.isAlive() && node instanceof ValueNode) { + ValueNode valueNode = (ValueNode) node; + METRIC_INFER_STAMP_CALLED.increment(); + if (valueNode.inferStamp()) { + METRIC_STAMP_CHANGED.increment(); + if (valueNode.stamp() instanceof IntegerStamp && valueNode.integerStamp().lowerBound() == valueNode.integerStamp().upperBound()) { + ValueNode replacement = ConstantNode.forIntegerKind(valueNode.kind(), valueNode.integerStamp().lowerBound(), graph); + Debug.log("Canonicalizer: replacing %s with %s (inferStamp)", valueNode, replacement); + valueNode.replaceAtUsages(replacement); + } else { + for (Node usage : valueNode.usages()) { + workList.addAgain(usage); + } } } } } - } - private static final class Tool implements SimplifierTool { + private static final class Tool implements SimplifierTool { - private final NodeWorkList nodeWorkSet; - private final MetaAccessProvider runtime; - private final Assumptions assumptions; + private final NodeWorkList nodeWorkSet; + private final MetaAccessProvider runtime; + private final Assumptions assumptions; - public Tool(NodeWorkList nodeWorkSet, MetaAccessProvider runtime, Assumptions assumptions) { - this.nodeWorkSet = nodeWorkSet; - this.runtime = runtime; - this.assumptions = assumptions; - } + public Tool(NodeWorkList nodeWorkSet, MetaAccessProvider runtime, Assumptions assumptions) { + this.nodeWorkSet = nodeWorkSet; + this.runtime = runtime; + this.assumptions = assumptions; + } - @Override - public void deleteBranch(FixedNode branch) { - branch.predecessor().replaceFirstSuccessor(branch, null); - GraphUtil.killCFG(branch); - } + @Override + public void deleteBranch(FixedNode branch) { + branch.predecessor().replaceFirstSuccessor(branch, null); + GraphUtil.killCFG(branch); + } - /** - * @return an object that can be used for recording assumptions or {@code null} if - * assumptions are not allowed in the current context. - */ - @Override - public Assumptions assumptions() { - return assumptions; - } + /** + * @return an object that can be used for recording assumptions or {@code null} if + * assumptions are not allowed in the current context. + */ + @Override + public Assumptions assumptions() { + return assumptions; + } - @Override - public MetaAccessProvider runtime() { - return runtime; - } + @Override + public MetaAccessProvider runtime() { + return runtime; + } - @Override - public void addToWorkList(Node node) { - nodeWorkSet.addAgain(node); - } + @Override + public void addToWorkList(Node node) { + nodeWorkSet.addAgain(node); + } - @Override - public void removeIfUnused(Node node) { - tryKillUnused(node); + @Override + public void removeIfUnused(Node node) { + tryKillUnused(node); + } } } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -346,7 +346,7 @@ private static Scope createScope(Loop loop, HashMap processedLoops) { Scope parent = processedLoops.get(loop.parent); if (parent == null) { - parent = createScope(loop, processedLoops); + parent = createScope(loop.parent, processedLoops); } Scope result = new Scope(loop.loopBegin(), parent); processedLoops.put(loop, result); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -482,9 +482,9 @@ PiNode piNode; if (isNull) { ConstantNode nullObject = ConstantNode.forObject(null, metaAccessProvider, graph); - piNode = graph.unique(new PiNode(nullObject, anchor, StampFactory.forConstant(nullObject.value, metaAccessProvider))); + piNode = graph.unique(new PiNode(nullObject, StampFactory.forConstant(nullObject.value, metaAccessProvider), anchor)); } else { - piNode = graph.unique(new PiNode(object, anchor, StampFactory.declared(type, nonNull))); + piNode = graph.unique(new PiNode(object, StampFactory.declared(type, nonNull), anchor)); } checkCast.replaceAtUsages(piNode); graph.replaceFixedWithFixed(checkCast, anchor); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ExpandBoxingNodesPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ExpandBoxingNodesPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 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. - */ -package com.oracle.graal.phases.common; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.phases.*; - -public class ExpandBoxingNodesPhase extends Phase { - - private final BoxingMethodPool pool; - - public ExpandBoxingNodesPhase(BoxingMethodPool pool) { - this.pool = pool; - } - - @Override - protected void run(StructuredGraph graph) { - for (BoxNode boxNode : graph.getNodes(BoxNode.class)) { - boxNode.expand(pool); - } - - for (UnboxNode unboxNode : graph.getNodes(UnboxNode.class)) { - unboxNode.expand(pool); - } - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -146,7 +146,7 @@ StructuredGraph graph = (StructuredGraph) accessNode.graph(); assert accessNode.getNullCheck() == false; Object locationIdentity = accessNode.location().locationIdentity(); - if (locationIdentity != LocationNode.UNKNOWN_LOCATION) { + if (locationIdentity != LocationNode.ANY_LOCATION) { ValueNode lastLocationAccess = state.getLastLocationAccess(locationIdentity); FloatingAccessNode floatingNode = accessNode.asFloatingNode(lastLocationAccess); floatingNode.setNullCheck(accessNode.getNullCheck()); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2013, 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.graal.phases.common; + +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.graph.*; +import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure; + +public class FrameStateAssignmentPhase extends Phase { + + private static class FrameStateAssignmentState { + + private FrameState framestate; + + public FrameStateAssignmentState(FrameState framestate) { + this.framestate = framestate; + } + + public FrameState getFramestate() { + return framestate; + } + + public void setFramestate(FrameState framestate) { + assert framestate != null; + this.framestate = framestate; + } + + @Override + public String toString() { + return "FrameStateAssignementState: " + framestate; + } + } + + private static class FrameStateAssignementClosure extends BlockIteratorClosure { + + @Override + protected void processBlock(Block block, FrameStateAssignmentState currentState) { + FixedNode node = block.getBeginNode(); + while (node != null) { + if (node instanceof DeoptimizingNode) { + DeoptimizingNode deopt = (DeoptimizingNode) node; + if (deopt.canDeoptimize() && deopt.getDeoptimizationState() == null) { + deopt.setDeoptimizationState(currentState.getFramestate()); + } + } + + if (node instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) node; + if (stateSplit.stateAfter() != null) { + currentState.setFramestate(stateSplit.stateAfter()); + stateSplit.setStateAfter(null); + } + } + + if (node instanceof FixedWithNextNode) { + node = ((FixedWithNextNode) node).next(); + } else { + node = null; + } + } + } + + @Override + protected FrameStateAssignmentState merge(Block mergeBlock, List states) { + MergeNode merge = (MergeNode) mergeBlock.getBeginNode(); + if (merge.stateAfter() != null) { + return new FrameStateAssignmentState(merge.stateAfter()); + } + return new FrameStateAssignmentState(singleFrameState(states)); + } + + @Override + protected FrameStateAssignmentState cloneState(FrameStateAssignmentState oldState) { + return new FrameStateAssignmentState(oldState.getFramestate()); + } + + @Override + protected List processLoop(Loop loop, FrameStateAssignmentState initialState) { + return ReentrantBlockIterator.processLoop(this, loop, initialState).exitStates; + } + + } + + @Override + protected void run(StructuredGraph graph) { + assert checkFixedDeopts(graph); + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false); + ReentrantBlockIterator.apply(new FrameStateAssignementClosure(), cfg.getStartBlock(), new FrameStateAssignmentState(null), null); + } + + private static boolean checkFixedDeopts(StructuredGraph graph) { + NodePredicate isFloatingNode = GraphUtil.isFloatingNode(); + for (Node n : graph.getNodes().filterInterface(DeoptimizingNode.class)) { + if (((DeoptimizingNode) n).canDeoptimize() && isFloatingNode.apply(n)) { + return false; + } + } + return true; + } + + private static FrameState singleFrameState(List states) { + Iterator it = states.iterator(); + assert it.hasNext(); + FrameState first = it.next().getFramestate(); + while (it.hasNext()) { + if (first != it.next().getFramestate()) { + return null; + } + } + return first; + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -114,12 +114,12 @@ Access fixedAccess = access; if (access instanceof FloatingAccessNode) { fixedAccess = ((FloatingAccessNode) access).asFixedNode(); - replaceCurrent((FixedWithNextNode) fixedAccess.node()); + replaceCurrent((FixedWithNextNode) fixedAccess.asNode()); } assert fixedAccess instanceof FixedNode; fixedAccess.setNullCheck(true); LogicNode condition = guard.condition(); - guard.replaceAndDelete(fixedAccess.node()); + guard.replaceAndDelete(fixedAccess.asNode()); if (condition.usages().isEmpty()) { GraphUtil.killWithUnusedFloatingInputs(condition); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IdentifyBoxingPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IdentifyBoxingPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * Copyright (c) 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. - */ -package com.oracle.graal.phases.common; - -import java.lang.reflect.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.phases.*; - -public class IdentifyBoxingPhase extends Phase { - - private final BoxingMethodPool pool; - - public IdentifyBoxingPhase(BoxingMethodPool pool) { - this.pool = pool; - } - - @Override - protected void run(StructuredGraph graph) { - for (Invoke invoke : graph.getInvokes()) { - tryIntrinsify(invoke); - } - } - - public void tryIntrinsify(Invoke invoke) { - if (!(invoke.callTarget() instanceof MethodCallTargetNode)) { - return; - } - MethodCallTargetNode callTarget = invoke.methodCallTarget(); - ResolvedJavaMethod targetMethod = callTarget.targetMethod(); - if (pool.isSpecialMethod(targetMethod)) { - assert callTarget.arguments().size() == 1 : "boxing/unboxing method must have exactly one argument"; - Kind returnKind = callTarget.returnKind(); - ValueNode sourceValue = callTarget.arguments().get(0); - - // Check whether this is a boxing or an unboxing. - Node newNode = null; - if (returnKind == Kind.Object) { - // We have a boxing method here. - assert Modifier.isStatic(targetMethod.getModifiers()) : "boxing method must be static"; - Kind sourceKind = targetMethod.getSignature().getParameterKind(0); - newNode = invoke.graph().add(new BoxNode(sourceValue, targetMethod.getDeclaringClass(), sourceKind, invoke.bci())); - } else { - // We have an unboxing method here. - assert !Modifier.isStatic(targetMethod.getModifiers()) : "unboxing method must be an instance method"; - newNode = invoke.graph().add(new UnboxNode(returnKind, sourceValue)); - } - - // Intrinsify the invoke to the special node. - invoke.intrinsify(newNode); - } - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -52,6 +52,7 @@ private final MetaAccessProvider runtime; private final Assumptions assumptions; + private final Replacements replacements; private final GraphCache cache; private final InliningPolicy inliningPolicy; private final OptimisticOptimizations optimisticOpts; @@ -67,12 +68,15 @@ private static final DebugMetric metricInliningStoppedByMaxDesiredSize = Debug.metric("InliningStoppedByMaxDesiredSize"); private static final DebugMetric metricInliningRuns = Debug.metric("Runs"); - public InliningPhase(MetaAccessProvider runtime, Map hints, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) { - this(runtime, assumptions, cache, plan, createInliningPolicy(runtime, assumptions, optimisticOpts, hints), optimisticOpts); + public InliningPhase(MetaAccessProvider runtime, Map hints, Replacements replacements, Assumptions assumptions, GraphCache cache, PhasePlan plan, + OptimisticOptimizations optimisticOpts) { + this(runtime, replacements, assumptions, cache, plan, createInliningPolicy(runtime, replacements, assumptions, optimisticOpts, hints), optimisticOpts); } - public InliningPhase(MetaAccessProvider runtime, Assumptions assumptions, GraphCache cache, PhasePlan plan, InliningPolicy inliningPolicy, OptimisticOptimizations optimisticOpts) { + public InliningPhase(MetaAccessProvider runtime, Replacements replacements, Assumptions assumptions, GraphCache cache, PhasePlan plan, InliningPolicy inliningPolicy, + OptimisticOptimizations optimisticOpts) { this.runtime = runtime; + this.replacements = replacements; this.assumptions = assumptions; this.cache = cache; this.plan = plan; @@ -107,13 +111,13 @@ if (isWorthInlining) { int mark = graph.getMark(); try { - List invokeUsages = candidate.invoke().node().usages().snapshot(); - candidate.inline(graph, runtime, this, assumptions); + List invokeUsages = candidate.invoke().asNode().usages().snapshot(); + candidate.inline(graph, runtime, replacements, this, assumptions); Debug.dump(graph, "after %s", candidate); Iterable newNodes = graph.getNewNodes(mark); inliningPolicy.scanInvokes(newNodes); if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(runtime, assumptions, invokeUsages, mark, customCanonicalizer).apply(graph); + new CanonicalizerPhase.Instance(runtime, assumptions, invokeUsages, mark, customCanonicalizer).apply(graph); } inliningCount++; metricInliningPerformed.increment(); @@ -157,7 +161,7 @@ new ComputeProbabilityPhase().apply(newGraph); } if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(runtime, assumptions).apply(newGraph); + new CanonicalizerPhase.Instance(runtime, assumptions).apply(newGraph); } if (GraalOptions.CullFrameStates) { new CullFrameStatesPhase().apply(newGraph); @@ -178,10 +182,12 @@ private static class GreedySizeBasedInliningDecision implements InliningDecision { private final MetaAccessProvider runtime; + private final Replacements replacements; private final Map hints; - public GreedySizeBasedInliningDecision(MetaAccessProvider runtime, Map hints) { + public GreedySizeBasedInliningDecision(MetaAccessProvider runtime, Replacements replacements, Map hints) { this.runtime = runtime; + this.replacements = replacements; this.hints = hints; } @@ -195,8 +201,14 @@ * also getting queued in the compilation queue concurrently) */ - if (GraalOptions.AlwaysInlineIntrinsics && onlyIntrinsics(info)) { - return InliningUtil.logInlinedMethod(info, "intrinsic"); + if (GraalOptions.AlwaysInlineIntrinsics) { + if (onlyIntrinsics(replacements, info)) { + return InliningUtil.logInlinedMethod(info, "intrinsic"); + } + } else { + if (onlyForcedIntrinsics(replacements, info)) { + return InliningUtil.logInlinedMethod(info, "intrinsic"); + } } double bonus = 1; @@ -266,7 +278,7 @@ private static int countInvokeUsages(InlineInfo info) { // inlining calls with lots of usages simplifies the caller int usages = 0; - for (Node n : info.invoke().node().usages()) { + for (Node n : info.invoke().asNode().usages()) { if (!(n instanceof FrameState)) { usages++; } @@ -334,9 +346,21 @@ return result; } - private static boolean onlyIntrinsics(InlineInfo info) { + private static boolean onlyIntrinsics(Replacements replacements, InlineInfo info) { for (int i = 0; i < info.numberOfMethods(); i++) { - if (!InliningUtil.canIntrinsify(info.methodAt(i))) { + if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) { + return false; + } + } + return true; + } + + private static boolean onlyForcedIntrinsics(Replacements replacements, InlineInfo info) { + for (int i = 0; i < info.numberOfMethods(); i++) { + if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) { + return false; + } + if (!replacements.isForcedSubstitution(info.methodAt(i))) { return false; } } @@ -348,13 +372,15 @@ private final InliningDecision inliningDecision; private final Assumptions assumptions; + private final Replacements replacements; private final OptimisticOptimizations optimisticOpts; private final Deque sortedInvokes; private NodeBitMap visitedFixedNodes; private FixedNode invokePredecessor; - public CFInliningPolicy(InliningDecision inliningPolicy, Assumptions assumptions, OptimisticOptimizations optimisticOpts) { + public CFInliningPolicy(InliningDecision inliningPolicy, Replacements replacements, Assumptions assumptions, OptimisticOptimizations optimisticOpts) { this.inliningDecision = inliningPolicy; + this.replacements = replacements; this.assumptions = assumptions; this.optimisticOpts = optimisticOpts; this.sortedInvokes = new ArrayDeque<>(); @@ -372,7 +398,7 @@ public InlineInfo next() { Invoke invoke = sortedInvokes.pop(); - InlineInfo info = InliningUtil.getInlineInfo(invoke, assumptions, optimisticOpts); + InlineInfo info = InliningUtil.getInlineInfo(invoke, replacements, assumptions, optimisticOpts); if (info != null) { invokePredecessor = (FixedNode) info.invoke().predecessor(); assert invokePredecessor.isAlive(); @@ -513,8 +539,8 @@ } } - private static InliningPolicy createInliningPolicy(MetaAccessProvider runtime, Assumptions assumptions, OptimisticOptimizations optimisticOpts, Map hints) { - InliningDecision inliningDecision = new GreedySizeBasedInliningDecision(runtime, hints); - return new CFInliningPolicy(inliningDecision, assumptions, optimisticOpts); + private static InliningPolicy createInliningPolicy(MetaAccessProvider runtime, Replacements replacements, Assumptions assumptions, OptimisticOptimizations optimisticOpts, Map hints) { + InliningDecision inliningDecision = new GreedySizeBasedInliningDecision(runtime, replacements, hints); + return new CFInliningPolicy(inliningDecision, replacements, assumptions, optimisticOpts); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Mon Apr 15 08:51:19 2013 +0200 @@ -31,7 +31,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType; import com.oracle.graal.api.meta.ResolvedJavaType.Representation; -import com.oracle.graal.api.replacements.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; @@ -39,6 +38,7 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; @@ -73,13 +73,47 @@ boolean isWorthInlining(InlineInfo info); } + /** + * Print a HotSpot-style inlining message to the console. + */ + private static void printInlining(final InlineInfo info, final boolean success, final String msg, final Object... args) { + printInlining(info.methodAt(0), info.invoke(), success, msg, args); + } + + /** + * Print a HotSpot-style inlining message to the console. + */ + private static void printInlining(final ResolvedJavaMethod method, final Invoke invoke, final boolean success, final String msg, final Object... args) { + if (GraalOptions.HotSpotPrintInlining) { + final int mod = method.getModifiers(); + // 1234567 + TTY.print(" "); // print timestamp + // 1234 + TTY.print(" "); // print compilation number + // % s ! b n + TTY.print("%c%c%c%c%c ", ' ', Modifier.isSynchronized(mod) ? 's' : ' ', ' ', ' ', Modifier.isNative(mod) ? 'n' : ' '); + TTY.print(" "); // more indent + TTY.print(" "); // initial inlining indent + final int level = computeInliningLevel(invoke); + for (int i = 0; i < level; i++) { + TTY.print(" "); + } + TTY.println(String.format("@ %d %s %s%s", invoke.bci(), methodName(method, null), success ? "" : "not inlining ", String.format(msg, args))); + } + } + + public static boolean logInlinedMethod(InlineInfo info, String msg, Object... args) { + logInliningDecision(info, true, msg, args); + return true; + } + public static boolean logNotInlinedMethod(InlineInfo info, String msg, Object... args) { - logInliningDecision(info, false, msg, args); return false; } public static void logInliningDecision(InlineInfo info, boolean success, String msg, final Object... args) { + printInlining(info, success, msg, args); if (shouldLogInliningDecision()) { logInliningDecision(methodName(info), success, msg, args); } @@ -94,11 +128,6 @@ }); } - public static boolean logInlinedMethod(InlineInfo info, String string, Object... args) { - logInliningDecision(info, true, string, args); - return true; - } - private static boolean logNotInlinedMethodAndReturnFalse(Invoke invoke, String msg) { if (shouldLogInliningDecision()) { String methodString = invoke.toString() + (invoke.callTarget() == null ? " callTarget=null" : invoke.callTarget().targetName()); @@ -112,6 +141,7 @@ } private static InlineInfo logNotInlinedMethodAndReturnNull(Invoke invoke, ResolvedJavaMethod method, String msg, Object... args) { + printInlining(method, invoke, false, msg, args); if (shouldLogInliningDecision()) { String methodString = methodName(method, invoke); logInliningDecision(methodString, false, msg, args); @@ -120,6 +150,7 @@ } private static boolean logNotInlinedMethodAndReturnFalse(Invoke invoke, ResolvedJavaMethod method, String msg) { + printInlining(method, invoke, false, msg, new Object[0]); if (shouldLogInliningDecision()) { String methodString = methodName(method, invoke); logInliningDecision(methodString, false, msg, new Object[0]); @@ -193,7 +224,7 @@ * return value of the inlined method (or null for void methods and methods that have no * non-exceptional exit). **/ - void inline(StructuredGraph graph, MetaAccessProvider runtime, InliningCallback callback, Assumptions assumptions); + void inline(StructuredGraph graph, MetaAccessProvider runtime, Replacements replacements, InliningCallback callback, Assumptions assumptions); /** * Try to make the call static bindable to avoid interface and virtual method calls. @@ -219,17 +250,17 @@ return computeInliningLevel(invoke); } - protected static void inline(Invoke invoke, ResolvedJavaMethod concrete, InliningCallback callback, Assumptions assumptions, boolean receiverNullCheck) { - Class macroNodeClass = getMacroNodeClass(concrete); + protected static void inline(Invoke invoke, ResolvedJavaMethod concrete, InliningCallback callback, Replacements replacements, Assumptions assumptions, boolean receiverNullCheck) { + Class macroNodeClass = getMacroNodeClass(replacements, concrete); StructuredGraph graph = (StructuredGraph) invoke.graph(); if (macroNodeClass != null) { FixedWithNextNode macroNode; try { macroNode = macroNodeClass.getConstructor(Invoke.class).newInstance(invoke); } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) { - throw new GraalInternalError(e).addContext(invoke.node()).addContext("macroSubstitution", macroNodeClass); + throw new GraalInternalError(e).addContext(invoke.asNode()).addContext("macroSubstitution", macroNodeClass); } - macroNode.setProbability(invoke.node().probability()); + macroNode.setProbability(invoke.asNode().probability()); CallTargetNode callTarget = invoke.callTarget(); if (invoke instanceof InvokeNode) { graph.replaceFixedWithFixed((InvokeNode) invoke, graph.add(macroNode)); @@ -240,7 +271,7 @@ } GraphUtil.killWithUnusedFloatingInputs(callTarget); } else { - StructuredGraph calleeGraph = getIntrinsicGraph(concrete); + StructuredGraph calleeGraph = getIntrinsicGraph(replacements, concrete); if (calleeGraph == null) { calleeGraph = getGraph(concrete, callback); } @@ -268,7 +299,7 @@ protected void replaceInvokeCallTarget(StructuredGraph graph, InvokeKind invokeKind, ResolvedJavaMethod targetMethod) { MethodCallTargetNode oldCallTarget = invoke.methodCallTarget(); MethodCallTargetNode newCallTarget = graph.add(new MethodCallTargetNode(invokeKind, targetMethod, oldCallTarget.arguments().toArray(new ValueNode[0]), oldCallTarget.returnType())); - invoke.node().replaceFirstInput(oldCallTarget, newCallTarget); + invoke.asNode().replaceFirstInput(oldCallTarget, newCallTarget); } } @@ -286,8 +317,8 @@ } @Override - public void inline(StructuredGraph compilerGraph, MetaAccessProvider runtime, InliningCallback callback, Assumptions assumptions) { - inline(invoke, concrete, callback, assumptions, true); + public void inline(StructuredGraph compilerGraph, MetaAccessProvider runtime, Replacements replacements, InliningCallback callback, Assumptions assumptions) { + inline(invoke, concrete, callback, replacements, assumptions, true); } @Override @@ -340,9 +371,9 @@ } @Override - public void inline(StructuredGraph graph, MetaAccessProvider runtime, InliningCallback callback, Assumptions assumptions) { + public void inline(StructuredGraph graph, MetaAccessProvider runtime, Replacements replacements, InliningCallback callback, Assumptions assumptions) { createGuard(graph, runtime); - inline(invoke, concrete, callback, assumptions, false); + inline(invoke, concrete, callback, replacements, assumptions, false); } @Override @@ -364,9 +395,9 @@ ValueNode anchoredReceiver = createAnchoredReceiver(graph, anchor, type, receiver, true); invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver); - graph.addBeforeFixed(invoke.node(), receiverHub); - graph.addBeforeFixed(invoke.node(), guard); - graph.addBeforeFixed(invoke.node(), anchor); + graph.addBeforeFixed(invoke.asNode(), receiverHub); + graph.addBeforeFixed(invoke.asNode(), guard); + graph.addBeforeFixed(invoke.asNode(), anchor); } @Override @@ -410,13 +441,13 @@ } @Override - public void inline(StructuredGraph graph, MetaAccessProvider runtime, InliningCallback callback, Assumptions assumptions) { + public void inline(StructuredGraph graph, MetaAccessProvider runtime, Replacements replacements, InliningCallback callback, Assumptions assumptions) { // receiver null check must be the first node InliningUtil.receiverNullCheck(invoke); if (hasSingleMethod()) { - inlineSingleMethod(graph, callback, assumptions); + inlineSingleMethod(graph, callback, replacements, assumptions); } else { - inlineMultipleMethods(graph, callback, assumptions); + inlineMultipleMethods(graph, callback, replacements, assumptions); } } @@ -428,7 +459,7 @@ return notRecordedTypeProbability > 0; } - private void inlineMultipleMethods(StructuredGraph graph, InliningCallback callback, Assumptions assumptions) { + private void inlineMultipleMethods(StructuredGraph graph, InliningCallback callback, Replacements replacements, Assumptions assumptions) { int numberOfMethods = concretes.size(); FixedNode continuation = invoke.next(); @@ -439,8 +470,8 @@ returnMerge.setStateAfter(invoke.stateAfter().duplicate(invoke.stateAfter().bci)); PhiNode returnValuePhi = null; - if (invoke.node().kind() != Kind.Void) { - returnValuePhi = graph.unique(new PhiNode(invoke.node().kind(), returnMerge)); + if (invoke.asNode().kind() != Kind.Void) { + returnValuePhi = graph.unique(new PhiNode(invoke.asNode().kind(), returnMerge)); } MergeNode exceptionMerge = null; @@ -489,7 +520,7 @@ GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge()); } - assert invoke.node().isAlive(); + assert invoke.asNode().isAlive(); // replace the invoke with a switch on the type of the actual receiver createDispatchOnTypeBeforeInvoke(graph, successors, false); @@ -497,10 +528,10 @@ assert invoke.next() == continuation; invoke.setNext(null); returnMerge.setNext(continuation); - invoke.node().replaceAtUsages(returnValuePhi); - invoke.node().replaceAndDelete(null); + invoke.asNode().replaceAtUsages(returnValuePhi); + invoke.asNode().replaceAndDelete(null); - ArrayList replacements = new ArrayList<>(); + ArrayList replacementNodes = new ArrayList<>(); // do the actual inlining for every invoke for (int i = 0; i < numberOfMethods; i++) { @@ -513,12 +544,12 @@ PiNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver, exact); invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver); - inline(invokeForInlining, concretes.get(i), callback, assumptions, false); + inline(invokeForInlining, concretes.get(i), callback, replacements, assumptions, false); - replacements.add(anchoredReceiver); + replacementNodes.add(anchoredReceiver); } if (shouldFallbackToInvoke()) { - replacements.add(null); + replacementNodes.add(null); } if (GraalOptions.OptTailDuplication) { /* @@ -538,7 +569,7 @@ if (opportunities > 0) { metricInliningTailDuplication.increment(); Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities); - TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacements); + TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes); } } } @@ -576,7 +607,7 @@ return result; } - private void inlineSingleMethod(StructuredGraph graph, InliningCallback callback, Assumptions assumptions) { + private void inlineSingleMethod(StructuredGraph graph, InliningCallback callback, Replacements replacements, Assumptions assumptions) { assert concretes.size() == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0; BeginNode calleeEntryNode = graph.add(new BeginNode()); @@ -586,10 +617,10 @@ BeginNode[] successors = new BeginNode[]{calleeEntryNode, unknownTypeSux}; createDispatchOnTypeBeforeInvoke(graph, successors, false); - calleeEntryNode.setNext(invoke.node()); + calleeEntryNode.setNext(invoke.asNode()); ResolvedJavaMethod concrete = concretes.get(0); - inline(invoke, concrete, callback, assumptions, false); + inline(invoke, concrete, callback, replacements, assumptions, false); } private void createDispatchOnTypeBeforeInvoke(StructuredGraph graph, BeginNode[] successors, boolean invokeIsOnlySuccessor) { @@ -597,7 +628,7 @@ Kind hubKind = invoke.methodCallTarget().targetMethod().getDeclaringClass().getEncoding(Representation.ObjectHub).getKind(); LoadHubNode hub = graph.add(new LoadHubNode(invoke.methodCallTarget().receiver(), hubKind)); - graph.addBeforeFixed(invoke.node(), hub); + graph.addBeforeFixed(invoke.asNode(), hub); ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.size()]; double[] keyProbabilities = new double[ptypes.size() + 1]; @@ -612,7 +643,7 @@ keySuccessors[keySuccessors.length - 1] = successors.length - 1; TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(hub, successors, keys, keyProbabilities, keySuccessors)); - FixedWithNextNode pred = (FixedWithNextNode) invoke.node().predecessor(); + FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor(); pred.setNext(typeSwitch); } @@ -620,7 +651,7 @@ double probability, boolean useForInlining) { Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining, probability); BeginNode calleeEntryNode = graph.add(new BeginNode()); - calleeEntryNode.setNext(duplicatedInvoke.node()); + calleeEntryNode.setNext(duplicatedInvoke.asNode()); calleeEntryNode.setProbability(probability); EndNode endNode = graph.add(new EndNode()); @@ -630,24 +661,24 @@ returnMerge.addForwardEnd(endNode); if (returnValuePhi != null) { - returnValuePhi.addInput(duplicatedInvoke.node()); + returnValuePhi.addInput(duplicatedInvoke.asNode()); } return calleeEntryNode; } private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining, double probability) { - Invoke result = (Invoke) invoke.node().copyWithInputs(); + Invoke result = (Invoke) invoke.asNode().copyWithInputs(); Node callTarget = result.callTarget().copyWithInputs(); - result.node().replaceFirstInput(result.callTarget(), callTarget); + result.asNode().replaceFirstInput(result.callTarget(), callTarget); result.setUseForInlining(useForInlining); result.setProbability(probability); result.setInliningRelevance(invoke.inliningRelevance() * probability); - Kind kind = invoke.node().kind(); + Kind kind = invoke.asNode().kind(); if (kind != Kind.Void) { FrameState stateAfter = invoke.stateAfter(); stateAfter = stateAfter.duplicate(stateAfter.bci); - stateAfter.replaceFirstInput(invoke.node(), result.node()); + stateAfter.replaceFirstInput(invoke.asNode(), result.asNode()); result.setStateAfter(stateAfter); } @@ -712,7 +743,7 @@ BeginNode[] successors = new BeginNode[]{invocationEntry, unknownTypeSux}; createDispatchOnTypeBeforeInvoke(graph, successors, true); - invocationEntry.setNext(invoke.node()); + invocationEntry.setNext(invoke.asNode()); ValueNode receiver = invoke.methodCallTarget().receiver(); PiNode anchoredReceiver = createAnchoredReceiver(graph, invocationEntry, target.getDeclaringClass(), receiver, false); invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver); @@ -759,11 +790,11 @@ } @Override - public void inline(StructuredGraph graph, MetaAccessProvider runtime, InliningCallback callback, Assumptions assumptions) { + public void inline(StructuredGraph graph, MetaAccessProvider runtime, Replacements replacements, InliningCallback callback, Assumptions assumptions) { assumptions.record(takenAssumption); Debug.log("recording assumption: %s", takenAssumption); - super.inline(graph, runtime, callback, assumptions); + super.inline(graph, runtime, replacements, callback, assumptions); } @Override @@ -784,7 +815,7 @@ * @param invoke the invoke that should be inlined * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke */ - public static InlineInfo getInlineInfo(Invoke invoke, Assumptions assumptions, OptimisticOptimizations optimisticOpts) { + public static InlineInfo getInlineInfo(Invoke invoke, Replacements replacements, Assumptions assumptions, OptimisticOptimizations optimisticOpts) { if (!checkInvokeConditions(invoke)) { return null; } @@ -793,7 +824,7 @@ ResolvedJavaMethod targetMethod = callTarget.targetMethod(); if (callTarget.invokeKind() == InvokeKind.Special || targetMethod.canBeStaticallyBound()) { - return getExactInlineInfo(invoke, optimisticOpts, targetMethod); + return getExactInlineInfo(replacements, invoke, optimisticOpts, targetMethod); } assert callTarget.invokeKind() == InvokeKind.Virtual || callTarget.invokeKind() == InvokeKind.Interface; @@ -808,49 +839,50 @@ holder = receiverType; if (receiverStamp.isExactType()) { assert targetMethod.getDeclaringClass().isAssignableFrom(holder) : holder + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod; - return getExactInlineInfo(invoke, optimisticOpts, holder.resolveMethod(targetMethod)); + return getExactInlineInfo(replacements, invoke, optimisticOpts, holder.resolveMethod(targetMethod)); } } } if (holder.isArray()) { // arrays can be treated as Objects - return getExactInlineInfo(invoke, optimisticOpts, holder.resolveMethod(targetMethod)); + return getExactInlineInfo(replacements, invoke, optimisticOpts, holder.resolveMethod(targetMethod)); } if (assumptions.useOptimisticAssumptions()) { ResolvedJavaType uniqueSubtype = holder.findUniqueConcreteSubtype(); if (uniqueSubtype != null) { - return getAssumptionInlineInfo(invoke, optimisticOpts, uniqueSubtype.resolveMethod(targetMethod), new Assumptions.ConcreteSubtype(holder, uniqueSubtype)); + return getAssumptionInlineInfo(replacements, invoke, optimisticOpts, uniqueSubtype.resolveMethod(targetMethod), new Assumptions.ConcreteSubtype(holder, uniqueSubtype)); } ResolvedJavaMethod concrete = holder.findUniqueConcreteMethod(targetMethod); if (concrete != null) { - return getAssumptionInlineInfo(invoke, optimisticOpts, concrete, new Assumptions.ConcreteMethod(targetMethod, holder, concrete)); + return getAssumptionInlineInfo(replacements, invoke, optimisticOpts, concrete, new Assumptions.ConcreteMethod(targetMethod, holder, concrete)); } } // type check based inlining - return getTypeCheckedInlineInfo(invoke, caller, holder, targetMethod, optimisticOpts); + return getTypeCheckedInlineInfo(replacements, invoke, caller, holder, targetMethod, optimisticOpts); } - private static InlineInfo getAssumptionInlineInfo(Invoke invoke, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod concrete, Assumption takenAssumption) { + private static InlineInfo getAssumptionInlineInfo(Replacements replacements, Invoke invoke, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod concrete, Assumption takenAssumption) { assert !Modifier.isAbstract(concrete.getModifiers()); - if (!checkTargetConditions(invoke, concrete, optimisticOpts)) { + if (!checkTargetConditions(replacements, invoke, concrete, optimisticOpts)) { return null; } return new AssumptionInlineInfo(invoke, concrete, takenAssumption); } - private static InlineInfo getExactInlineInfo(Invoke invoke, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod targetMethod) { + private static InlineInfo getExactInlineInfo(Replacements replacements, Invoke invoke, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod targetMethod) { assert !Modifier.isAbstract(targetMethod.getModifiers()); - if (!checkTargetConditions(invoke, targetMethod, optimisticOpts)) { + if (!checkTargetConditions(replacements, invoke, targetMethod, optimisticOpts)) { return null; } return new ExactInlineInfo(invoke, targetMethod); } - private static InlineInfo getTypeCheckedInlineInfo(Invoke invoke, ResolvedJavaMethod caller, ResolvedJavaType holder, ResolvedJavaMethod targetMethod, OptimisticOptimizations optimisticOpts) { + private static InlineInfo getTypeCheckedInlineInfo(Replacements replacements, Invoke invoke, ResolvedJavaMethod caller, ResolvedJavaType holder, ResolvedJavaMethod targetMethod, + OptimisticOptimizations optimisticOpts) { ProfilingInfo profilingInfo = caller.getProfilingInfo(); JavaTypeProfile typeProfile = profilingInfo.getTypeProfile(invoke.bci()); if (typeProfile == null) { @@ -871,7 +903,7 @@ ResolvedJavaType type = ptypes.get(0).getType(); ResolvedJavaMethod concrete = type.resolveMethod(targetMethod); - if (!checkTargetConditions(invoke, concrete, optimisticOpts)) { + if (!checkTargetConditions(replacements, invoke, concrete, optimisticOpts)) { return null; } return new TypeGuardInlineInfo(invoke, concrete, type); @@ -903,7 +935,7 @@ } for (ResolvedJavaMethod concrete : concreteMethods) { - if (!checkTargetConditions(invoke, concrete, optimisticOpts)) { + if (!checkTargetConditions(replacements, invoke, concrete, optimisticOpts)) { return logNotInlinedMethodAndReturnNull(invoke, targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined"); } } @@ -930,11 +962,11 @@ private static PiNode createAnchoredReceiver(StructuredGraph graph, FixedNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) { // to avoid that floating reads on receiver fields float above the type check - return graph.unique(new PiNode(receiver, anchor, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType))); + return graph.unique(new PiNode(receiver, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType), anchor)); } private static boolean checkInvokeConditions(Invoke invoke) { - if (invoke.predecessor() == null || !invoke.node().isAlive()) { + if (invoke.predecessor() == null || !invoke.asNode().isAlive()) { return logNotInlinedMethodAndReturnFalse(invoke, "the invoke is dead code"); } else if (!(invoke.callTarget() instanceof MethodCallTargetNode)) { return logNotInlinedMethodAndReturnFalse(invoke, "the invoke has already been lowered, or has been created as a low-level node"); @@ -951,10 +983,10 @@ } } - private static boolean checkTargetConditions(Invoke invoke, ResolvedJavaMethod method, OptimisticOptimizations optimisticOpts) { + private static boolean checkTargetConditions(Replacements replacements, Invoke invoke, ResolvedJavaMethod method, OptimisticOptimizations optimisticOpts) { if (method == null) { return logNotInlinedMethodAndReturnFalse(invoke, method, "the method is not resolved"); - } else if (Modifier.isNative(method.getModifiers()) && (!GraalOptions.Intrinsify || !InliningUtil.canIntrinsify(method))) { + } else if (Modifier.isNative(method.getModifiers()) && (!GraalOptions.Intrinsify || !InliningUtil.canIntrinsify(replacements, method))) { return logNotInlinedMethodAndReturnFalse(invoke, method, "it is a non-intrinsic native method"); } else if (Modifier.isAbstract(method.getModifiers())) { return logNotInlinedMethodAndReturnFalse(invoke, method, "it is an abstract method"); @@ -1016,7 +1048,7 @@ */ public static Map inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) { NodeInputList parameters = invoke.callTarget().arguments(); - StructuredGraph graph = (StructuredGraph) invoke.node().graph(); + StructuredGraph graph = (StructuredGraph) invoke.asNode().graph(); FrameState stateAfter = invoke.stateAfter(); assert stateAfter.isAlive(); @@ -1044,17 +1076,17 @@ } } // ensure proper anchoring of things that were anchored to the StartNode - replacements.put(entryPointNode, BeginNode.prevBegin(invoke.node())); + replacements.put(entryPointNode, BeginNode.prevBegin(invoke.asNode())); - assert invoke.node().successors().first() != null : invoke; - assert invoke.node().predecessor() != null; + assert invoke.asNode().successors().first() != null : invoke; + assert invoke.asNode().predecessor() != null; Map duplicates = graph.addDuplicates(nodes, replacements); FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); if (receiverNullCheck) { receiverNullCheck(invoke); } - invoke.node().replaceAtPredecessor(firstCFGNodeDuplicate); + invoke.asNode().replaceAtPredecessor(firstCFGNodeDuplicate); FrameState stateAtExceptionEdge = null; if (invoke instanceof InvokeWithExceptionNode) { @@ -1093,7 +1125,7 @@ } FrameState outerFrameState = null; - double invokeProbability = invoke.node().probability(); + double invokeProbability = invoke.asNode().probability(); int callerLockDepth = stateAfter.nestedLockDepth(); for (Node node : duplicates.values()) { if (GraalOptions.ProbabilityAnalysis) { @@ -1116,7 +1148,7 @@ } if (node instanceof FrameState) { FrameState frameState = (FrameState) node; - assert frameState.bci != FrameState.BEFORE_BCI; + assert frameState.bci != FrameState.BEFORE_BCI : frameState; if (frameState.bci == FrameState.AFTER_BCI) { frameState.replaceAndDelete(stateAfter); } else if (frameState.bci == FrameState.AFTER_EXCEPTION_BCI) { @@ -1131,7 +1163,7 @@ if (frameState.outerFrameState() == null) { assert frameState.bci == FrameState.INVALID_FRAMESTATE_BCI || frameState.method() == inlineGraph.method(); if (outerFrameState == null) { - outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invoke.node().kind()); + outerFrameState = stateAfter.duplicateModified(invoke.bci(), stateAfter.rethrowException(), invoke.asNode().kind()); outerFrameState.setDuringCall(true); } frameState.setOuterFrameState(outerFrameState); @@ -1151,7 +1183,7 @@ } else { returnValue = duplicates.get(returnNode.result()); } - invoke.node().replaceAtUsages(returnValue); + invoke.asNode().replaceAtUsages(returnValue); Node returnDuplicate = duplicates.get(returnNode); returnDuplicate.clearInputs(); Node n = invoke.next(); @@ -1159,8 +1191,8 @@ returnDuplicate.replaceAndDelete(n); } - invoke.node().replaceAtUsages(null); - GraphUtil.killCFG(invoke.node()); + invoke.asNode().replaceAtUsages(null); + GraphUtil.killCFG(invoke.asNode()); return duplicates; } @@ -1171,21 +1203,20 @@ NodeInputList parameters = callTarget.arguments(); ValueNode firstParam = parameters.size() <= 0 ? null : parameters.get(0); if (!callTarget.isStatic() && firstParam.kind() == Kind.Object && !firstParam.objectStamp().nonNull()) { - graph.addBeforeFixed(invoke.node(), + graph.addBeforeFixed(invoke.asNode(), graph.add(new FixedGuardNode(graph.unique(new IsNullNode(firstParam)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true))); } } - public static boolean canIntrinsify(ResolvedJavaMethod target) { - return getIntrinsicGraph(target) != null || getMacroNodeClass(target) != null; + public static boolean canIntrinsify(Replacements replacements, ResolvedJavaMethod target) { + return getIntrinsicGraph(replacements, target) != null || getMacroNodeClass(replacements, target) != null; } - public static StructuredGraph getIntrinsicGraph(ResolvedJavaMethod target) { - return (StructuredGraph) target.getCompilerStorage().get(MethodSubstitution.class); + public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target) { + return replacements.getMethodSubstitution(target); } - public static Class getMacroNodeClass(ResolvedJavaMethod target) { - Object result = target.getCompilerStorage().get(Node.class); - return result == null ? null : ((Class) result).asSubclass(FixedWithNextNode.class); + public static Class getMacroNodeClass(Replacements replacements, ResolvedJavaMethod target) { + return replacements.getMacroSubstitution(target); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -53,7 +53,7 @@ if (canonicalizationRoots.isEmpty()) { break; } - new CanonicalizerPhase(runtime, assumptions, canonicalizationRoots, null).apply(graph); + new CanonicalizerPhase.Instance(runtime, assumptions, canonicalizationRoots, null).apply(graph); canonicalizationRoots.clear(); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -65,6 +65,11 @@ } @Override + public Replacements getReplacements() { + return replacements; + } + + @Override public ValueNode createNullCheckGuard(ValueNode object) { return createGuard(object.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true); } @@ -113,13 +118,15 @@ private final TargetDescription target; private final GraalCodeCacheProvider runtime; + private final Replacements replacements; private final Assumptions assumptions; private boolean deferred; - public LoweringPhase(TargetDescription target, GraalCodeCacheProvider runtime, Assumptions assumptions) { + public LoweringPhase(TargetDescription target, GraalCodeCacheProvider runtime, Replacements replacements, Assumptions assumptions) { this.target = target; this.runtime = runtime; + this.replacements = replacements; this.assumptions = assumptions; } @@ -144,7 +151,7 @@ deferred = false; processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null, schedule, processed); Debug.dump(graph, "Lowering iteration %d", i++); - new CanonicalizerPhase(runtime, assumptions, mark, null).apply(graph); + new CanonicalizerPhase.Instance(runtime, assumptions, mark, null).apply(graph); if (!deferred && !containsLowerable(graph.getNewNodes(mark))) { // No new lowerable nodes - done! diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/PushThroughPiPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/PushThroughPiPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,48 @@ +/* + * 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.graal.phases.common; + +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.*; + +public class PushThroughPiPhase extends Phase { + + public static final DebugMetric PUSHED_NODES = Debug.metric("NodesPushedThroughPi"); + + @Override + protected void run(StructuredGraph graph) { + for (PiNode pi : graph.getNodes(PiNode.class)) { + for (Node n : pi.usages().snapshot()) { + if (n instanceof PiPushable) { + PiPushable pip = (PiPushable) n; + if (pip.push(pi)) { + PUSHED_NODES.add(1); + } + } + } + } + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 @@ -46,7 +46,6 @@ /* * Various metrics on the circumstances in which tail duplication was/wasn't performed. */ - private static final DebugMetric metricDuplicationMonitors = Debug.metric("DuplicationMonitors"); private static final DebugMetric metricDuplicationEnd = Debug.metric("DuplicationEnd"); private static final DebugMetric metricDuplicationEndPerformed = Debug.metric("DuplicationEndPerformed"); private static final DebugMetric metricDuplicationOther = Debug.metric("DuplicationOther"); @@ -128,21 +127,13 @@ } }; - private int tailDuplicationCount; - - public int getTailDuplicationCount() { - return tailDuplicationCount; - } - @Override protected void run(StructuredGraph graph) { // A snapshot is taken here, so that new MergeNode instances aren't considered for tail // duplication. for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) { if (!(merge instanceof LoopBeginNode) && merge.probability() >= GraalOptions.TailDuplicationProbability) { - if (tailDuplicate(merge, DEFAULT_DECISION, null)) { - tailDuplicationCount++; - } + tailDuplicate(merge, DEFAULT_DECISION, null); } } } @@ -168,20 +159,11 @@ assert replacements == null || replacements.size() == merge.forwardEndCount(); FixedNode fixed = merge; int fixedCount = 0; - boolean containsMonitor = false; while (fixed instanceof FixedWithNextNode) { - if (fixed instanceof MonitorEnterNode || fixed instanceof MonitorExitNode) { - containsMonitor = true; - } fixed = ((FixedWithNextNode) fixed).next(); fixedCount++; } - if (containsMonitor) { - // cannot currently be handled - // TODO (ls) re-evaluate this limitation after changes to the lock representation and - // the LIR generator - metricDuplicationMonitors.increment(); - } else if (fixedCount > 1) { + if (fixedCount > 1) { if (fixed instanceof EndNode && !(((EndNode) fixed).merge() instanceof LoopBeginNode)) { metricDuplicationEnd.increment(); if (decision.doTransform(merge, fixedCount)) { @@ -261,7 +243,6 @@ final HashSet duplicatedNodes = buildDuplicatedNodeSet(fixedNodes, stateAfter); mergeAfter.clearEnds(); expandDuplicated(duplicatedNodes, mergeAfter); - retargetDependencies(duplicatedNodes, anchor); List endSnapshot = merge.forwardEnds().snapshot(); List phiSnapshot = merge.phis().snapshot(); @@ -536,29 +517,6 @@ } /** - * Moves all depdendencies that point outside the duplicated area to the supplied value - * anchor node. - * - * @param duplicatedNodes The set of duplicated nodes. - * @param anchor The node that will be the new target for all dependencies that point - * outside the duplicated set of nodes. - */ - private static void retargetDependencies(HashSet duplicatedNodes, ValueAnchorNode anchor) { - for (Node node : duplicatedNodes) { - if (node instanceof ValueNode) { - NodeInputList dependencies = ((ValueNode) node).dependencies(); - for (int i = 0; i < dependencies.size(); i++) { - Node dependency = dependencies.get(i); - if (dependency != null && !duplicatedNodes.contains(dependency)) { - Debug.log("retargeting dependency %s to %s on %s", dependency, anchor, node); - dependencies.set(i, anchor); - } - } - } - } - } - - /** * Checks if the given node has usages that are not within the given set of nodes. * * @param node The node whose usages are checked. diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/BasePhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,77 @@ +/* + * 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. + */ +package com.oracle.graal.phases; + +import com.oracle.graal.debug.*; +import com.oracle.graal.nodes.*; + +/** + * Base class for all compiler phases. Subclasses should be stateless. There will be one global + * instance for each compiler phase that is shared for all compilations. VM-, target- and + * compilation-specific data can be passed with a context object. + */ +public abstract class BasePhase { + + private String name; + private static final DebugMetric metricPhaseRuns = Debug.metric("Runs"); + protected static final DebugMetric METRIC_PROCESSED_NODES = Debug.metric("ProcessedNodes"); + + protected BasePhase() { + this.name = this.getClass().getSimpleName(); + if (name.endsWith("Phase")) { + name = name.substring(0, name.length() - "Phase".length()); + } + } + + protected BasePhase(String name) { + this.name = name; + } + + protected String getDetailedName() { + return getName(); + } + + public final void apply(final StructuredGraph graph, final C context) { + apply(graph, context, true); + } + + public final void apply(final StructuredGraph graph, final C context, final boolean dumpGraph) { + Debug.scope(name, this, new Runnable() { + + public void run() { + BasePhase.this.run(graph, context); + metricPhaseRuns.increment(); + if (dumpGraph) { + Debug.dump(graph, "After phase %s", name); + } + assert graph.verify(); + } + }); + } + + public final String getName() { + return name; + } + + protected abstract void run(StructuredGraph graph, C context); +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Mon Apr 15 08:51:19 2013 +0200 @@ -88,6 +88,9 @@ public static int SlowQueueCutoff = 100000; public static boolean SlowCompileThreads = ____; public static boolean DynamicCompilePriority = ____; + public static String CompileTheWorld = null; + public static int CompileTheWorldStartAt = 1; + public static int CompileTheWorldStopAt = Integer.MAX_VALUE; // graph caching public static boolean CacheGraphs = true; @@ -116,6 +119,7 @@ // Debug settings: public static boolean Debug = true; public static boolean DebugReplacements = ____; + public static boolean BootstrapReplacements = ____; public static boolean PerThreadDebugValues = ____; public static boolean SummarizeDebugValues = ____; public static boolean SummarizePerPhase = ____; @@ -127,7 +131,7 @@ public static String MethodFilter = null; public static boolean DumpOnError = ____; public static boolean GenericDynamicCounters = ____; - public static boolean BenchmarkDynamicCounters = ____; + public static String BenchmarkDynamicCounters = null; // Ideal graph visualizer output settings public static boolean PrintBinaryGraphs = true; @@ -151,6 +155,10 @@ public static boolean ExitVMOnBailout = ____; public static boolean ExitVMOnException = true; + // HotSpot command line options + public static boolean HotSpotPrintCompilation = ____; + public static boolean HotSpotPrintInlining = ____; + // Register allocator debugging public static String RegisterPressure = null; @@ -203,6 +211,8 @@ public static boolean OptEliminatePartiallyRedundantGuards = true; public static boolean OptFilterProfiledTypes = true; public static boolean OptDevirtualizeInvokesOptimistically = true; + public static boolean OptPushThroughPi = true; + // Intrinsification settings public static boolean IntrinsifyObjectClone = ____; @@ -215,6 +225,7 @@ public static boolean IntrinsifyMathMethods = true; public static boolean IntrinsifyAESMethods = true; public static boolean IntrinsifyInstalledCodeMethods = true; + public static boolean IntrinsifyCallSiteTarget = true; /** * Counts the various paths taken through snippets. */ diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/Phase.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/Phase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/Phase.java Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -22,28 +22,18 @@ */ package com.oracle.graal.phases; -import com.oracle.graal.debug.*; import com.oracle.graal.nodes.*; -public abstract class Phase { - - private String name; - private static final DebugMetric metricPhaseRuns = Debug.metric("Runs"); - protected static final DebugMetric METRIC_PROCESSED_NODES = Debug.metric("ProcessedNodes"); +/** + * Base class for compiler phases that don't need a context object. + */ +public abstract class Phase extends BasePhase { protected Phase() { - this.name = this.getClass().getSimpleName(); - if (name.endsWith("Phase")) { - name = name.substring(0, name.length() - "Phase".length()); - } } protected Phase(String name) { - this.name = name; - } - - protected String getDetailedName() { - return getName(); + super(name); } public final void apply(final StructuredGraph graph) { @@ -51,22 +41,13 @@ } public final void apply(final StructuredGraph graph, final boolean dumpGraph) { - Debug.scope(name, this, new Runnable() { - - public void run() { - Phase.this.run(graph); - metricPhaseRuns.increment(); - if (dumpGraph) { - Debug.dump(graph, "After phase %s", name); - } - assert graph.verify(); - } - }); - } - - public final String getName() { - return name; + apply(graph, null, dumpGraph); } protected abstract void run(StructuredGraph graph); + + @Override + protected final void run(StructuredGraph graph, Object context) { + run(graph); + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhaseSuite.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/PhaseSuite.java Mon Apr 15 08:51:19 2013 +0200 @@ -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. + */ +package com.oracle.graal.phases; + +import java.util.*; + +import com.oracle.graal.nodes.*; + +public class PhaseSuite extends BasePhase { + + private final List> phases; + + public PhaseSuite(String name, List> phases) { + super(name); + this.phases = phases; + } + + @Override + protected void run(StructuredGraph graph, C context) { + for (BasePhase phase : phases) { + phase.apply(graph, context); + } + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java Mon Apr 15 08:51:19 2013 +0200 @@ -217,7 +217,7 @@ } protected void invoke(Invoke invoke) { - node(invoke.node()); + node(invoke.asNode()); } protected void finished() { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java Mon Apr 15 08:51:19 2013 +0200 @@ -39,7 +39,7 @@ protected abstract void processBlock(Block block, StateT currentState); - protected abstract StateT merge(MergeNode merge, List states); + protected abstract StateT merge(Block merge, List states); protected abstract StateT cloneState(StateT oldState); @@ -161,12 +161,11 @@ assert current.getPredecessors().size() > 1; MergeNode merge = (MergeNode) current.getBeginNode(); ArrayList mergedStates = new ArrayList<>(merge.forwardEndCount()); - for (int i = 0; i < merge.forwardEndCount(); i++) { - StateT other = states.get(merge.forwardEndAt(i)); - assert other != null; - mergedStates.add(other); + for (Block predecessor : current.getPredecessors()) { + EndNode end = (EndNode) predecessor.getEndNode(); + mergedStates.add(states.get(end)); } - state = closure.merge(merge, mergedStates); + state = closure.merge(current, mergedStates); } assert state != null; } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -39,6 +39,30 @@ public final class SchedulePhase extends Phase { + /** + * Error thrown when a graph cannot be scheduled. + */ + public static class SchedulingError extends Error { + + private static final long serialVersionUID = 1621001069476473145L; + + public SchedulingError() { + super(); + } + + /** + * This constructor creates a {@link SchedulingError} with a message assembled via + * {@link String#format(String, Object...)}. + * + * @param format a {@linkplain Formatter format} string + * @param args parameters to {@link String#format(String, Object...)} + */ + public SchedulingError(String format, Object... args) { + super(String.format(format, args)); + } + + } + public static enum SchedulingStrategy { EARLIEST, LATEST, LATEST_OUT_OF_LOOPS } @@ -91,7 +115,7 @@ } @Override - protected HashSet merge(MergeNode merge, List> states) { + protected HashSet merge(Block merge, List> states) { HashSet state = new HashSet<>(states.get(0)); for (int i = 1; i < states.size(); i++) { state.retainAll(states.get(i)); @@ -169,8 +193,8 @@ /** * Sets {@link ScheduledNode#scheduledNext} on all scheduled nodes in all blocks using the - * scheduling built by @link {@link #run(StructuredGraph)}. This method should thus only be - * called when run has been successfully executed. + * scheduling built by {@link #run(StructuredGraph)}. This method should thus only be called + * when run has been successfully executed. */ public void scheduleGraph() { assert blockToNodesMap != null : "cannot set scheduledNext before run has been executed"; @@ -207,7 +231,9 @@ private void assignBlockToNodes(StructuredGraph graph, SchedulingStrategy strategy) { for (Block block : cfg.getBlocks()) { List nodes = new ArrayList<>(); - assert blockToNodesMap.get(block) == null; + if (blockToNodesMap.get(block) != null) { + throw new SchedulingError(); + } blockToNodesMap.put(block, nodes); for (FixedNode node : block.getNodes()) { nodes.add(node); @@ -234,8 +260,9 @@ } // PhiNodes and FixedNodes should already have been placed in blocks by // ControlFlowGraph.identifyBlocks - assert !(node instanceof PhiNode) : node; - assert !(node instanceof FixedNode) : node; + if (node instanceof PhiNode || node instanceof FixedNode) { + throw new SchedulingError("%s should already have been placed in a block", node); + } Block block; switch (strategy) { @@ -251,8 +278,10 @@ // schedule at the latest position possible in the outermost loop possible Block earliestBlock = earliestBlock(node); block = scheduleOutOfLoops(node, block, earliestBlock); - assert earliestBlock.dominates(block) : "Graph cannot be scheduled : inconsistent for " + node + ", " + node.usages().count() + " usages, (" + earliestBlock + - " needs to dominate " + block + ")"; + if (!earliestBlock.dominates(block)) { + throw new SchedulingError("%s: Graph cannot be scheduled : inconsistent for %s, %d usages, (%s needs to dominate %s)", node.graph(), node, node.usages().count(), + earliestBlock, block); + } } break; default: @@ -271,7 +300,9 @@ private Block latestBlock(ScheduledNode node, SchedulingStrategy strategy) { CommonDominatorBlockClosure cdbc = new CommonDominatorBlockClosure(null); for (Node succ : node.successors().nonNull()) { - assert cfg.getNodeToBlock().get(succ) != null; + if (cfg.getNodeToBlock().get(succ) == null) { + throw new SchedulingError(); + } cdbc.apply(cfg.getNodeToBlock().get(succ)); } ensureScheduledUsages(node, strategy); @@ -281,7 +312,9 @@ List usages = phantomUsages.get(node); if (usages != null) { for (FixedNode usage : usages) { - assert cfg.getNodeToBlock().get(usage) != null; + if (cfg.getNodeToBlock().get(usage) == null) { + throw new SchedulingError(); + } cdbc.apply(cfg.getNodeToBlock().get(usage)); } } @@ -331,7 +364,9 @@ */ BitSet dominators = new BitSet(cfg.getBlocks().length); - assert node.predecessor() == null; + if (node.predecessor() != null) { + throw new SchedulingError(); + } for (Node input : node.inputs().nonNull()) { assert input instanceof ValueNode; Block inputEarliest; @@ -356,7 +391,9 @@ } private static Block scheduleOutOfLoops(Node n, Block latestBlock, Block earliest) { - assert latestBlock != null : "no latest : " + n; + if (latestBlock == null) { + throw new SchedulingError("no latest : %s", n); + } Block cur = latestBlock; Block result = latestBlock; while (cur.getLoop() != null && cur != earliest && cur.getDominator() != null) { @@ -378,7 +415,9 @@ * @param closure the closure that will be called for each block */ private void blocksForUsage(ScheduledNode node, Node usage, BlockClosure closure, SchedulingStrategy strategy) { - assert !(node instanceof PhiNode); + if (node instanceof PhiNode) { + throw new SchedulingError(node.toString()); + } if (usage instanceof PhiNode) { // An input to a PhiNode is used at the end of the predecessor block that corresponds to @@ -388,7 +427,9 @@ PhiNode phi = (PhiNode) usage; MergeNode merge = phi.merge(); Block mergeBlock = cfg.getNodeToBlock().get(merge); - assert mergeBlock != null : "no block for merge " + merge.toString(Verbosity.Id); + if (mergeBlock == null) { + throw new SchedulingError("no block for merge %s", merge.toString(Verbosity.Id)); + } for (int i = 0; i < phi.valueCount(); ++i) { if (phi.valueAt(i) == node) { if (mergeBlock.getPredecessorCount() <= i) { @@ -412,7 +453,9 @@ blocksForUsage(node, unscheduledUsage, closure, strategy); } else if (unscheduledUsage instanceof MergeNode) { // Only FrameStates can be connected to MergeNodes. - assert usage instanceof FrameState; + if (!(usage instanceof FrameState)) { + throw new SchedulingError(usage.toString()); + } // If a FrameState belongs to a MergeNode then it's inputs will be placed at the // common dominator of all EndNodes. for (Node pred : unscheduledUsage.cfgPredecessors()) { @@ -420,8 +463,12 @@ } } else { // For the time being, only FrameStates can be connected to StateSplits. - assert usage instanceof FrameState; - assert unscheduledUsage instanceof StateSplit; + if (!(usage instanceof FrameState)) { + throw new SchedulingError(usage.toString()); + } + if (!(unscheduledUsage instanceof StateSplit || unscheduledUsage instanceof DeoptimizingNode)) { + throw new SchedulingError(unscheduledUsage.toString()); + } // Otherwise: Put the input into the same block as the usage. assignBlockToNode((ScheduledNode) unscheduledUsage, strategy); closure.apply(cfg.getNodeToBlock().get(unscheduledUsage)); @@ -459,8 +506,12 @@ } private void sortNodesWithinBlock(Block b, NodeBitMap visited, SchedulingStrategy strategy) { - assert !visited.isMarked(b.getBeginNode()) && cfg.blockFor(b.getBeginNode()) == b; - assert !visited.isMarked(b.getEndNode()) && cfg.blockFor(b.getEndNode()) == b; + if (visited.isMarked(b.getBeginNode()) || cfg.blockFor(b.getBeginNode()) != b) { + throw new SchedulingError(); + } + if (visited.isMarked(b.getEndNode()) || cfg.blockFor(b.getEndNode()) != b) { + throw new SchedulingError(); + } List sortedInstructions; switch (strategy) { @@ -520,7 +571,9 @@ private void addUnscheduledToLatestSorting(Block b, VirtualState state, List sortedInstructions, NodeBitMap visited) { if (state != null) { // UnscheduledNodes should never be marked as visited. - assert !visited.isMarked(state); + if (visited.isMarked(state)) { + throw new SchedulingError(); + } for (Node input : state.inputs()) { if (input instanceof VirtualState) { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/HighTierContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/HighTierContext.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,33 @@ +/* + * 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.graal.phases.tiers; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; + +public class HighTierContext extends PhaseContext { + + public HighTierContext(MetaAccessProvider runtime, Assumptions assumptions) { + super(runtime, assumptions); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/PhaseContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/PhaseContext.java Mon Apr 15 08:51:19 2013 +0200 @@ -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. + */ +package com.oracle.graal.phases.tiers; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; + +public class PhaseContext { + + private final MetaAccessProvider runtime; + private final Assumptions assumptions; + + public PhaseContext(MetaAccessProvider runtime, Assumptions assumptions) { + this.runtime = runtime; + this.assumptions = assumptions; + } + + public MetaAccessProvider getRuntime() { + return runtime; + } + + public Assumptions getAssumptions() { + return assumptions; + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/HexCodeFile.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/HexCodeFile.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/HexCodeFile.java Mon Apr 15 08:51:19 2013 +0200 @@ -288,7 +288,9 @@ } void warning(int offset, String message) { + // CheckStyle: stop system..print check System.err.println("Warning: " + errorMessage(offset, message)); + // CheckStyle: resume system..print check } String errorMessage(int offset, String message) { @@ -316,8 +318,10 @@ int lineStart = input.lastIndexOf(HexCodeFile.NEW_LINE, index) + 1; String l = input.substring(lineStart, lineStart + 10); + // CheckStyle: stop system..print check System.out.println("YYY" + input.substring(index, index + 10) + "..."); System.out.println("XXX" + l + "..."); + // CheckStyle: resume system..print check int pos = input.indexOf(HexCodeFile.NEW_LINE, 0); int line = 1; diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java --- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertSnippets.java Mon Apr 15 08:51:19 2013 +0200 @@ -23,18 +23,20 @@ package com.oracle.graal.replacements.amd64; import static com.oracle.graal.replacements.SnippetTemplate.*; -import static com.oracle.graal.replacements.SnippetTemplate.Arguments.*; import static com.oracle.graal.replacements.nodes.BranchProbabilityNode.*; +import java.util.*; + import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.calc.ConvertNode.Op; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.replacements.*; -import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; /** * Snippets used for conversion operations on AMD64 where the AMD64 instruction used does not match @@ -54,7 +56,7 @@ * @param result the result produced by the CVTTSS2SI instruction */ @Snippet - public static int f2i(@Parameter("input") float input, @Parameter("result") int result) { + public static int f2i(float input, int result) { if (result == Integer.MIN_VALUE) { probability(NOT_FREQUENT_PROBABILITY); if (Float.isNaN(input)) { @@ -80,7 +82,7 @@ * @param result the result produced by the CVTTSS2SI instruction */ @Snippet - public static long f2l(@Parameter("input") float input, @Parameter("result") long result) { + public static long f2l(float input, long result) { if (result == Long.MIN_VALUE) { probability(NOT_FREQUENT_PROBABILITY); if (Float.isNaN(input)) { @@ -106,7 +108,7 @@ * @param result the result produced by the CVTTSS2SI instruction */ @Snippet - public static int d2i(@Parameter("input") double input, @Parameter("result") int result) { + public static int d2i(double input, int result) { if (result == Integer.MIN_VALUE) { probability(NOT_FREQUENT_PROBABILITY); if (Double.isNaN(input)) { @@ -132,7 +134,7 @@ * @param result the result produced by the CVTTSS2SI instruction */ @Snippet - public static long d2l(@Parameter("input") double input, @Parameter("result") long result) { + public static long d2l(double input, long result) { if (result == Long.MIN_VALUE) { probability(NOT_FREQUENT_PROBABILITY); if (Double.isNaN(input)) { @@ -146,34 +148,26 @@ return result; } - public static class Templates extends AbstractTemplates { + public static class Templates extends AbstractTemplates { - private final ResolvedJavaMethod f2i; - private final ResolvedJavaMethod f2l; - private final ResolvedJavaMethod d2i; - private final ResolvedJavaMethod d2l; + private final EnumMap snippets; - public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) { - super(runtime, assumptions, target, AMD64ConvertSnippets.class); - f2i = snippet("f2i", float.class, int.class); - f2l = snippet("f2l", float.class, long.class); - d2i = snippet("d2i", double.class, int.class); - d2l = snippet("d2l", double.class, long.class); + public Templates(CodeCacheProvider runtime, Replacements replacements, TargetDescription target) { + super(runtime, replacements, target); + + snippets = new EnumMap<>(Op.class); + snippets.put(Op.F2I, snippet(AMD64ConvertSnippets.class, "f2i")); + snippets.put(Op.F2L, snippet(AMD64ConvertSnippets.class, "f2l")); + snippets.put(Op.D2I, snippet(AMD64ConvertSnippets.class, "d2i")); + snippets.put(Op.D2L, snippet(AMD64ConvertSnippets.class, "d2l")); } public void lower(ConvertNode convert, LoweringTool tool) { - if (convert.opcode == Op.F2I) { - lower0(convert, tool, f2i); - } else if (convert.opcode == Op.F2L) { - lower0(convert, tool, f2l); - } else if (convert.opcode == Op.D2I) { - lower0(convert, tool, d2i); - } else if (convert.opcode == Op.D2L) { - lower0(convert, tool, d2l); + SnippetInfo key = snippets.get(convert.opcode); + if (key == null) { + return; } - } - private void lower0(ConvertNode convert, LoweringTool tool, ResolvedJavaMethod snippet) { StructuredGraph graph = (StructuredGraph) convert.graph(); // Insert a unique placeholder node in place of the Convert node so that the @@ -183,11 +177,13 @@ LocalNode replacee = graph.add(new LocalNode(Integer.MAX_VALUE, convert.stamp())); convert.replaceAtUsages(replacee); - Key key = new Key(snippet); - Arguments arguments = arguments("input", convert.value()).add("result", convert); - SnippetTemplate template = cache.get(key, assumptions); - Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.opcode, graph, convert, template, arguments); - template.instantiate(runtime, replacee, DEFAULT_REPLACER, tool, arguments); + Arguments args = new Arguments(key); + args.add("input", convert.value()); + args.add("result", convert); + + SnippetTemplate template = template(args); + Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.opcode, graph, convert, template, args); + template.instantiate(runtime, replacee, DEFAULT_REPLACER, tool, args); } } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/CheckCastTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/CheckCastTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,214 +0,0 @@ -/* - * Copyright (c) 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. - */ -package com.oracle.graal.replacements; - - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; - -/** - * Tests the implementation of checkcast, allowing profiling information to be manually specified. - */ -public class CheckCastTest extends TypeCheckTest { - - @Override - protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) { - CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first(); - if (ccn != null) { - CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.type(), ccn.object(), profile)); - graph.replaceFixedWithFixed(ccn, ccnNew); - } - } - - @LongTest - public void test1() { - test("asNumber", profile(), 111); - test("asNumber", profile(Integer.class), 111); - test("asNumber", profile(Long.class, Short.class), 111); - test("asNumberExt", profile(), 111); - test("asNumberExt", profile(Integer.class), 111); - test("asNumberExt", profile(Long.class, Short.class), 111); - } - - @LongTest - public void test2() { - test("asString", profile(), "111"); - test("asString", profile(String.class), "111"); - test("asString", profile(String.class), "111"); - - final String nullString = null; - test("asString", profile(), nullString); - test("asString", profile(String.class), nullString); - test("asString", profile(String.class), nullString); - - test("asStringExt", profile(), "111"); - test("asStringExt", profile(String.class), "111"); - test("asStringExt", profile(String.class), "111"); - } - - @LongTest - public void test3() { - test("asNumber", profile(), "111"); - } - - @LongTest - public void test4() { - test("asString", profile(String.class), 111); - } - - @LongTest - public void test5() { - test("asNumberExt", profile(), "111"); - } - - @LongTest - public void test6() { - test("asStringExt", profile(String.class), 111); - } - - @LongTest - public void test7() { - Throwable throwable = new Exception(); - test("asThrowable", profile(), throwable); - test("asThrowable", profile(Throwable.class), throwable); - test("asThrowable", profile(Exception.class, Error.class), throwable); - } - - @LongTest - public void test8() { - test("arrayStore", new Object[100], "111"); - } - - @LongTest - public void test8_1() { - test("arrayFill", new Object[100], "111"); - } - - public static Number asNumber(Object o) { - return (Number) o; - } - - public static String asString(Object o) { - return (String) o; - } - - public static Throwable asThrowable(Object o) { - return (Throwable) o; - } - - public static ValueNode asValueNode(Object o) { - return (ValueNode) o; - } - - public static Number asNumberExt(Object o) { - Number n = (Number) o; - return n.intValue() + 10; - } - - public static String asStringExt(Object o) { - String s = (String) o; - return "#" + s; - } - - public static Object[] arrayStore(Object[] arr, Object value) { - arr[15] = value; - return arr; - } - - public static Object[] arrayFill(Object[] arr, Object value) { - for (int i = 0; i < arr.length; i++) { - arr[i] = value; - } - return arr; - } - - static class Depth1 implements Cloneable { - } - - static class Depth2 extends Depth1 { - } - - static class Depth3 extends Depth2 { - } - - static class Depth4 extends Depth3 { - } - - static class Depth5 extends Depth4 { - } - - static class Depth6 extends Depth5 { - } - - static class Depth7 extends Depth6 { - } - - static class Depth8 extends Depth7 { - } - - static class Depth9 extends Depth8 { - } - - static class Depth10 extends Depth9 { - } - - static class Depth11 extends Depth10 { - } - - static class Depth12 extends Depth11 { - } - - static class Depth13 extends Depth12 { - } - - static class Depth14 extends Depth12 { - } - - public static Depth12 asDepth12(Object o) { - return (Depth12) o; - } - - public static Depth12[][] asDepth12Arr(Object o) { - return (Depth12[][]) o; - } - - public static Cloneable asCloneable(Object o) { - return (Cloneable) o; - } - - @LongTest - public void test9() { - Object o = new Depth13(); - test("asDepth12", profile(), o); - test("asDepth12", profile(Depth13.class), o); - test("asDepth12", profile(Depth13.class, Depth14.class), o); - } - - @LongTest - public void test10() { - Object o = new Depth13[3][]; - test("asDepth12Arr", o); - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/InstanceOfDynamicTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/InstanceOfDynamicTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * Copyright (c) 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. - */ -package com.oracle.graal.replacements; - -import com.oracle.graal.test.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.nodes.java.*; - -/** - * Tests for {@link InstanceOfDynamicNode}. - */ -public class InstanceOfDynamicTest extends GraalCompilerTest { - - public static int id(int value) { - return value; - } - - @LongTest - public void test100() { - final Object nul = null; - test("isStringDynamic", nul); - test("isStringDynamic", "object"); - test("isStringDynamic", Object.class); - } - - @LongTest - public void test101() { - final Object nul = null; - test("isStringIntDynamic", nul); - test("isStringIntDynamic", "object"); - test("isStringIntDynamic", Object.class); - } - - @LongTest - public void test103() { - test("isInstanceDynamic", String.class, null); - test("isInstanceDynamic", String.class, "object"); - test("isInstanceDynamic", String.class, Object.class); - test("isInstanceDynamic", int.class, null); - test("isInstanceDynamic", int.class, "Object"); - test("isInstanceDynamic", int.class, Object.class); - } - - @LongTest - public void test104() { - test("isInstanceIntDynamic", String.class, null); - test("isInstanceIntDynamic", String.class, "object"); - test("isInstanceIntDynamic", String.class, Object.class); - test("isInstanceIntDynamic", int.class, null); - test("isInstanceIntDynamic", int.class, "Object"); - test("isInstanceIntDynamic", int.class, Object.class); - } - - public static boolean isStringDynamic(Object o) { - return String.class.isInstance(o); - } - - public static int isStringIntDynamic(Object o) { - if (String.class.isInstance(o)) { - return o.toString().length(); - } - return o.getClass().getName().length(); - } - - public static boolean isInstanceDynamic(Class c, Object o) { - return c.isInstance(o); - } - - public static int isInstanceIntDynamic(Class c, Object o) { - if (c.isInstance(o)) { - return o.toString().length(); - } - return o.getClass().getName().length(); - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/InstanceOfTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/InstanceOfTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,398 +0,0 @@ -/* - * Copyright (c) 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. - */ -package com.oracle.graal.replacements; - -import java.util.*; - - -import com.oracle.graal.api.code.CompilationResult.Call; -import com.oracle.graal.api.code.CompilationResult.Mark; -import com.oracle.graal.api.code.CompilationResult.Site; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.replacements.CheckCastTest.*; - -/** - * Tests the implementation of instanceof, allowing profiling information to be manually specified. - */ -public class InstanceOfTest extends TypeCheckTest { - - @Override - protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) { - phasePlan.disablePhase(InliningPhase.class); - } - - @Override - protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) { - InstanceOfNode ion = graph.getNodes().filter(InstanceOfNode.class).first(); - if (ion != null) { - InstanceOfNode ionNew = graph.add(new InstanceOfNode(ion.type(), ion.object(), profile)); - graph.replaceFloating(ion, ionNew); - } - } - - @LongTest - public void test1() { - test("isString", profile(), "object"); - test("isString", profile(String.class), "object"); - - test("isString", profile(), Object.class); - test("isString", profile(String.class), Object.class); - } - - @LongTest - public void test2() { - test("isStringInt", profile(), "object"); - test("isStringInt", profile(String.class), "object"); - - test("isStringInt", profile(), Object.class); - test("isStringInt", profile(String.class), Object.class); - } - - @LongTest - public void test2_1() { - test("isStringIntComplex", profile(), "object"); - test("isStringIntComplex", profile(String.class), "object"); - - test("isStringIntComplex", profile(), Object.class); - test("isStringIntComplex", profile(String.class), Object.class); - } - - @LongTest - public void test3() { - Throwable throwable = new Exception(); - test("isThrowable", profile(), throwable); - test("isThrowable", profile(Throwable.class), throwable); - test("isThrowable", profile(Exception.class, Error.class), throwable); - - test("isThrowable", profile(), Object.class); - test("isThrowable", profile(Throwable.class), Object.class); - test("isThrowable", profile(Exception.class, Error.class), Object.class); - } - - @LongTest - public void test3_1() { - onlyFirstIsException(new Exception(), new Error()); - test("onlyFirstIsException", profile(), new Exception(), new Error()); - test("onlyFirstIsException", profile(), new Error(), new Exception()); - test("onlyFirstIsException", profile(), new Exception(), new Exception()); - test("onlyFirstIsException", profile(), new Error(), new Error()); - } - - @LongTest - public void test4() { - Throwable throwable = new Exception(); - test("isThrowableInt", profile(), throwable); - test("isThrowableInt", profile(Throwable.class), throwable); - test("isThrowableInt", profile(Exception.class, Error.class), throwable); - - test("isThrowableInt", profile(), Object.class); - test("isThrowableInt", profile(Throwable.class), Object.class); - test("isThrowableInt", profile(Exception.class, Error.class), Object.class); - } - - @LongTest - public void test5() { - Map map = new HashMap<>(); - test("isMap", profile(), map); - test("isMap", profile(HashMap.class), map); - test("isMap", profile(TreeMap.class, HashMap.class), map); - - test("isMap", profile(), Object.class); - test("isMap", profile(HashMap.class), Object.class); - test("isMap", profile(TreeMap.class, HashMap.class), Object.class); - } - - @LongTest - public void test6() { - Map map = new HashMap<>(); - test("isMapInt", profile(), map); - test("isMapInt", profile(HashMap.class), map); - test("isMapInt", profile(TreeMap.class, HashMap.class), map); - - test("isMapInt", profile(), Object.class); - test("isMapInt", profile(HashMap.class), Object.class); - test("isMapInt", profile(TreeMap.class, HashMap.class), Object.class); - } - - @LongTest - public void test7() { - Object o = new Depth13(); - test("isDepth12", profile(), o); - test("isDepth12", profile(Depth13.class), o); - test("isDepth12", profile(Depth13.class, Depth14.class), o); - - o = "not a depth"; - test("isDepth12", profile(), o); - test("isDepth12", profile(Depth13.class), o); - test("isDepth12", profile(Depth13.class, Depth14.class), o); - } - - @LongTest - public void test8() { - Object o = new Depth13(); - test("isDepth12Int", profile(), o); - test("isDepth12Int", profile(Depth13.class), o); - test("isDepth12Int", profile(Depth13.class, Depth14.class), o); - - o = "not a depth"; - test("isDepth12Int", profile(), o); - test("isDepth12Int", profile(Depth13.class), o); - test("isDepth12Int", profile(Depth13.class, Depth14.class), o); - } - - public static boolean isString(Object o) { - return o instanceof String; - } - - public static int isStringInt(Object o) { - if (o instanceof String) { - return id(1); - } - return id(0); - } - - public static int isStringIntComplex(Object o) { - if (o instanceof String || o instanceof Integer) { - return id(o instanceof String ? 1 : 0); - } - return id(0); - } - - public static int id(int value) { - return value; - } - - public static boolean isThrowable(Object o) { - return ((Throwable) o) instanceof Exception; - } - - public static int onlyFirstIsException(Throwable t1, Throwable t2) { - if (t1 instanceof Exception ^ t2 instanceof Exception) { - return t1 instanceof Exception ? 1 : -1; - } - return -1; - } - - public static int isThrowableInt(Object o) { - int result = o instanceof Throwable ? 4 : 5; - if (o instanceof Throwable) { - return id(4); - } - return result; - } - - public static boolean isMap(Object o) { - return o instanceof Map; - } - - public static int isMapInt(Object o) { - if (o instanceof Map) { - return id(1); - } - return id(0); - } - - public static boolean isDepth12(Object o) { - return o instanceof Depth12; - } - - public static int isDepth12Int(Object o) { - if (o instanceof Depth12) { - return id(0); - } - return id(0); - } - - abstract static class MySite { - - final int offset; - - MySite(int offset) { - this.offset = offset; - } - } - - static class MyMark extends MySite { - - MyMark(int offset) { - super(offset); - } - } - - abstract static class MySafepoint extends MySite { - - MySafepoint(int offset) { - super(offset); - } - } - - static class MyCall extends MySafepoint { - - MyCall(int offset) { - super(offset); - } - } - - @LongTest - public void test9() { - MyCall callAt63 = new MyCall(63); - MyMark markAt63 = new MyMark(63); - test("compareMySites", callAt63, callAt63); - test("compareMySites", callAt63, markAt63); - test("compareMySites", markAt63, callAt63); - test("compareMySites", markAt63, markAt63); - } - - public static int compareMySites(MySite s1, MySite s2) { - if (s1.offset == s2.offset && (s1 instanceof MyMark ^ s2 instanceof MyMark)) { - return s1 instanceof MyMark ? -1 : 1; - } - return s1.offset - s2.offset; - } - - @LongTest - public void test10() { - Mark[] noMarks = {}; - Call callAt63 = new Call(null, 63, 5, true, null); - Mark markAt63 = new Mark(63, "1", noMarks); - test("compareSites", callAt63, callAt63); - test("compareSites", callAt63, markAt63); - test("compareSites", markAt63, callAt63); - test("compareSites", markAt63, markAt63); - } - - public static int compareSites(Site s1, Site s2) { - if (s1.pcOffset == s2.pcOffset && (s1 instanceof Mark ^ s2 instanceof Mark)) { - return s1 instanceof Mark ? -1 : 1; - } - return s1.pcOffset - s2.pcOffset; - } - - /** - * This test exists to show the kind of pattern that is be optimizable by - * {@code removeIntermediateMaterialization()} in {@link IfNode}. - *

- * The test exists in this source file as the transformation was originally motivated by the - * need to remove use of special JumpNodes in the {@code InstanceOfSnippets}. - */ - @LongTest - public void test_removeIntermediateMaterialization() { - List list = Arrays.asList("1", "2", "3", "4"); - test("removeIntermediateMaterialization", profile(), list, "2", "yes", "no"); - test("removeIntermediateMaterialization", profile(), list, null, "yes", "no"); - test("removeIntermediateMaterialization", profile(), null, "2", "yes", "no"); - } - - public static String removeIntermediateMaterialization(List list, Object e, String a, String b) { - boolean test; - if (list == null || e == null) { - test = false; - } else { - test = false; - for (Object i : list) { - if (i.equals(e)) { - test = true; - break; - } - } - } - if (test) { - return a; - } - return b; - } - - abstract static class A { - } - - static class B extends A { - } - - static class C extends B { - } - - abstract static class D extends C { - } - - public static boolean isArrayOfA(Object o) { - return o instanceof A[]; - } - - public static boolean isArrayOfB(Object o) { - return o instanceof B[]; - } - - public static boolean isArrayOfC(Object o) { - return o instanceof C[]; - } - - public static boolean isArrayOfD(Object o) { - return o instanceof D[]; - } - - @LongTest - public void testArray() { - Object aArray = new A[10]; - test("isArrayOfA", aArray); - - Object bArray = new B[10]; - test("isArrayOfA", aArray); - test("isArrayOfA", bArray); - test("isArrayOfB", aArray); - test("isArrayOfB", bArray); - - Object cArray = new C[10]; - test("isArrayOfA", aArray); - test("isArrayOfA", bArray); - test("isArrayOfA", cArray); - test("isArrayOfB", aArray); - test("isArrayOfB", bArray); - test("isArrayOfB", cArray); - test("isArrayOfC", aArray); - test("isArrayOfC", bArray); - test("isArrayOfC", cArray); - - Object dArray = new D[10]; - test("isArrayOfA", aArray); - test("isArrayOfA", bArray); - test("isArrayOfA", cArray); - test("isArrayOfA", dArray); - test("isArrayOfB", aArray); - test("isArrayOfB", bArray); - test("isArrayOfB", cArray); - test("isArrayOfB", dArray); - test("isArrayOfC", aArray); - test("isArrayOfC", bArray); - test("isArrayOfC", cArray); - test("isArrayOfC", dArray); - test("isArrayOfD", aArray); - test("isArrayOfD", bArray); - test("isArrayOfD", cArray); - test("isArrayOfD", dArray); - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/InvokeTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/InvokeTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - * Copyright (c) 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. - */ -package com.oracle.graal.replacements; - -import org.junit.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; - -/** - * Tests the implementation of the snippets for lowering the INVOKE* instructions. - */ -public class InvokeTest extends GraalCompilerTest { - - @Override - protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) { - phasePlan.disablePhase(InliningPhase.class); - } - - public interface I { - - String virtualMethod(String s); - } - - public static class A implements I { - - final String name = "A"; - - public String virtualMethod(String s) { - return name + s; - } - } - - @SuppressWarnings("static-method") - private String privateMethod(String s) { - return s; - } - - @Test - public void test1() { - test("invokestatic", "a string"); - test("invokespecialConstructor", "a string"); - test("invokespecial", this, "a string"); - test("invokevirtual", new A(), "a string"); - test("invokevirtual2", new A(), "a string"); - test("invokeinterface", new A(), "a string"); - Object[] args = {null}; - test("invokestatic", args); - test("invokespecialConstructor", args); - test("invokespecial", null, null); - test("invokevirtual", null, null); - test("invokevirtual2", null, null); - test("invokeinterface", null, null); - } - - public static String invokestatic(String s) { - return staticMethod(s); - } - - public static String staticMethod(String s) { - return s; - } - - public static String invokespecialConstructor(String s) { - return new A().virtualMethod(s); - } - - public static String invokespecial(InvokeTest a, String s) { - return a.privateMethod(s); - } - - public static String invokevirtual(A a, String s) { - return a.virtualMethod(s); - } - - public static String invokevirtual2(A a, String s) { - a.virtualMethod(s); - return a.virtualMethod(s); - } - - public static String invokeinterface(I i, String s) { - return i.virtualMethod(s); - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/MethodSubstitutionTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/MethodSubstitutionTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * 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. - */ -package com.oracle.graal.replacements; - -import static org.junit.Assert.*; - -import java.util.concurrent.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.replacements.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; - -/** - * Tests if {@link MethodSubstitution}s are inlined correctly. Most test cases only assert that - * there are no remaining invocations in the graph. This is sufficient if the method that is being - * substituted is a native method. For Java methods, additional checks are necessary. - */ -public abstract class MethodSubstitutionTest extends GraalCompilerTest { - - protected StructuredGraph test(final String snippet) { - return Debug.scope("MethodSubstitutionTest", runtime.lookupJavaMethod(getMethod(snippet)), new Callable() { - - @Override - public StructuredGraph call() { - StructuredGraph graph = parse(snippet); - PhasePlan phasePlan = getDefaultPhasePlan(); - Assumptions assumptions = new Assumptions(true); - new ComputeProbabilityPhase().apply(graph); - Debug.dump(graph, "Graph"); - new InliningPhase(runtime(), null, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); - Debug.dump(graph, "Graph"); - new CanonicalizerPhase(runtime(), assumptions).apply(graph); - new DeadCodeEliminationPhase().apply(graph); - - assertNotInGraph(graph, Invoke.class); - return graph; - } - }); - } - - protected static StructuredGraph assertNotInGraph(StructuredGraph graph, Class clazz) { - for (Node node : graph.getNodes()) { - if (clazz.isInstance(node)) { - fail(node.toString()); - } - } - return graph; - } - - protected static StructuredGraph assertInGraph(StructuredGraph graph, Class clazz) { - for (Node node : graph.getNodes()) { - if (clazz.isInstance(node)) { - return graph; - } - } - fail("Graph does not contain a node of class " + clazz.getName()); - return graph; - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/MonitorTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/MonitorTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,209 +0,0 @@ -/* - * 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. - */ -package com.oracle.graal.replacements; - -import org.junit.*; - -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.virtual.phases.ea.*; - -public class MonitorTest extends GraalCompilerTest { - - @Test - public void test0() { - test("lockObjectSimple", new Object(), new Object()); - test("lockObjectSimple", new Object(), null); - } - - @Test - public void test0_1() { - test("lockThisSimple", "test1", new Object()); - test("lockThisSimple", "test1", null); - } - - @Test - public void test0_2() { - test("lockObjectSimple", null, "test1"); - } - - @Test - public void test1_1() { - test("lockObject", new Object(), "test1", new String[1]); - } - - @Test - public void test1_2() { - test("lockObject", null, "test1_1", new String[1]); - } - - @Test - public void test2() { - test("lockThis", "test2", new String[1]); - } - - /** - * Tests monitor operations on {@link PartialEscapeAnalysisPhase virtual objects}. - */ - @Test - public void test3() { - test("lockLocalObject", "test3", new String[1]); - } - - /** - * Tests recursive locking of objects which should be biasable. - */ - @Test - public void test4() { - Chars src = new Chars("1234567890".toCharArray()); - Chars dst = new Chars(src.data.length); - test("copyObj", src, dst, 100); - } - - /** - * Tests recursive locking of objects which do not appear to be biasable. - */ - @Test - public void test5() { - char[] src = "1234567890".toCharArray(); - char[] dst = new char[src.length]; - test("copyArr", src, dst, 100); - } - - /** - * Extends {@link #test4()} with contention. - */ - @Test - public void test6() { - Chars src = new Chars("1234567890".toCharArray()); - Chars dst = new Chars(src.data.length); - int n = Runtime.getRuntime().availableProcessors(); - testN(n, "copyObj", src, dst, 100); - } - - /** - * Extends {@link #test5()} with contention. - */ - @Test - public void test7() { - char[] src = "1234567890".toCharArray(); - char[] dst = new char[src.length]; - int n = Runtime.getRuntime().availableProcessors(); - testN(n, "copyArr", src, dst, 100); - } - - private static String setAndGet(String[] box, String value) { - synchronized (box) { - box[0] = null; - } - - // Do a GC while a object is locked (by the caller) - System.gc(); - - synchronized (box) { - box[0] = value; - } - return box[0]; - } - - public static Object lockObjectSimple(Object o, Object value) { - synchronized (o) { - value.hashCode(); - return value; - } - } - - public String lockThisSimple(String value, Object o) { - synchronized (this) { - synchronized (value) { - o.hashCode(); - return value; - } - } - } - - public static String lockObject(Object o, String value, String[] box) { - synchronized (o) { - return setAndGet(box, value); - } - } - - public String lockThis(String value, String[] box) { - synchronized (this) { - return setAndGet(box, value); - } - } - - public static String lockLocalObject(String value, String[] box) { - Object o = new Object(); - synchronized (o) { - return setAndGet(box, value); - } - } - - static class Chars { - - final char[] data; - - public Chars(int size) { - this.data = new char[size]; - } - - public Chars(char[] data) { - this.data = data; - } - } - - public static String copyObj(Chars src, Chars dst, int n) { - for (int j = 0; j < n; j++) { - for (int i = 0; i < src.data.length; i++) { - synchronized (src) { - synchronized (dst) { - synchronized (src) { - synchronized (dst) { - dst.data[i] = src.data[i]; - } - } - } - } - } - } - return new String(dst.data); - } - - public static String copyArr(char[] src, char[] dst, int n) { - for (int j = 0; j < n; j++) { - for (int i = 0; i < src.length; i++) { - synchronized (src) { - synchronized (dst) { - synchronized (src) { - synchronized (dst) { - dst[i] = src[i]; - } - } - } - } - } - } - return new String(dst); - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/NewArrayTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/NewArrayTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -/* - * Copyright (c) 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. - */ -package com.oracle.graal.replacements; - -import org.junit.*; - -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.test.*; - -/** - * Tests the implementation of {@code [A]NEWARRAY}. - */ -public class NewArrayTest extends GraalCompilerTest { - - @Override - protected void assertEquals(Object expected, Object actual) { - Assert.assertTrue(expected != null); - Assert.assertTrue(actual != null); - super.assertEquals(expected.getClass(), actual.getClass()); - if (expected instanceof int[]) { - Assert.assertArrayEquals((int[]) expected, (int[]) actual); - } else if (expected instanceof byte[]) { - Assert.assertArrayEquals((byte[]) expected, (byte[]) actual); - } else if (expected instanceof char[]) { - Assert.assertArrayEquals((char[]) expected, (char[]) actual); - } else if (expected instanceof short[]) { - Assert.assertArrayEquals((short[]) expected, (short[]) actual); - } else if (expected instanceof float[]) { - Assert.assertArrayEquals((float[]) expected, (float[]) actual, 0.0f); - } else if (expected instanceof long[]) { - Assert.assertArrayEquals((long[]) expected, (long[]) actual); - } else if (expected instanceof double[]) { - Assert.assertArrayEquals((double[]) expected, (double[]) actual, 0.0d); - } else if (expected instanceof Object[]) { - Assert.assertArrayEquals((Object[]) expected, (Object[]) actual); - } else { - Assert.fail("non-array value encountered: " + expected); - } - } - - @LongTest - public void test1() { - for (String type : new String[]{"Byte", "Char", "Short", "Int", "Float", "Long", "Double", "String"}) { - test("new" + type + "Array7"); - test("new" + type + "ArrayMinus7"); - test("new" + type + "Array", 7); - test("new" + type + "Array", -7); - test("new" + type + "Array", Integer.MAX_VALUE); - test("new" + type + "Array", Integer.MIN_VALUE); - } - } - - public static Object newCharArray7() { - return new char[7]; - } - - public static Object newCharArrayMinus7() { - return new char[-7]; - } - - public static Object newCharArray(int length) { - return new char[length]; - } - - public static Object newShortArray7() { - return new short[7]; - } - - public static Object newShortArrayMinus7() { - return new short[-7]; - } - - public static Object newShortArray(int length) { - return new short[length]; - } - - public static Object newFloatArray7() { - return new float[7]; - } - - public static Object newFloatArrayMinus7() { - return new float[-7]; - } - - public static Object newFloatArray(int length) { - return new float[length]; - } - - public static Object newLongArray7() { - return new long[7]; - } - - public static Object newLongArrayMinus7() { - return new long[-7]; - } - - public static Object newLongArray(int length) { - return new long[length]; - } - - public static Object newDoubleArray7() { - return new double[7]; - } - - public static Object newDoubleArrayMinus7() { - return new double[-7]; - } - - public static Object newDoubleArray(int length) { - return new double[length]; - } - - public static Object newIntArray7() { - return new int[7]; - } - - public static Object newIntArrayMinus7() { - return new int[-7]; - } - - public static Object newIntArray(int length) { - return new int[length]; - } - - public static Object newByteArray7() { - return new byte[7]; - } - - public static Object newByteArrayMinus7() { - return new byte[-7]; - } - - public static Object newByteArray(int length) { - return new byte[length]; - } - - public static Object newStringArray7() { - return new String[7]; - } - - public static Object newStringArrayMinus7() { - return new String[-7]; - } - - public static Object newStringArray(int length) { - return new String[length]; - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/NewInstanceTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/NewInstanceTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,249 +0,0 @@ -/* - * Copyright (c) 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. - */ -package com.oracle.graal.replacements; - -import java.util.*; - -import org.junit.*; - -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.test.*; - -/** - * Tests the implementation of {@code NEW}. - */ -public class NewInstanceTest extends GraalCompilerTest { - - @Override - protected void assertEquals(Object expected, Object actual) { - Assert.assertTrue(expected != null); - Assert.assertTrue(actual != null); - super.assertEquals(expected.getClass(), actual.getClass()); - - if (expected instanceof Object[]) { - Assert.assertTrue(actual instanceof Object[]); - Object[] eArr = (Object[]) expected; - Object[] aArr = (Object[]) actual; - Assert.assertTrue(eArr.length == aArr.length); - for (int i = 0; i < eArr.length; i++) { - assertEquals(eArr[i], aArr[i]); - } - } else if (expected.getClass() != Object.class) { - try { - expected.getClass().getDeclaredMethod("equals", Object.class); - super.assertEquals(expected, actual); - } catch (Exception e) { - } - } - } - - @LongTest - public void test1() { - test("newObject"); - } - - @LongTest - public void test2() { - test("newObjectTwice"); - } - - public static Object newObject() { - return new Object(); - } - - @LongTest - public void test3() { - test("newObjectLoop", 100); - } - - @LongTest - public void test4() { - test("newBigObject"); - } - - @LongTest - public void test5() { - test("newSomeObject"); - } - - @LongTest - public void test6() { - test("newEmptyString"); - } - - @LongTest - public void test7() { - test("newString", "value"); - } - - @LongTest - public void test8() { - test("newHashMap", 31); - } - - @LongTest - public void test9() { - test("newRegression", true); - } - - public static Object[] newObjectTwice() { - Object[] res = {new Object(), new Object()}; - return res; - } - - public static Object[] newObjectLoop(int n) { - Object[] res = new Object[n]; - for (int i = 0; i < n; i++) { - res[i] = new Object(); - } - return res; - } - - public static BigObject newBigObject() { - return new BigObject(); - } - - public static SomeObject newSomeObject() { - return new SomeObject(); - } - - public static String newEmptyString() { - return new String(); - } - - public static String newString(String value) { - return new String(value); - } - - public static HashMap newHashMap(int initialCapacity) { - return new HashMap(initialCapacity); - } - - static class SomeObject { - - String name = "o1"; - HashMap map = new HashMap<>(); - - public SomeObject() { - map.put(name, this.getClass()); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof SomeObject) { - SomeObject so = (SomeObject) obj; - return so.name.equals(name) && so.map.equals(map); - } - return false; - } - - @Override - public int hashCode() { - return name.hashCode(); - } - } - - static class BigObject { - - Object f01; - Object f02; - Object f03; - Object f04; - Object f05; - Object f06; - Object f07; - Object f08; - Object f09; - Object f10; - Object f12; - Object f13; - Object f14; - Object f15; - Object f16; - Object f17; - Object f18; - Object f19; - Object f20; - Object f21; - Object f22; - Object f23; - Object f24; - Object f25; - Object f26; - Object f27; - Object f28; - Object f29; - Object f30; - Object f31; - Object f32; - Object f33; - Object f34; - Object f35; - Object f36; - Object f37; - Object f38; - Object f39; - Object f40; - Object f41; - Object f42; - Object f43; - Object f44; - Object f45; - } - - /** - * Tests that an earlier bug does not occur. The issue was that the loading of the TLAB 'top' - * and 'end' values was being GVN'ed from each branch of the 'if' statement. This meant that the - * allocated B object in the true branch overwrote the allocated array. The cause is that - * RegisterNode was a floating node and the reads from it were UnsafeLoads which are also - * floating. The fix was to make RegisterNode a fixed node (which it should have been in the - * first place). - */ - public static Object newRegression(boolean condition) { - Object result; - if (condition) { - Object[] arr = {0, 1, 2, 3, 4, 5}; - result = new B(); - for (int i = 0; i < arr.length; ++i) { - // If the bug exists, the values of arr will now be deadbeef values - // and the virtual dispatch will cause a segfault. This can result in - // either a VM crash or a spurious NullPointerException. - if (arr[i].equals(Integer.valueOf(i))) { - return false; - } - } - } else { - result = new B(); - } - return result; - } - - static class B { - - long f1 = 0xdeadbeefdeadbe01L; - long f2 = 0xdeadbeefdeadbe02L; - long f3 = 0xdeadbeefdeadbe03L; - long f4 = 0xdeadbeefdeadbe04L; - long f5 = 0xdeadbeefdeadbe05L; - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/NewMultiArrayTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/NewMultiArrayTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -/* - * 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. - */ -package com.oracle.graal.replacements; - -import java.lang.reflect.*; -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; - -/** - * Tests the lowering of the MULTIANEWARRAY instruction. - */ -public class NewMultiArrayTest extends GraalCompilerTest { - - private static int rank(ResolvedJavaType type) { - String name = type.getName(); - int dims = 0; - while (dims < name.length() && name.charAt(dims) == '[') { - dims++; - } - return dims; - } - - @Override - protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) { - boolean forceCompile = false; - if (bottomType != null) { - List snapshot = graph.getNodes().filter(NewMultiArrayNode.class).snapshot(); - assert snapshot != null; - assert snapshot.size() == 1; - - NewMultiArrayNode node = snapshot.get(0); - assert rank(arrayType) == dimensions.length; - int rank = dimensions.length; - ValueNode[] dimensionNodes = new ValueNode[rank]; - for (int i = 0; i < rank; i++) { - dimensionNodes[i] = graph.unique(ConstantNode.forInt(dimensions[i], graph)); - } - - NewMultiArrayNode repl = graph.add(new NewMultiArrayNode(arrayType, dimensionNodes)); - graph.replaceFixedWithFixed(node, repl); - forceCompile = true; - } - return super.getCode(method, graph, forceCompile); - } - - @Override - protected Object referenceInvoke(Method method, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { - if (bottomType != null) { - try { - return Array.newInstance(bottomClass, dimensions); - } catch (Exception e) { - throw new InvocationTargetException(e); - } - } - return super.referenceInvoke(method, receiver, args); - } - - ResolvedJavaType arrayType; - ResolvedJavaType bottomType; - Class bottomClass; - int[] dimensions; - - @LongTest - public void test1() { - for (Class clazz : new Class[]{byte.class, char.class, short.class, int.class, float.class, long.class, double.class, String.class}) { - bottomClass = clazz; - bottomType = runtime.lookupJavaType(clazz); - arrayType = bottomType; - for (int rank : new int[]{1, 2, 10, 50, 100, 200, 254, 255}) { - while (rank(arrayType) != rank) { - arrayType = arrayType.getArrayClass(); - } - - dimensions = new int[rank]; - for (int i = 0; i < rank; i++) { - dimensions[i] = 1; - } - - test("newMultiArray"); - } - } - bottomType = null; - arrayType = null; - } - - public static Object newMultiArray() { - // This is merely a template - the NewMultiArrayNode is replaced in getCode() above. - // This also means we need a separate test for correct handling of negative dimensions - // as deoptimization won't do what we want for a graph modified to be different from the - // source bytecode. - return new Object[10][9][8]; - } - - @LongTest - public void test2() { - test("newMultiArrayException"); - } - - public static Object newMultiArrayException() { - return new Object[10][9][-8]; - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/PointerTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/PointerTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,399 +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. - */ -package com.oracle.graal.replacements; - -import java.lang.reflect.*; - -import org.junit.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.runtime.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.replacements.Snippet.*; -import com.oracle.graal.word.*; - -/** - * Tests for the {@link Pointer} read and write operations. - */ -public class PointerTest extends GraalCompilerTest implements Snippets { - - private static final Object ID = new Object(); - private static final Kind[] KINDS = new Kind[]{Kind.Byte, Kind.Char, Kind.Short, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object}; - private final TargetDescription target; - private final ReplacementsInstaller installer; - - public PointerTest() { - target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget(); - installer = new ReplacementsInstaller(runtime, new Assumptions(false), target); - } - - private static final ThreadLocal inliningPolicy = new ThreadLocal<>(); - - @Override - protected StructuredGraph parse(Method m) { - ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); - return installer.makeGraph(resolvedMethod, inliningPolicy.get()); - } - - @Test - public void test_read1() { - for (Kind kind : KINDS) { - assertRead(parse("read" + kind.name() + "1"), kind, false, ID); - } - } - - @Test - public void test_read2() { - for (Kind kind : KINDS) { - assertRead(parse("read" + kind.name() + "2"), kind, true, ID); - } - } - - @Test - public void test_read3() { - for (Kind kind : KINDS) { - assertRead(parse("read" + kind.name() + "3"), kind, false, LocationNode.UNKNOWN_LOCATION); - } - } - - @Test - public void test_write1() { - for (Kind kind : KINDS) { - assertWrite(parse("write" + kind.name() + "1"), kind, false, ID); - } - } - - @Test - public void test_write2() { - for (Kind kind : KINDS) { - assertWrite(parse("write" + kind.name() + "2"), kind, true, ID); - } - } - - @Test - public void test_write3() { - for (Kind kind : KINDS) { - assertWrite(parse("write" + kind.name() + "3"), kind, false, LocationNode.ANY_LOCATION); - } - } - - private void assertRead(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) { - ReadNode read = (ReadNode) graph.start().next(); - Assert.assertEquals(kind.getStackKind(), read.kind()); - - UnsafeCastNode cast = (UnsafeCastNode) read.object(); - Assert.assertEquals(graph.getLocal(0), cast.object()); - Assert.assertEquals(target.wordKind, cast.kind()); - - IndexedLocationNode location = (IndexedLocationNode) read.location(); - Assert.assertEquals(kind, location.getValueKind()); - Assert.assertEquals(locationIdentity, location.locationIdentity()); - Assert.assertEquals(1, location.indexScaling()); - - if (indexConvert) { - ConvertNode convert = (ConvertNode) location.index(); - Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode); - Assert.assertEquals(graph.getLocal(1), convert.value()); - } else { - Assert.assertEquals(graph.getLocal(1), location.index()); - } - - ReturnNode ret = (ReturnNode) read.next(); - Assert.assertEquals(read, ret.result()); - } - - private void assertWrite(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) { - WriteNode write = (WriteNode) graph.start().next(); - Assert.assertEquals(graph.getLocal(2), write.value()); - Assert.assertEquals(Kind.Void, write.kind()); - Assert.assertEquals(FrameState.INVALID_FRAMESTATE_BCI, write.stateAfter().bci); - - UnsafeCastNode cast = (UnsafeCastNode) write.object(); - Assert.assertEquals(graph.getLocal(0), cast.object()); - Assert.assertEquals(target.wordKind, cast.kind()); - - IndexedLocationNode location = (IndexedLocationNode) write.location(); - Assert.assertEquals(kind, location.getValueKind()); - Assert.assertEquals(locationIdentity, location.locationIdentity()); - Assert.assertEquals(1, location.indexScaling()); - - if (indexConvert) { - ConvertNode convert = (ConvertNode) location.index(); - Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode); - Assert.assertEquals(graph.getLocal(1), convert.value()); - } else { - Assert.assertEquals(graph.getLocal(1), location.index()); - } - - AbstractStateSplit stateSplit = (AbstractStateSplit) write.next(); - Assert.assertEquals(FrameState.AFTER_BCI, stateSplit.stateAfter().bci); - - ReturnNode ret = (ReturnNode) stateSplit.next(); - Assert.assertEquals(null, ret.result()); - } - - @Snippet - public static byte readByte1(Object o, int offset) { - return Word.fromObject(o).readByte(offset, ID); - } - - @Snippet - public static byte readByte2(Object o, int offset) { - return Word.fromObject(o).readByte(Word.signed(offset), ID); - } - - @Snippet - public static byte readByte3(Object o, int offset) { - return Word.fromObject(o).readByte(offset); - } - - @Snippet - public static void writeByte1(Object o, int offset, byte value) { - Word.fromObject(o).writeByte(offset, value, ID); - } - - @Snippet - public static void writeByte2(Object o, int offset, byte value) { - Word.fromObject(o).writeByte(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeByte3(Object o, int offset, byte value) { - Word.fromObject(o).writeByte(offset, value); - } - - @Snippet - public static char readChar1(Object o, int offset) { - return Word.fromObject(o).readChar(offset, ID); - } - - @Snippet - public static char readChar2(Object o, int offset) { - return Word.fromObject(o).readChar(Word.signed(offset), ID); - } - - @Snippet - public static char readChar3(Object o, int offset) { - return Word.fromObject(o).readChar(offset); - } - - @Snippet - public static void writeChar1(Object o, int offset, char value) { - Word.fromObject(o).writeChar(offset, value, ID); - } - - @Snippet - public static void writeChar2(Object o, int offset, char value) { - Word.fromObject(o).writeChar(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeChar3(Object o, int offset, char value) { - Word.fromObject(o).writeChar(offset, value); - } - - @Snippet - public static short readShort1(Object o, int offset) { - return Word.fromObject(o).readShort(offset, ID); - } - - @Snippet - public static short readShort2(Object o, int offset) { - return Word.fromObject(o).readShort(Word.signed(offset), ID); - } - - @Snippet - public static short readShort3(Object o, int offset) { - return Word.fromObject(o).readShort(offset); - } - - @Snippet - public static void writeShort1(Object o, int offset, short value) { - Word.fromObject(o).writeShort(offset, value, ID); - } - - @Snippet - public static void writeShort2(Object o, int offset, short value) { - Word.fromObject(o).writeShort(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeShort3(Object o, int offset, short value) { - Word.fromObject(o).writeShort(offset, value); - } - - @Snippet - public static int readInt1(Object o, int offset) { - return Word.fromObject(o).readInt(offset, ID); - } - - @Snippet - public static int readInt2(Object o, int offset) { - return Word.fromObject(o).readInt(Word.signed(offset), ID); - } - - @Snippet - public static int readInt3(Object o, int offset) { - return Word.fromObject(o).readInt(offset); - } - - @Snippet - public static void writeInt1(Object o, int offset, int value) { - Word.fromObject(o).writeInt(offset, value, ID); - } - - @Snippet - public static void writeInt2(Object o, int offset, int value) { - Word.fromObject(o).writeInt(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeInt3(Object o, int offset, int value) { - Word.fromObject(o).writeInt(offset, value); - } - - @Snippet - public static long readLong1(Object o, int offset) { - return Word.fromObject(o).readLong(offset, ID); - } - - @Snippet - public static long readLong2(Object o, int offset) { - return Word.fromObject(o).readLong(Word.signed(offset), ID); - } - - @Snippet - public static long readLong3(Object o, int offset) { - return Word.fromObject(o).readLong(offset); - } - - @Snippet - public static void writeLong1(Object o, int offset, long value) { - Word.fromObject(o).writeLong(offset, value, ID); - } - - @Snippet - public static void writeLong2(Object o, int offset, long value) { - Word.fromObject(o).writeLong(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeLong3(Object o, int offset, long value) { - Word.fromObject(o).writeLong(offset, value); - } - - @Snippet - public static float readFloat1(Object o, int offset) { - return Word.fromObject(o).readFloat(offset, ID); - } - - @Snippet - public static float readFloat2(Object o, int offset) { - return Word.fromObject(o).readFloat(Word.signed(offset), ID); - } - - @Snippet - public static float readFloat3(Object o, int offset) { - return Word.fromObject(o).readFloat(offset); - } - - @Snippet - public static void writeFloat1(Object o, int offset, float value) { - Word.fromObject(o).writeFloat(offset, value, ID); - } - - @Snippet - public static void writeFloat2(Object o, int offset, float value) { - Word.fromObject(o).writeFloat(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeFloat3(Object o, int offset, float value) { - Word.fromObject(o).writeFloat(offset, value); - } - - @Snippet - public static double readDouble1(Object o, int offset) { - return Word.fromObject(o).readDouble(offset, ID); - } - - @Snippet - public static double readDouble2(Object o, int offset) { - return Word.fromObject(o).readDouble(Word.signed(offset), ID); - } - - @Snippet - public static double readDouble3(Object o, int offset) { - return Word.fromObject(o).readDouble(offset); - } - - @Snippet - public static void writeDouble1(Object o, int offset, double value) { - Word.fromObject(o).writeDouble(offset, value, ID); - } - - @Snippet - public static void writeDouble2(Object o, int offset, double value) { - Word.fromObject(o).writeDouble(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeDouble3(Object o, int offset, double value) { - Word.fromObject(o).writeDouble(offset, value); - } - - @Snippet - public static Object readObject1(Object o, int offset) { - return Word.fromObject(o).readObject(offset, ID); - } - - @Snippet - public static Object readObject2(Object o, int offset) { - return Word.fromObject(o).readObject(Word.signed(offset), ID); - } - - @Snippet - public static Object readObject3(Object o, int offset) { - return Word.fromObject(o).readObject(offset); - } - - @Snippet - public static void writeObject1(Object o, int offset, Object value) { - Word.fromObject(o).writeObject(offset, value, ID); - } - - @Snippet - public static void writeObject2(Object o, int offset, Object value) { - Word.fromObject(o).writeObject(Word.signed(offset), value, ID); - } - - @Snippet - public static void writeObject3(Object o, int offset, Object value) { - Word.fromObject(o).writeObject(offset, value); - } - -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/StandardMethodSubstitutionsTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/StandardMethodSubstitutionsTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,453 +0,0 @@ -/* - * 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. - */ -package com.oracle.graal.replacements; - -import static com.oracle.graal.graph.UnsafeAccess.*; -import static com.oracle.graal.replacements.UnsafeSubstitutions.*; - -import java.lang.reflect.*; -import java.util.concurrent.atomic.*; - -import org.junit.*; - -import sun.misc.*; - -import com.oracle.graal.api.replacements.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.replacements.nodes.*; - -/** - * Tests the VM independent {@link MethodSubstitution}s. - */ -public class StandardMethodSubstitutionsTest extends MethodSubstitutionTest { - - static long off(Object o, String name) { - try { - return unsafe.objectFieldOffset(o.getClass().getDeclaredField(name)); - } catch (Exception e) { - Assert.fail(e.toString()); - return 0L; - } - } - - static class Foo { - - boolean z; - byte b; - short s; - char c; - int i; - long l; - float f; - double d; - Object o; - - void testGet(Field field, long offset, String getName, Object value) throws Exception { - field.set(this, value); - Method m1 = Unsafe.class.getDeclaredMethod(getName, Object.class, long.class); - Method m2 = UnsafeSubstitutions.class.getDeclaredMethod(getName, Object.class, Object.class, long.class); - Object expected = m1.invoke(unsafe, this, offset); - Object actual = m2.invoke(null, unsafe, this, offset); - Assert.assertEquals(expected, actual); - } - - void testDirect(Field field, long offset, String type, Object value) throws Exception { - if (type.equals("Boolean") || type.equals("Object")) { - // No direct memory access for these types - return; - } - - long address = unsafe.allocateMemory(offset + 16); - - String getName = "get" + type; - String putName = "put" + type; - Method m1 = Unsafe.class.getDeclaredMethod(putName, long.class, field.getType()); - Method m2 = Unsafe.class.getDeclaredMethod(getName, long.class); - - Method m3 = UnsafeSubstitutions.class.getDeclaredMethod(putName, Object.class, long.class, field.getType()); - Method m4 = UnsafeSubstitutions.class.getDeclaredMethod(getName, Object.class, long.class); - - m1.invoke(unsafe, address + offset, value); - Object expected = m2.invoke(unsafe, address + offset); - - m3.invoke(null, unsafe, address + offset, value); - Object actual = m4.invoke(null, unsafe, address + offset); - - unsafe.freeMemory(address); - Assert.assertEquals(expected, actual); - } - - void testPut(Field field, long offset, String putName, Object value) throws Exception { - Object initialValue = field.get(new Foo()); - field.set(this, initialValue); - - try { - Method m1 = Unsafe.class.getDeclaredMethod(putName, Object.class, long.class, field.getType()); - Method m2 = UnsafeSubstitutions.class.getDeclaredMethod(putName, Object.class, Object.class, long.class, field.getType()); - m1.invoke(unsafe, this, offset, value); - Object expected = field.get(this); - m2.invoke(null, unsafe, this, offset, value); - Object actual = field.get(this); - Assert.assertEquals(expected, actual); - } catch (NoSuchMethodException e) { - if (!putName.startsWith("putOrdered")) { - throw e; - } - } - } - - void test(String fieldName, String typeSuffix, Object value) { - try { - Field field = Foo.class.getDeclaredField(fieldName); - long offset = unsafe.objectFieldOffset(field); - testGet(field, offset, "get" + typeSuffix, value); - testGet(field, offset, "get" + typeSuffix + "Volatile", value); - testPut(field, offset, "put" + typeSuffix, value); - testPut(field, offset, "put" + typeSuffix + "Volatile", value); - testPut(field, offset, "putOrdered" + typeSuffix, value); - testDirect(field, offset, typeSuffix, value); - } catch (Exception e) { - throw new AssertionError(e); - } - } - } - - @Test - public void testUnsafeSubstitutions() throws Exception { - test("unsafeCompareAndSwapInt"); - test("unsafeCompareAndSwapLong"); - test("unsafeCompareAndSwapObject"); - - test("unsafeGetBoolean"); - test("unsafeGetByte"); - test("unsafeGetShort"); - test("unsafeGetChar"); - test("unsafeGetInt"); - test("unsafeGetLong"); - test("unsafeGetFloat"); - test("unsafeGetDouble"); - test("unsafeGetObject"); - - test("unsafePutBoolean"); - test("unsafePutByte"); - test("unsafePutShort"); - test("unsafePutChar"); - test("unsafePutInt"); - test("unsafePutFloat"); - test("unsafePutDouble"); - test("unsafePutObject"); - - test("unsafeDirectMemoryRead"); - test("unsafeDirectMemoryWrite"); - - AtomicInteger a1 = new AtomicInteger(42); - AtomicInteger a2 = new AtomicInteger(42); - assertEquals(unsafe.compareAndSwapInt(a1, off(a1, "value"), 42, 53), compareAndSwapInt(unsafe, a2, off(a2, "value"), 42, 53)); - assertEquals(a1.get(), a2.get()); - - AtomicLong l1 = new AtomicLong(42); - AtomicLong l2 = new AtomicLong(42); - assertEquals(unsafe.compareAndSwapLong(l1, off(l1, "value"), 42, 53), compareAndSwapLong(unsafe, l2, off(l2, "value"), 42, 53)); - assertEquals(l1.get(), l2.get()); - - AtomicReference o1 = new AtomicReference<>("42"); - AtomicReference o2 = new AtomicReference<>("42"); - assertEquals(unsafe.compareAndSwapObject(o1, off(o1, "value"), "42", "53"), compareAndSwapObject(unsafe, o2, off(o2, "value"), "42", "53")); - assertEquals(o1.get(), o2.get()); - - Foo f1 = new Foo(); - f1.test("z", "Boolean", Boolean.TRUE); - f1.test("b", "Byte", Byte.MIN_VALUE); - f1.test("s", "Short", Short.MAX_VALUE); - f1.test("c", "Char", '!'); - f1.test("i", "Int", 1010010); - f1.test("f", "Float", -34.5F); - f1.test("l", "Long", 99999L); - f1.test("d", "Double", 1234.5678D); - f1.test("o", "Object", "object"); - } - - @SuppressWarnings("all") - public static boolean unsafeCompareAndSwapInt(Unsafe unsafe, Object obj, long offset) { - return unsafe.compareAndSwapInt(obj, offset, 0, 1); - } - - @SuppressWarnings("all") - public static boolean unsafeCompareAndSwapLong(Unsafe unsafe, Object obj, long offset) { - return unsafe.compareAndSwapLong(obj, offset, 0, 1); - } - - @SuppressWarnings("all") - public static boolean unsafeCompareAndSwapObject(Unsafe unsafe, Object obj, long offset) { - return unsafe.compareAndSwapObject(obj, offset, null, new Object()); - } - - @SuppressWarnings("all") - public static boolean unsafeGetBoolean(Unsafe unsafe, Object obj, long offset) { - return unsafe.getBoolean(obj, offset) && unsafe.getBooleanVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static int unsafeGetByte(Unsafe unsafe, Object obj, long offset) { - return unsafe.getByte(obj, offset) + unsafe.getByteVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static int unsafeGetShort(Unsafe unsafe, Object obj, long offset) { - return unsafe.getShort(obj, offset) + unsafe.getShortVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static int unsafeGetChar(Unsafe unsafe, Object obj, long offset) { - return unsafe.getChar(obj, offset) + unsafe.getCharVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static int unsafeGetInt(Unsafe unsafe, Object obj, long offset) { - return unsafe.getInt(obj, offset) + unsafe.getIntVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static long unsafeGetLong(Unsafe unsafe, Object obj, long offset) { - return unsafe.getLong(obj, offset) + unsafe.getLongVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static float unsafeGetFloat(Unsafe unsafe, Object obj, long offset) { - return unsafe.getFloat(obj, offset) + unsafe.getFloatVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static double unsafeGetDouble(Unsafe unsafe, Object obj, long offset) { - return unsafe.getDouble(obj, offset) + unsafe.getDoubleVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static boolean unsafeGetObject(Unsafe unsafe, Object obj, long offset) { - return unsafe.getObject(obj, offset) == unsafe.getObjectVolatile(obj, offset); - } - - @SuppressWarnings("all") - public static void unsafePutBoolean(Unsafe unsafe, Object obj, long offset, boolean value) { - unsafe.putBoolean(obj, offset, value); - unsafe.putBooleanVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutByte(Unsafe unsafe, Object obj, long offset, byte value) { - unsafe.putByte(obj, offset, value); - unsafe.putByteVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutShort(Unsafe unsafe, Object obj, long offset, short value) { - unsafe.putShort(obj, offset, value); - unsafe.putShortVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutChar(Unsafe unsafe, Object obj, long offset, char value) { - unsafe.putChar(obj, offset, value); - unsafe.putCharVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutInt(Unsafe unsafe, Object obj, long offset, int value) { - unsafe.putInt(obj, offset, value); - unsafe.putIntVolatile(obj, offset, value); - unsafe.putOrderedInt(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutLong(Unsafe unsafe, Object obj, long offset, long value) { - unsafe.putLong(obj, offset, value); - unsafe.putLongVolatile(obj, offset, value); - unsafe.putOrderedLong(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutFloat(Unsafe unsafe, Object obj, long offset, float value) { - unsafe.putFloat(obj, offset, value); - unsafe.putFloatVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutDouble(Unsafe unsafe, Object obj, long offset, double value) { - unsafe.putDouble(obj, offset, value); - unsafe.putDoubleVolatile(obj, offset, value); - } - - @SuppressWarnings("all") - public static void unsafePutObject(Unsafe unsafe, Object obj, long offset, Object value) { - unsafe.putObject(obj, offset, value); - unsafe.putObjectVolatile(obj, offset, value); - unsafe.putOrderedObject(obj, offset, value); - } - - @SuppressWarnings("all") - public static double unsafeDirectMemoryRead(Unsafe unsafe, long address) { - // Unsafe.getBoolean(long) and Unsafe.getObject(long) do not exist - return unsafe.getByte(address) + unsafe.getShort(address) + unsafe.getChar(address) + unsafe.getInt(address) + unsafe.getLong(address) + unsafe.getFloat(address) + unsafe.getDouble(address); - } - - @SuppressWarnings("all") - public static void unsafeDirectMemoryWrite(Unsafe unsafe, long address, byte value) { - // Unsafe.putBoolean(long) and Unsafe.putObject(long) do not exist - unsafe.putByte(address, value); - unsafe.putShort(address, value); - unsafe.putChar(address, (char) value); - unsafe.putInt(address, value); - unsafe.putLong(address, value); - unsafe.putFloat(address, value); - unsafe.putDouble(address, value); - } - - @Test - public void testMathSubstitutions() { - assertInGraph(assertNotInGraph(test("mathAbs"), IfNode.class), MathIntrinsicNode.class); // Java - test("math"); - - double value = 34567.891D; - assertEquals(Math.sqrt(value), MathSubstitutionsX86.sqrt(value)); - assertEquals(Math.log(value), MathSubstitutionsX86.log(value)); - assertEquals(Math.log10(value), MathSubstitutionsX86.log10(value)); - assertEquals(Math.sin(value), MathSubstitutionsX86.sin(value)); - assertEquals(Math.cos(value), MathSubstitutionsX86.cos(value)); - assertEquals(Math.tan(value), MathSubstitutionsX86.tan(value)); - } - - @SuppressWarnings("all") - public static double mathAbs(double value) { - return Math.abs(value); - } - - @SuppressWarnings("all") - public static double math(double value) { - return Math.sqrt(value) + Math.log(value) + Math.log10(value) + Math.sin(value) + Math.cos(value) + Math.tan(value); - // Math.exp(value) + - // Math.pow(value, 13); - } - - @Test - public void testIntegerSubstitutions() { - assertInGraph(test("integerReverseBytes"), ReverseBytesNode.class); // Java - assertInGraph(test("integerNumberOfLeadingZeros"), BitScanReverseNode.class); // Java - assertInGraph(test("integerNumberOfTrailingZeros"), BitScanForwardNode.class); // Java - assertInGraph(test("integerBitCount"), BitCountNode.class); // Java - - for (int i : new int[]{Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE}) { - assertEquals(Integer.reverseBytes(i), IntegerSubstitutions.reverseBytes(i)); - assertEquals(Integer.numberOfLeadingZeros(i), IntegerSubstitutions.numberOfLeadingZeros(i)); - assertEquals(Integer.numberOfTrailingZeros(i), IntegerSubstitutions.numberOfTrailingZeros(i)); - assertEquals(Integer.bitCount(i), IntegerSubstitutions.bitCount(i)); - } - } - - @SuppressWarnings("all") - public static int integerReverseBytes(int value) { - return Integer.reverseBytes(value); - } - - @SuppressWarnings("all") - public static int integerNumberOfLeadingZeros(int value) { - return Integer.numberOfLeadingZeros(value); - } - - @SuppressWarnings("all") - public static int integerNumberOfTrailingZeros(int value) { - return Integer.numberOfTrailingZeros(value); - } - - @SuppressWarnings("all") - public static int integerBitCount(int value) { - return Integer.bitCount(value); - } - - @Test - public void testLongSubstitutions() { - assertInGraph(test("longReverseBytes"), ReverseBytesNode.class); // Java - assertInGraph(test("longNumberOfLeadingZeros"), BitScanReverseNode.class); // Java - assertInGraph(test("longNumberOfTrailingZeros"), BitScanForwardNode.class); // Java - assertInGraph(test("longBitCount"), BitCountNode.class); // Java - - for (long l : new long[]{Long.MIN_VALUE, -1L, 0L, 1L, Long.MAX_VALUE}) { - assertEquals(Long.reverseBytes(l), LongSubstitutions.reverseBytes(l)); - assertEquals(Long.numberOfLeadingZeros(l), LongSubstitutions.numberOfLeadingZeros(l)); - assertEquals(Long.numberOfTrailingZeros(l), LongSubstitutions.numberOfTrailingZeros(l)); - assertEquals(Long.bitCount(l), LongSubstitutions.bitCount(l)); - } - } - - @SuppressWarnings("all") - public static long longReverseBytes(long value) { - return Long.reverseBytes(value); - } - - @SuppressWarnings("all") - public static long longNumberOfLeadingZeros(long value) { - return Long.numberOfLeadingZeros(value); - } - - @SuppressWarnings("all") - public static long longNumberOfTrailingZeros(long value) { - return Long.numberOfTrailingZeros(value); - } - - @SuppressWarnings("all") - public static int longBitCount(long value) { - return Long.bitCount(value); - } - - @Test - public void testFloatSubstitutions() { - assertInGraph(test("floatToIntBits"), ConvertNode.class); // Java - test("intBitsToFloat"); - } - - @SuppressWarnings("all") - public static int floatToIntBits(float value) { - return Float.floatToIntBits(value); - } - - @SuppressWarnings("all") - public static float intBitsToFloat(int value) { - return Float.intBitsToFloat(value); - } - - @Test - public void testDoubleSubstitutions() { - assertInGraph(test("doubleToLongBits"), ConvertNode.class); // Java - test("longBitsToDouble"); - } - - @SuppressWarnings("all") - public static long doubleToLongBits(double value) { - return Double.doubleToLongBits(value); - } - - @SuppressWarnings("all") - public static double longBitsToDouble(long value) { - return Double.longBitsToDouble(value); - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/TypeCheckTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/TypeCheckTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * Copyright (c) 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. - */ -package com.oracle.graal.replacements; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.nodes.*; - -/** - * Base class for checkcast and instanceof test classes. - */ -public abstract class TypeCheckTest extends GraalCompilerTest { - - protected abstract void replaceProfile(StructuredGraph graph, JavaTypeProfile profile); - - protected JavaTypeProfile currentProfile; - - @Override - protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) { - boolean forceCompile = false; - if (currentProfile != null) { - replaceProfile(graph, currentProfile); - forceCompile = true; - } - return super.getCode(method, graph, forceCompile); - } - - protected JavaTypeProfile profile(Class... types) { - if (types.length == 0) { - return null; - } - ProfiledType[] ptypes = new ProfiledType[types.length]; - for (int i = 0; i < types.length; i++) { - ptypes[i] = new ProfiledType(runtime.lookupJavaType(types[i]), 1.0D / types.length); - } - return new JavaTypeProfile(0.0D, ptypes); - } - - protected void test(String name, JavaTypeProfile profile, Object... args) { - assert currentProfile == null; - currentProfile = profile; - try { - super.test(name, args); - } finally { - currentProfile = null; - } - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/WordTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/WordTest.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,227 +0,0 @@ -/* - * Copyright (c) 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. - */ -package com.oracle.graal.replacements; - -import java.lang.reflect.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.runtime.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.test.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.replacements.Snippet.*; -import com.oracle.graal.word.*; - -/** - * Tests for the {@link Word} type. - */ -public class WordTest extends GraalCompilerTest implements Snippets { - - private final ReplacementsInstaller installer; - - public WordTest() { - TargetDescription target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget(); - installer = new ReplacementsInstaller(runtime, new Assumptions(false), target); - } - - private static final ThreadLocal inliningPolicy = new ThreadLocal<>(); - - @Override - protected StructuredGraph parse(Method m) { - ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); - return installer.makeGraph(resolvedMethod, inliningPolicy.get()); - } - - @LongTest - public void construction() { - long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L, - Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L}; - for (long word : words) { - test("unsigned_long", word); - test("unsigned_int", (int) word); - test("signed_long", word); - test("signed_int", (int) word); - } - } - - @LongTest - public void test_arithmetic() { - long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L, - Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L}; - for (long word : words) { - test("unsigned_not", word); - test("signed_not", word); - for (long addend : words) { - test("unsigned_plus_int", word, (int) addend); - test("unsigned_minus_int", word, (int) addend); - test("unsigned_plus_int", word, -((int) addend)); - test("unsigned_minus_int", word, -((int) addend)); - test("unsigned_plus_long", word, addend); - test("unsigned_minus_long", word, addend); - test("unsigned_plus_long", word, -addend); - test("unsigned_minus_long", word, -addend); - test("signed_plus_int", word, (int) addend); - test("signed_minus_int", word, (int) addend); - test("signed_plus_int", word, -((int) addend)); - test("signed_minus_int", word, -((int) addend)); - test("signed_plus_long", word, addend); - test("signed_minus_long", word, addend); - test("signed_plus_long", word, -addend); - test("signed_minus_long", word, -addend); - - test("and_int", word, (int) addend); - test("or_int", word, (int) addend); - test("and_int", word, -((int) addend)); - test("or_int", word, -((int) addend)); - test("and_long", word, addend); - test("or_long", word, addend); - test("and_long", word, -addend); - test("or_long", word, -addend); - } - } - } - - @LongTest - public void test_compare() { - long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE}; - for (long word1 : words) { - for (long word2 : words) { - for (String method : new String[]{"aboveOrEqual", "above", "belowOrEqual", "below"}) { - test(method, word1, word2); - test(method, word2, word1); - } - } - } - } - - @Snippet - public static long unsigned_long(long word) { - return Word.unsigned(word).rawValue(); - } - - @Snippet - public static long unsigned_int(int word) { - return Word.unsigned(word).rawValue(); - } - - @Snippet - public static long signed_long(long word) { - return Word.signed(word).rawValue(); - } - - @Snippet - public static long signed_int(int word) { - return Word.signed(word).rawValue(); - } - - @Snippet - public static long unsigned_plus_int(long word, int addend) { - return Word.unsigned(word).add(addend).rawValue(); - } - - @Snippet - public static long unsigned_minus_int(long word, int addend) { - return Word.unsigned(word).subtract(addend).rawValue(); - } - - @Snippet - public static long unsigned_plus_long(long word, long addend) { - return Word.unsigned(word).add(Word.unsigned(addend)).rawValue(); - } - - @Snippet - public static long unsigned_minus_long(long word, long addend) { - return Word.unsigned(word).subtract(Word.unsigned(addend)).rawValue(); - } - - @Snippet - public static long signed_plus_int(long word, int addend) { - return Word.signed(word).add(addend).rawValue(); - } - - @Snippet - public static long signed_minus_int(long word, int addend) { - return Word.signed(word).subtract(addend).rawValue(); - } - - @Snippet - public static long signed_plus_long(long word, long addend) { - return Word.signed(word).add(Word.signed(addend)).rawValue(); - } - - @Snippet - public static long signed_minus_long(long word, long addend) { - return Word.signed(word).subtract(Word.signed(addend)).rawValue(); - } - - @Snippet - public static long signed_not(long word) { - return Word.signed(word).not().rawValue(); - } - - @Snippet - public static long unsigned_not(long word) { - return Word.unsigned(word).not().rawValue(); - } - - @Snippet - public static boolean aboveOrEqual(long word1, long word2) { - return Word.unsigned(word1).aboveOrEqual(Word.unsigned(word2)); - } - - @Snippet - public static boolean above(long word1, long word2) { - return Word.unsigned(word1).aboveThan(Word.unsigned(word2)); - } - - @Snippet - public static boolean belowOrEqual(long word1, long word2) { - return Word.unsigned(word1).belowOrEqual(Word.unsigned(word2)); - } - - @Snippet - public static boolean below(long word1, long word2) { - return Word.unsigned(word1).belowThan(Word.unsigned(word2)); - } - - @Snippet - public static long and_int(long word, int addend) { - return Word.unsigned(word).and(addend).rawValue(); - } - - @Snippet - public static long or_int(long word, int addend) { - return Word.unsigned(word).or(addend).rawValue(); - } - - @Snippet - public static long and_long(long word, long addend) { - return Word.unsigned(word).and(Word.unsigned(addend)).rawValue(); - } - - @Snippet - public static long or_long(long word, long addend) { - return Word.unsigned(word).or(Word.unsigned(addend)).rawValue(); - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CheckCastTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,214 @@ +/* + * Copyright (c) 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. + */ +package com.oracle.graal.replacements.test; + + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; + +/** + * Tests the implementation of checkcast, allowing profiling information to be manually specified. + */ +public class CheckCastTest extends TypeCheckTest { + + @Override + protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) { + CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first(); + if (ccn != null) { + CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.type(), ccn.object(), profile)); + graph.replaceFixedWithFixed(ccn, ccnNew); + } + } + + @LongTest + public void test1() { + test("asNumber", profile(), 111); + test("asNumber", profile(Integer.class), 111); + test("asNumber", profile(Long.class, Short.class), 111); + test("asNumberExt", profile(), 111); + test("asNumberExt", profile(Integer.class), 111); + test("asNumberExt", profile(Long.class, Short.class), 111); + } + + @LongTest + public void test2() { + test("asString", profile(), "111"); + test("asString", profile(String.class), "111"); + test("asString", profile(String.class), "111"); + + final String nullString = null; + test("asString", profile(), nullString); + test("asString", profile(String.class), nullString); + test("asString", profile(String.class), nullString); + + test("asStringExt", profile(), "111"); + test("asStringExt", profile(String.class), "111"); + test("asStringExt", profile(String.class), "111"); + } + + @LongTest + public void test3() { + test("asNumber", profile(), "111"); + } + + @LongTest + public void test4() { + test("asString", profile(String.class), 111); + } + + @LongTest + public void test5() { + test("asNumberExt", profile(), "111"); + } + + @LongTest + public void test6() { + test("asStringExt", profile(String.class), 111); + } + + @LongTest + public void test7() { + Throwable throwable = new Exception(); + test("asThrowable", profile(), throwable); + test("asThrowable", profile(Throwable.class), throwable); + test("asThrowable", profile(Exception.class, Error.class), throwable); + } + + @LongTest + public void test8() { + test("arrayStore", new Object[100], "111"); + } + + @LongTest + public void test8_1() { + test("arrayFill", new Object[100], "111"); + } + + public static Number asNumber(Object o) { + return (Number) o; + } + + public static String asString(Object o) { + return (String) o; + } + + public static Throwable asThrowable(Object o) { + return (Throwable) o; + } + + public static ValueNode asValueNode(Object o) { + return (ValueNode) o; + } + + public static Number asNumberExt(Object o) { + Number n = (Number) o; + return n.intValue() + 10; + } + + public static String asStringExt(Object o) { + String s = (String) o; + return "#" + s; + } + + public static Object[] arrayStore(Object[] arr, Object value) { + arr[15] = value; + return arr; + } + + public static Object[] arrayFill(Object[] arr, Object value) { + for (int i = 0; i < arr.length; i++) { + arr[i] = value; + } + return arr; + } + + static class Depth1 implements Cloneable { + } + + static class Depth2 extends Depth1 { + } + + static class Depth3 extends Depth2 { + } + + static class Depth4 extends Depth3 { + } + + static class Depth5 extends Depth4 { + } + + static class Depth6 extends Depth5 { + } + + static class Depth7 extends Depth6 { + } + + static class Depth8 extends Depth7 { + } + + static class Depth9 extends Depth8 { + } + + static class Depth10 extends Depth9 { + } + + static class Depth11 extends Depth10 { + } + + static class Depth12 extends Depth11 { + } + + static class Depth13 extends Depth12 { + } + + static class Depth14 extends Depth12 { + } + + public static Depth12 asDepth12(Object o) { + return (Depth12) o; + } + + public static Depth12[][] asDepth12Arr(Object o) { + return (Depth12[][]) o; + } + + public static Cloneable asCloneable(Object o) { + return (Cloneable) o; + } + + @LongTest + public void test9() { + Object o = new Depth13(); + test("asDepth12", profile(), o); + test("asDepth12", profile(Depth13.class), o); + test("asDepth12", profile(Depth13.class, Depth14.class), o); + } + + @LongTest + public void test10() { + Object o = new Depth13[3][]; + test("asDepth12Arr", o); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CompiledExceptionHandlerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CompiledExceptionHandlerTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 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. + */ +package com.oracle.graal.replacements.test; + +import java.lang.reflect.*; + +import org.junit.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; + +/** + * Tests compilation of a hot exception handler. + */ +public class CompiledExceptionHandlerTest extends GraalCompilerTest { + + @Override + protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) { + phasePlan.disablePhase(InliningPhase.class); + } + + @Override + protected StructuredGraph parse(Method m) { + StructuredGraph graph = super.parse(m); + int handlers = graph.getNodes().filter(ExceptionObjectNode.class).count(); + Assert.assertEquals(1, handlers); + return graph; + } + + private static void raiseException(String s) { + throw new RuntimeException(s); + } + + @Test + public void test1() { + // Ensure the profile shows a hot exception + for (int i = 0; i < 10000; i++) { + test1Snippet(""); + test1Snippet(null); + } + + test("test1Snippet", "a string"); + } + + public static String test1Snippet(String message) { + if (message != null) { + try { + raiseException(message); + } catch (Exception e) { + return message; + } + } + return null; + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfDynamicTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfDynamicTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 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. + */ +package com.oracle.graal.replacements.test; + +import com.oracle.graal.test.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.java.*; + +/** + * Tests for {@link InstanceOfDynamicNode}. + */ +public class InstanceOfDynamicTest extends GraalCompilerTest { + + public static int id(int value) { + return value; + } + + @LongTest + public void test100() { + final Object nul = null; + test("isStringDynamic", nul); + test("isStringDynamic", "object"); + test("isStringDynamic", Object.class); + } + + @LongTest + public void test101() { + final Object nul = null; + test("isStringIntDynamic", nul); + test("isStringIntDynamic", "object"); + test("isStringIntDynamic", Object.class); + } + + @LongTest + public void test103() { + test("isInstanceDynamic", String.class, null); + test("isInstanceDynamic", String.class, "object"); + test("isInstanceDynamic", String.class, Object.class); + test("isInstanceDynamic", int.class, null); + test("isInstanceDynamic", int.class, "Object"); + test("isInstanceDynamic", int.class, Object.class); + } + + @LongTest + public void test104() { + test("isInstanceIntDynamic", String.class, null); + test("isInstanceIntDynamic", String.class, "object"); + test("isInstanceIntDynamic", String.class, Object.class); + test("isInstanceIntDynamic", int.class, null); + test("isInstanceIntDynamic", int.class, "Object"); + test("isInstanceIntDynamic", int.class, Object.class); + } + + public static boolean isStringDynamic(Object o) { + return String.class.isInstance(o); + } + + public static int isStringIntDynamic(Object o) { + if (String.class.isInstance(o)) { + return o.toString().length(); + } + return o.getClass().getName().length(); + } + + public static boolean isInstanceDynamic(Class c, Object o) { + return c.isInstance(o); + } + + public static int isInstanceIntDynamic(Class c, Object o) { + if (c.isInstance(o)) { + return o.toString().length(); + } + return o.getClass().getName().length(); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InstanceOfTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,401 @@ +/* + * Copyright (c) 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. + */ +package com.oracle.graal.replacements.test; + +import java.util.*; + +import com.oracle.graal.api.code.CompilationResult.Call; +import com.oracle.graal.api.code.CompilationResult.Mark; +import com.oracle.graal.api.code.CompilationResult.Site; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.replacements.test.CheckCastTest.Depth12; +import com.oracle.graal.replacements.test.CheckCastTest.Depth13; +import com.oracle.graal.replacements.test.CheckCastTest.Depth14; +import com.oracle.graal.test.*; + +/** + * Tests the implementation of instanceof, allowing profiling information to be manually specified. + */ +public class InstanceOfTest extends TypeCheckTest { + + @Override + protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) { + phasePlan.disablePhase(InliningPhase.class); + } + + @Override + protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) { + InstanceOfNode ion = graph.getNodes().filter(InstanceOfNode.class).first(); + if (ion != null) { + InstanceOfNode ionNew = graph.add(new InstanceOfNode(ion.type(), ion.object(), profile)); + graph.replaceFloating(ion, ionNew); + } + } + + @LongTest + public void test1() { + test("isString", profile(), "object"); + test("isString", profile(String.class), "object"); + + test("isString", profile(), Object.class); + test("isString", profile(String.class), Object.class); + } + + @LongTest + public void test2() { + test("isStringInt", profile(), "object"); + test("isStringInt", profile(String.class), "object"); + + test("isStringInt", profile(), Object.class); + test("isStringInt", profile(String.class), Object.class); + } + + @LongTest + public void test2_1() { + test("isStringIntComplex", profile(), "object"); + test("isStringIntComplex", profile(String.class), "object"); + + test("isStringIntComplex", profile(), Object.class); + test("isStringIntComplex", profile(String.class), Object.class); + } + + @LongTest + public void test3() { + Throwable throwable = new Exception(); + test("isThrowable", profile(), throwable); + test("isThrowable", profile(Throwable.class), throwable); + test("isThrowable", profile(Exception.class, Error.class), throwable); + + test("isThrowable", profile(), Object.class); + test("isThrowable", profile(Throwable.class), Object.class); + test("isThrowable", profile(Exception.class, Error.class), Object.class); + } + + @LongTest + public void test3_1() { + onlyFirstIsException(new Exception(), new Error()); + test("onlyFirstIsException", profile(), new Exception(), new Error()); + test("onlyFirstIsException", profile(), new Error(), new Exception()); + test("onlyFirstIsException", profile(), new Exception(), new Exception()); + test("onlyFirstIsException", profile(), new Error(), new Error()); + } + + @LongTest + public void test4() { + Throwable throwable = new Exception(); + test("isThrowableInt", profile(), throwable); + test("isThrowableInt", profile(Throwable.class), throwable); + test("isThrowableInt", profile(Exception.class, Error.class), throwable); + + test("isThrowableInt", profile(), Object.class); + test("isThrowableInt", profile(Throwable.class), Object.class); + test("isThrowableInt", profile(Exception.class, Error.class), Object.class); + } + + @LongTest + public void test5() { + Map map = new HashMap<>(); + test("isMap", profile(), map); + test("isMap", profile(HashMap.class), map); + test("isMap", profile(TreeMap.class, HashMap.class), map); + + test("isMap", profile(), Object.class); + test("isMap", profile(HashMap.class), Object.class); + test("isMap", profile(TreeMap.class, HashMap.class), Object.class); + test("isMap", profile(String.class, HashMap.class), Object.class); + } + + @LongTest + public void test6() { + Map map = new HashMap<>(); + test("isMapInt", profile(), map); + test("isMapInt", profile(HashMap.class), map); + test("isMapInt", profile(TreeMap.class, HashMap.class), map); + + test("isMapInt", profile(), Object.class); + test("isMapInt", profile(HashMap.class), Object.class); + test("isMapInt", profile(TreeMap.class, HashMap.class), Object.class); + } + + @LongTest + public void test7() { + Object o = new Depth13(); + test("isDepth12", profile(), o); + test("isDepth12", profile(Depth13.class), o); + test("isDepth12", profile(Depth13.class, Depth14.class), o); + + o = "not a depth"; + test("isDepth12", profile(), o); + test("isDepth12", profile(Depth13.class), o); + test("isDepth12", profile(Depth13.class, Depth14.class), o); + test("isDepth12", profile(String.class, HashMap.class), o); + } + + @LongTest + public void test8() { + Object o = new Depth13(); + test("isDepth12Int", profile(), o); + test("isDepth12Int", profile(Depth13.class), o); + test("isDepth12Int", profile(Depth13.class, Depth14.class), o); + + o = "not a depth"; + test("isDepth12Int", profile(), o); + test("isDepth12Int", profile(Depth13.class), o); + test("isDepth12Int", profile(Depth13.class, Depth14.class), o); + } + + public static boolean isString(Object o) { + return o instanceof String; + } + + public static int isStringInt(Object o) { + if (o instanceof String) { + return id(1); + } + return id(0); + } + + public static int isStringIntComplex(Object o) { + if (o instanceof String || o instanceof Integer) { + return id(o instanceof String ? 1 : 0); + } + return id(0); + } + + public static int id(int value) { + return value; + } + + public static boolean isThrowable(Object o) { + return ((Throwable) o) instanceof Exception; + } + + public static int onlyFirstIsException(Throwable t1, Throwable t2) { + if (t1 instanceof Exception ^ t2 instanceof Exception) { + return t1 instanceof Exception ? 1 : -1; + } + return -1; + } + + public static int isThrowableInt(Object o) { + int result = o instanceof Throwable ? 4 : 5; + if (o instanceof Throwable) { + return id(4); + } + return result; + } + + public static boolean isMap(Object o) { + return o instanceof Map; + } + + public static int isMapInt(Object o) { + if (o instanceof Map) { + return id(1); + } + return id(0); + } + + public static boolean isDepth12(Object o) { + return o instanceof Depth12; + } + + public static int isDepth12Int(Object o) { + if (o instanceof Depth12) { + return id(0); + } + return id(0); + } + + abstract static class MySite { + + final int offset; + + MySite(int offset) { + this.offset = offset; + } + } + + static class MyMark extends MySite { + + MyMark(int offset) { + super(offset); + } + } + + abstract static class MySafepoint extends MySite { + + MySafepoint(int offset) { + super(offset); + } + } + + static class MyCall extends MySafepoint { + + MyCall(int offset) { + super(offset); + } + } + + @LongTest + public void test9() { + MyCall callAt63 = new MyCall(63); + MyMark markAt63 = new MyMark(63); + test("compareMySites", callAt63, callAt63); + test("compareMySites", callAt63, markAt63); + test("compareMySites", markAt63, callAt63); + test("compareMySites", markAt63, markAt63); + } + + public static int compareMySites(MySite s1, MySite s2) { + if (s1.offset == s2.offset && (s1 instanceof MyMark ^ s2 instanceof MyMark)) { + return s1 instanceof MyMark ? -1 : 1; + } + return s1.offset - s2.offset; + } + + @LongTest + public void test10() { + Mark[] noMarks = {}; + Call callAt63 = new Call(null, 63, 5, true, null); + Mark markAt63 = new Mark(63, "1", noMarks); + test("compareSites", callAt63, callAt63); + test("compareSites", callAt63, markAt63); + test("compareSites", markAt63, callAt63); + test("compareSites", markAt63, markAt63); + } + + public static int compareSites(Site s1, Site s2) { + if (s1.pcOffset == s2.pcOffset && (s1 instanceof Mark ^ s2 instanceof Mark)) { + return s1 instanceof Mark ? -1 : 1; + } + return s1.pcOffset - s2.pcOffset; + } + + /** + * This test exists to show the kind of pattern that is be optimizable by + * {@code removeIntermediateMaterialization()} in {@link IfNode}. + *

+ * The test exists in this source file as the transformation was originally motivated by the + * need to remove use of special JumpNodes in the {@code InstanceOfSnippets}. + */ + @LongTest + public void test_removeIntermediateMaterialization() { + List list = Arrays.asList("1", "2", "3", "4"); + test("removeIntermediateMaterialization", profile(), list, "2", "yes", "no"); + test("removeIntermediateMaterialization", profile(), list, null, "yes", "no"); + test("removeIntermediateMaterialization", profile(), null, "2", "yes", "no"); + } + + public static String removeIntermediateMaterialization(List list, Object e, String a, String b) { + boolean test; + if (list == null || e == null) { + test = false; + } else { + test = false; + for (Object i : list) { + if (i.equals(e)) { + test = true; + break; + } + } + } + if (test) { + return a; + } + return b; + } + + abstract static class A { + } + + static class B extends A { + } + + static class C extends B { + } + + abstract static class D extends C { + } + + public static boolean isArrayOfA(Object o) { + return o instanceof A[]; + } + + public static boolean isArrayOfB(Object o) { + return o instanceof B[]; + } + + public static boolean isArrayOfC(Object o) { + return o instanceof C[]; + } + + public static boolean isArrayOfD(Object o) { + return o instanceof D[]; + } + + @LongTest + public void testArray() { + Object aArray = new A[10]; + test("isArrayOfA", aArray); + + Object bArray = new B[10]; + test("isArrayOfA", aArray); + test("isArrayOfA", bArray); + test("isArrayOfB", aArray); + test("isArrayOfB", bArray); + + Object cArray = new C[10]; + test("isArrayOfA", aArray); + test("isArrayOfA", bArray); + test("isArrayOfA", cArray); + test("isArrayOfB", aArray); + test("isArrayOfB", bArray); + test("isArrayOfB", cArray); + test("isArrayOfC", aArray); + test("isArrayOfC", bArray); + test("isArrayOfC", cArray); + + Object dArray = new D[10]; + test("isArrayOfA", aArray); + test("isArrayOfA", bArray); + test("isArrayOfA", cArray); + test("isArrayOfA", dArray); + test("isArrayOfB", aArray); + test("isArrayOfB", bArray); + test("isArrayOfB", cArray); + test("isArrayOfB", dArray); + test("isArrayOfC", aArray); + test("isArrayOfC", bArray); + test("isArrayOfC", cArray); + test("isArrayOfC", dArray); + test("isArrayOfD", aArray); + test("isArrayOfD", bArray); + test("isArrayOfD", cArray); + test("isArrayOfD", dArray); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InvokeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/InvokeTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 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. + */ +package com.oracle.graal.replacements.test; + +import org.junit.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; + +/** + * Tests the implementation of the snippets for lowering the INVOKE* instructions. + */ +public class InvokeTest extends GraalCompilerTest { + + @Override + protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) { + phasePlan.disablePhase(InliningPhase.class); + } + + public interface I { + + String virtualMethod(String s); + } + + public static class A implements I { + + final String name = "A"; + + public String virtualMethod(String s) { + return name + s; + } + } + + @SuppressWarnings("static-method") + private String privateMethod(String s) { + return s; + } + + @Test + public void test1() { + test("invokestatic", "a string"); + test("invokespecialConstructor", "a string"); + test("invokespecial", this, "a string"); + test("invokevirtual", new A(), "a string"); + test("invokevirtual2", new A(), "a string"); + test("invokeinterface", new A(), "a string"); + Object[] args = {null}; + test("invokestatic", args); + test("invokespecialConstructor", args); + test("invokespecial", null, null); + test("invokevirtual", null, null); + test("invokevirtual2", null, null); + test("invokeinterface", null, null); + } + + public static String invokestatic(String s) { + return staticMethod(s); + } + + public static String staticMethod(String s) { + return s; + } + + public static String invokespecialConstructor(String s) { + return new A().virtualMethod(s); + } + + public static String invokespecial(InvokeTest a, String s) { + return a.privateMethod(s); + } + + public static String invokevirtual(A a, String s) { + return a.virtualMethod(s); + } + + public static String invokevirtual2(A a, String s) { + a.virtualMethod(s); + return a.virtualMethod(s); + } + + public static String invokeinterface(I i, String s) { + return i.virtualMethod(s); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,84 @@ +/* + * 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. + */ +package com.oracle.graal.replacements.test; + +import static org.junit.Assert.*; + +import java.util.concurrent.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; + +/** + * Tests if {@link MethodSubstitution}s are inlined correctly. Most test cases only assert that + * there are no remaining invocations in the graph. This is sufficient if the method that is being + * substituted is a native method. For Java methods, additional checks are necessary. + */ +public abstract class MethodSubstitutionTest extends GraalCompilerTest { + + protected StructuredGraph test(final String snippet) { + return Debug.scope("MethodSubstitutionTest", runtime.lookupJavaMethod(getMethod(snippet)), new Callable() { + + @Override + public StructuredGraph call() { + StructuredGraph graph = parse(snippet); + PhasePlan phasePlan = getDefaultPhasePlan(); + Assumptions assumptions = new Assumptions(true); + new ComputeProbabilityPhase().apply(graph); + Debug.dump(graph, "Graph"); + new InliningPhase(runtime(), null, replacements, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); + Debug.dump(graph, "Graph"); + new CanonicalizerPhase.Instance(runtime(), assumptions).apply(graph); + new DeadCodeEliminationPhase().apply(graph); + + assertNotInGraph(graph, Invoke.class); + return graph; + } + }); + } + + protected static StructuredGraph assertNotInGraph(StructuredGraph graph, Class clazz) { + for (Node node : graph.getNodes()) { + if (clazz.isInstance(node)) { + fail(node.toString()); + } + } + return graph; + } + + protected static StructuredGraph assertInGraph(StructuredGraph graph, Class clazz) { + for (Node node : graph.getNodes()) { + if (clazz.isInstance(node)) { + return graph; + } + } + fail("Graph does not contain a node of class " + clazz.getName()); + return graph; + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MonitorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MonitorTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,209 @@ +/* + * 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. + */ +package com.oracle.graal.replacements.test; + +import org.junit.*; + +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.virtual.phases.ea.*; + +public class MonitorTest extends GraalCompilerTest { + + @Test + public void test0() { + test("lockObjectSimple", new Object(), new Object()); + test("lockObjectSimple", new Object(), null); + } + + @Test + public void test0_1() { + test("lockThisSimple", "test1", new Object()); + test("lockThisSimple", "test1", null); + } + + @Test + public void test0_2() { + test("lockObjectSimple", null, "test1"); + } + + @Test + public void test1_1() { + test("lockObject", new Object(), "test1", new String[1]); + } + + @Test + public void test1_2() { + test("lockObject", null, "test1_1", new String[1]); + } + + @Test + public void test2() { + test("lockThis", "test2", new String[1]); + } + + /** + * Tests monitor operations on {@link PartialEscapeAnalysisPhase virtual objects}. + */ + @Test + public void test3() { + test("lockLocalObject", "test3", new String[1]); + } + + /** + * Tests recursive locking of objects which should be biasable. + */ + @Test + public void test4() { + Chars src = new Chars("1234567890".toCharArray()); + Chars dst = new Chars(src.data.length); + test("copyObj", src, dst, 100); + } + + /** + * Tests recursive locking of objects which do not appear to be biasable. + */ + @Test + public void test5() { + char[] src = "1234567890".toCharArray(); + char[] dst = new char[src.length]; + test("copyArr", src, dst, 100); + } + + /** + * Extends {@link #test4()} with contention. + */ + @Test + public void test6() { + Chars src = new Chars("1234567890".toCharArray()); + Chars dst = new Chars(src.data.length); + int n = Runtime.getRuntime().availableProcessors(); + testN(n, "copyObj", src, dst, 100); + } + + /** + * Extends {@link #test5()} with contention. + */ + @Test + public void test7() { + char[] src = "1234567890".toCharArray(); + char[] dst = new char[src.length]; + int n = Runtime.getRuntime().availableProcessors(); + testN(n, "copyArr", src, dst, 100); + } + + private static String setAndGet(String[] box, String value) { + synchronized (box) { + box[0] = null; + } + + // Do a GC while a object is locked (by the caller) + System.gc(); + + synchronized (box) { + box[0] = value; + } + return box[0]; + } + + public static Object lockObjectSimple(Object o, Object value) { + synchronized (o) { + value.hashCode(); + return value; + } + } + + public String lockThisSimple(String value, Object o) { + synchronized (this) { + synchronized (value) { + o.hashCode(); + return value; + } + } + } + + public static String lockObject(Object o, String value, String[] box) { + synchronized (o) { + return setAndGet(box, value); + } + } + + public String lockThis(String value, String[] box) { + synchronized (this) { + return setAndGet(box, value); + } + } + + public static String lockLocalObject(String value, String[] box) { + Object o = new Object(); + synchronized (o) { + return setAndGet(box, value); + } + } + + static class Chars { + + final char[] data; + + public Chars(int size) { + this.data = new char[size]; + } + + public Chars(char[] data) { + this.data = data; + } + } + + public static String copyObj(Chars src, Chars dst, int n) { + for (int j = 0; j < n; j++) { + for (int i = 0; i < src.data.length; i++) { + synchronized (src) { + synchronized (dst) { + synchronized (src) { + synchronized (dst) { + dst.data[i] = src.data[i]; + } + } + } + } + } + } + return new String(dst.data); + } + + public static String copyArr(char[] src, char[] dst, int n) { + for (int j = 0; j < n; j++) { + for (int i = 0; i < src.length; i++) { + synchronized (src) { + synchronized (dst) { + synchronized (src) { + synchronized (dst) { + dst[i] = src[i]; + } + } + } + } + } + } + return new String(dst); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewArrayTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewArrayTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,168 @@ +/* + * Copyright (c) 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. + */ +package com.oracle.graal.replacements.test; + +import org.junit.*; + +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.test.*; + +/** + * Tests the implementation of {@code [A]NEWARRAY}. + */ +public class NewArrayTest extends GraalCompilerTest { + + @Override + protected void assertEquals(Object expected, Object actual) { + Assert.assertTrue(expected != null); + Assert.assertTrue(actual != null); + super.assertEquals(expected.getClass(), actual.getClass()); + if (expected instanceof int[]) { + Assert.assertArrayEquals((int[]) expected, (int[]) actual); + } else if (expected instanceof byte[]) { + Assert.assertArrayEquals((byte[]) expected, (byte[]) actual); + } else if (expected instanceof char[]) { + Assert.assertArrayEquals((char[]) expected, (char[]) actual); + } else if (expected instanceof short[]) { + Assert.assertArrayEquals((short[]) expected, (short[]) actual); + } else if (expected instanceof float[]) { + Assert.assertArrayEquals((float[]) expected, (float[]) actual, 0.0f); + } else if (expected instanceof long[]) { + Assert.assertArrayEquals((long[]) expected, (long[]) actual); + } else if (expected instanceof double[]) { + Assert.assertArrayEquals((double[]) expected, (double[]) actual, 0.0d); + } else if (expected instanceof Object[]) { + Assert.assertArrayEquals((Object[]) expected, (Object[]) actual); + } else { + Assert.fail("non-array value encountered: " + expected); + } + } + + @LongTest + public void test1() { + for (String type : new String[]{"Byte", "Char", "Short", "Int", "Float", "Long", "Double", "String"}) { + test("new" + type + "Array7"); + test("new" + type + "ArrayMinus7"); + test("new" + type + "Array", 7); + test("new" + type + "Array", -7); + test("new" + type + "Array", Integer.MAX_VALUE); + test("new" + type + "Array", Integer.MIN_VALUE); + } + } + + public static Object newCharArray7() { + return new char[7]; + } + + public static Object newCharArrayMinus7() { + return new char[-7]; + } + + public static Object newCharArray(int length) { + return new char[length]; + } + + public static Object newShortArray7() { + return new short[7]; + } + + public static Object newShortArrayMinus7() { + return new short[-7]; + } + + public static Object newShortArray(int length) { + return new short[length]; + } + + public static Object newFloatArray7() { + return new float[7]; + } + + public static Object newFloatArrayMinus7() { + return new float[-7]; + } + + public static Object newFloatArray(int length) { + return new float[length]; + } + + public static Object newLongArray7() { + return new long[7]; + } + + public static Object newLongArrayMinus7() { + return new long[-7]; + } + + public static Object newLongArray(int length) { + return new long[length]; + } + + public static Object newDoubleArray7() { + return new double[7]; + } + + public static Object newDoubleArrayMinus7() { + return new double[-7]; + } + + public static Object newDoubleArray(int length) { + return new double[length]; + } + + public static Object newIntArray7() { + return new int[7]; + } + + public static Object newIntArrayMinus7() { + return new int[-7]; + } + + public static Object newIntArray(int length) { + return new int[length]; + } + + public static Object newByteArray7() { + return new byte[7]; + } + + public static Object newByteArrayMinus7() { + return new byte[-7]; + } + + public static Object newByteArray(int length) { + return new byte[length]; + } + + public static Object newStringArray7() { + return new String[7]; + } + + public static Object newStringArrayMinus7() { + return new String[-7]; + } + + public static Object newStringArray(int length) { + return new String[length]; + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewInstanceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewInstanceTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,249 @@ +/* + * Copyright (c) 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. + */ +package com.oracle.graal.replacements.test; + +import java.util.*; + +import org.junit.*; + +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.test.*; + +/** + * Tests the implementation of {@code NEW}. + */ +public class NewInstanceTest extends GraalCompilerTest { + + @Override + protected void assertEquals(Object expected, Object actual) { + Assert.assertTrue(expected != null); + Assert.assertTrue(actual != null); + super.assertEquals(expected.getClass(), actual.getClass()); + + if (expected instanceof Object[]) { + Assert.assertTrue(actual instanceof Object[]); + Object[] eArr = (Object[]) expected; + Object[] aArr = (Object[]) actual; + Assert.assertTrue(eArr.length == aArr.length); + for (int i = 0; i < eArr.length; i++) { + assertEquals(eArr[i], aArr[i]); + } + } else if (expected.getClass() != Object.class) { + try { + expected.getClass().getDeclaredMethod("equals", Object.class); + super.assertEquals(expected, actual); + } catch (Exception e) { + } + } + } + + @LongTest + public void test1() { + test("newObject"); + } + + @LongTest + public void test2() { + test("newObjectTwice"); + } + + public static Object newObject() { + return new Object(); + } + + @LongTest + public void test3() { + test("newObjectLoop", 100); + } + + @LongTest + public void test4() { + test("newBigObject"); + } + + @LongTest + public void test5() { + test("newSomeObject"); + } + + @LongTest + public void test6() { + test("newEmptyString"); + } + + @LongTest + public void test7() { + test("newString", "value"); + } + + @LongTest + public void test8() { + test("newHashMap", 31); + } + + @LongTest + public void test9() { + test("newRegression", true); + } + + public static Object[] newObjectTwice() { + Object[] res = {new Object(), new Object()}; + return res; + } + + public static Object[] newObjectLoop(int n) { + Object[] res = new Object[n]; + for (int i = 0; i < n; i++) { + res[i] = new Object(); + } + return res; + } + + public static BigObject newBigObject() { + return new BigObject(); + } + + public static SomeObject newSomeObject() { + return new SomeObject(); + } + + public static String newEmptyString() { + return new String(); + } + + public static String newString(String value) { + return new String(value); + } + + public static HashMap newHashMap(int initialCapacity) { + return new HashMap(initialCapacity); + } + + static class SomeObject { + + String name = "o1"; + HashMap map = new HashMap<>(); + + public SomeObject() { + map.put(name, this.getClass()); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof SomeObject) { + SomeObject so = (SomeObject) obj; + return so.name.equals(name) && so.map.equals(map); + } + return false; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + } + + static class BigObject { + + Object f01; + Object f02; + Object f03; + Object f04; + Object f05; + Object f06; + Object f07; + Object f08; + Object f09; + Object f10; + Object f12; + Object f13; + Object f14; + Object f15; + Object f16; + Object f17; + Object f18; + Object f19; + Object f20; + Object f21; + Object f22; + Object f23; + Object f24; + Object f25; + Object f26; + Object f27; + Object f28; + Object f29; + Object f30; + Object f31; + Object f32; + Object f33; + Object f34; + Object f35; + Object f36; + Object f37; + Object f38; + Object f39; + Object f40; + Object f41; + Object f42; + Object f43; + Object f44; + Object f45; + } + + /** + * Tests that an earlier bug does not occur. The issue was that the loading of the TLAB 'top' + * and 'end' values was being GVN'ed from each branch of the 'if' statement. This meant that the + * allocated B object in the true branch overwrote the allocated array. The cause is that + * RegisterNode was a floating node and the reads from it were UnsafeLoads which are also + * floating. The fix was to make RegisterNode a fixed node (which it should have been in the + * first place). + */ + public static Object newRegression(boolean condition) { + Object result; + if (condition) { + Object[] arr = {0, 1, 2, 3, 4, 5}; + result = new B(); + for (int i = 0; i < arr.length; ++i) { + // If the bug exists, the values of arr will now be deadbeef values + // and the virtual dispatch will cause a segfault. This can result in + // either a VM crash or a spurious NullPointerException. + if (arr[i].equals(Integer.valueOf(i))) { + return false; + } + } + } else { + result = new B(); + } + return result; + } + + static class B { + + long f1 = 0xdeadbeefdeadbe01L; + long f2 = 0xdeadbeefdeadbe02L; + long f3 = 0xdeadbeefdeadbe03L; + long f4 = 0xdeadbeefdeadbe04L; + long f5 = 0xdeadbeefdeadbe05L; + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewMultiArrayTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/NewMultiArrayTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,128 @@ +/* + * 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. + */ +package com.oracle.graal.replacements.test; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; + +/** + * Tests the lowering of the MULTIANEWARRAY instruction. + */ +public class NewMultiArrayTest extends GraalCompilerTest { + + private static int rank(ResolvedJavaType type) { + String name = type.getName(); + int dims = 0; + while (dims < name.length() && name.charAt(dims) == '[') { + dims++; + } + return dims; + } + + @Override + protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) { + boolean forceCompile = false; + if (bottomType != null) { + List snapshot = graph.getNodes().filter(NewMultiArrayNode.class).snapshot(); + assert snapshot != null; + assert snapshot.size() == 1; + + NewMultiArrayNode node = snapshot.get(0); + assert rank(arrayType) == dimensions.length; + int rank = dimensions.length; + ValueNode[] dimensionNodes = new ValueNode[rank]; + for (int i = 0; i < rank; i++) { + dimensionNodes[i] = graph.unique(ConstantNode.forInt(dimensions[i], graph)); + } + + NewMultiArrayNode repl = graph.add(new NewMultiArrayNode(arrayType, dimensionNodes)); + graph.replaceFixedWithFixed(node, repl); + forceCompile = true; + } + return super.getCode(method, graph, forceCompile); + } + + @Override + protected Object referenceInvoke(Method method, Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + if (bottomType != null) { + try { + return Array.newInstance(bottomClass, dimensions); + } catch (Exception e) { + throw new InvocationTargetException(e); + } + } + return super.referenceInvoke(method, receiver, args); + } + + ResolvedJavaType arrayType; + ResolvedJavaType bottomType; + Class bottomClass; + int[] dimensions; + + @LongTest + public void test1() { + for (Class clazz : new Class[]{byte.class, char.class, short.class, int.class, float.class, long.class, double.class, String.class}) { + bottomClass = clazz; + bottomType = runtime.lookupJavaType(clazz); + arrayType = bottomType; + for (int rank : new int[]{1, 2, 10, 50, 100, 200, 254, 255}) { + while (rank(arrayType) != rank) { + arrayType = arrayType.getArrayClass(); + } + + dimensions = new int[rank]; + for (int i = 0; i < rank; i++) { + dimensions[i] = 1; + } + + test("newMultiArray"); + } + } + bottomType = null; + arrayType = null; + } + + public static Object newMultiArray() { + // This is merely a template - the NewMultiArrayNode is replaced in getCode() above. + // This also means we need a separate test for correct handling of negative dimensions + // as deoptimization won't do what we want for a graph modified to be different from the + // source bytecode. + return new Object[10][9][8]; + } + + @LongTest + public void test2() { + test("newMultiArrayException"); + } + + public static Object newMultiArrayException() { + return new Object[10][9][-8]; + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,400 @@ +/* + * 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.graal.replacements.test; + +import java.lang.reflect.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.word.*; + +/** + * Tests for the {@link Pointer} read and write operations. + */ +public class PointerTest extends GraalCompilerTest implements Snippets { + + private static final Object ID = new Object(); + private static final Kind[] KINDS = new Kind[]{Kind.Byte, Kind.Char, Kind.Short, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object}; + private final TargetDescription target; + private final ReplacementsImpl installer; + + public PointerTest() { + target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget(); + installer = new ReplacementsImpl(runtime, new Assumptions(false), target); + } + + private static final ThreadLocal inliningPolicy = new ThreadLocal<>(); + + @Override + protected StructuredGraph parse(Method m) { + ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); + return installer.makeGraph(resolvedMethod, null, inliningPolicy.get()); + } + + @Test + public void test_read1() { + for (Kind kind : KINDS) { + assertRead(parse("read" + kind.name() + "1"), kind, false, ID); + } + } + + @Test + public void test_read2() { + for (Kind kind : KINDS) { + assertRead(parse("read" + kind.name() + "2"), kind, true, ID); + } + } + + @Test + public void test_read3() { + for (Kind kind : KINDS) { + assertRead(parse("read" + kind.name() + "3"), kind, false, LocationNode.ANY_LOCATION); + } + } + + @Test + public void test_write1() { + for (Kind kind : KINDS) { + assertWrite(parse("write" + kind.name() + "1"), kind, false, ID); + } + } + + @Test + public void test_write2() { + for (Kind kind : KINDS) { + assertWrite(parse("write" + kind.name() + "2"), kind, true, ID); + } + } + + @Test + public void test_write3() { + for (Kind kind : KINDS) { + assertWrite(parse("write" + kind.name() + "3"), kind, false, LocationNode.ANY_LOCATION); + } + } + + private void assertRead(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) { + ReadNode read = (ReadNode) graph.start().next(); + Assert.assertEquals(kind.getStackKind(), read.kind()); + + UnsafeCastNode cast = (UnsafeCastNode) read.object(); + Assert.assertEquals(graph.getLocal(0), cast.object()); + Assert.assertEquals(target.wordKind, cast.kind()); + + IndexedLocationNode location = (IndexedLocationNode) read.location(); + Assert.assertEquals(kind, location.getValueKind()); + Assert.assertEquals(locationIdentity, location.locationIdentity()); + Assert.assertEquals(1, location.indexScaling()); + + if (indexConvert) { + ConvertNode convert = (ConvertNode) location.index(); + Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode); + Assert.assertEquals(graph.getLocal(1), convert.value()); + } else { + Assert.assertEquals(graph.getLocal(1), location.index()); + } + + ReturnNode ret = (ReturnNode) read.next(); + Assert.assertEquals(read, ret.result()); + } + + private void assertWrite(StructuredGraph graph, Kind kind, boolean indexConvert, Object locationIdentity) { + WriteNode write = (WriteNode) graph.start().next(); + Assert.assertEquals(graph.getLocal(2), write.value()); + Assert.assertEquals(Kind.Void, write.kind()); + Assert.assertEquals(FrameState.INVALID_FRAMESTATE_BCI, write.stateAfter().bci); + + UnsafeCastNode cast = (UnsafeCastNode) write.object(); + Assert.assertEquals(graph.getLocal(0), cast.object()); + Assert.assertEquals(target.wordKind, cast.kind()); + + IndexedLocationNode location = (IndexedLocationNode) write.location(); + Assert.assertEquals(kind, location.getValueKind()); + Assert.assertEquals(locationIdentity, location.locationIdentity()); + Assert.assertEquals(1, location.indexScaling()); + + if (indexConvert) { + ConvertNode convert = (ConvertNode) location.index(); + Assert.assertEquals(ConvertNode.Op.I2L, convert.opcode); + Assert.assertEquals(graph.getLocal(1), convert.value()); + } else { + Assert.assertEquals(graph.getLocal(1), location.index()); + } + + AbstractStateSplit stateSplit = (AbstractStateSplit) write.next(); + Assert.assertEquals(FrameState.AFTER_BCI, stateSplit.stateAfter().bci); + + ReturnNode ret = (ReturnNode) stateSplit.next(); + Assert.assertEquals(null, ret.result()); + } + + @Snippet + public static byte readByte1(Object o, int offset) { + return Word.fromObject(o).readByte(offset, ID); + } + + @Snippet + public static byte readByte2(Object o, int offset) { + return Word.fromObject(o).readByte(Word.signed(offset), ID); + } + + @Snippet + public static byte readByte3(Object o, int offset) { + return Word.fromObject(o).readByte(offset); + } + + @Snippet + public static void writeByte1(Object o, int offset, byte value) { + Word.fromObject(o).writeByte(offset, value, ID); + } + + @Snippet + public static void writeByte2(Object o, int offset, byte value) { + Word.fromObject(o).writeByte(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeByte3(Object o, int offset, byte value) { + Word.fromObject(o).writeByte(offset, value); + } + + @Snippet + public static char readChar1(Object o, int offset) { + return Word.fromObject(o).readChar(offset, ID); + } + + @Snippet + public static char readChar2(Object o, int offset) { + return Word.fromObject(o).readChar(Word.signed(offset), ID); + } + + @Snippet + public static char readChar3(Object o, int offset) { + return Word.fromObject(o).readChar(offset); + } + + @Snippet + public static void writeChar1(Object o, int offset, char value) { + Word.fromObject(o).writeChar(offset, value, ID); + } + + @Snippet + public static void writeChar2(Object o, int offset, char value) { + Word.fromObject(o).writeChar(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeChar3(Object o, int offset, char value) { + Word.fromObject(o).writeChar(offset, value); + } + + @Snippet + public static short readShort1(Object o, int offset) { + return Word.fromObject(o).readShort(offset, ID); + } + + @Snippet + public static short readShort2(Object o, int offset) { + return Word.fromObject(o).readShort(Word.signed(offset), ID); + } + + @Snippet + public static short readShort3(Object o, int offset) { + return Word.fromObject(o).readShort(offset); + } + + @Snippet + public static void writeShort1(Object o, int offset, short value) { + Word.fromObject(o).writeShort(offset, value, ID); + } + + @Snippet + public static void writeShort2(Object o, int offset, short value) { + Word.fromObject(o).writeShort(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeShort3(Object o, int offset, short value) { + Word.fromObject(o).writeShort(offset, value); + } + + @Snippet + public static int readInt1(Object o, int offset) { + return Word.fromObject(o).readInt(offset, ID); + } + + @Snippet + public static int readInt2(Object o, int offset) { + return Word.fromObject(o).readInt(Word.signed(offset), ID); + } + + @Snippet + public static int readInt3(Object o, int offset) { + return Word.fromObject(o).readInt(offset); + } + + @Snippet + public static void writeInt1(Object o, int offset, int value) { + Word.fromObject(o).writeInt(offset, value, ID); + } + + @Snippet + public static void writeInt2(Object o, int offset, int value) { + Word.fromObject(o).writeInt(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeInt3(Object o, int offset, int value) { + Word.fromObject(o).writeInt(offset, value); + } + + @Snippet + public static long readLong1(Object o, int offset) { + return Word.fromObject(o).readLong(offset, ID); + } + + @Snippet + public static long readLong2(Object o, int offset) { + return Word.fromObject(o).readLong(Word.signed(offset), ID); + } + + @Snippet + public static long readLong3(Object o, int offset) { + return Word.fromObject(o).readLong(offset); + } + + @Snippet + public static void writeLong1(Object o, int offset, long value) { + Word.fromObject(o).writeLong(offset, value, ID); + } + + @Snippet + public static void writeLong2(Object o, int offset, long value) { + Word.fromObject(o).writeLong(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeLong3(Object o, int offset, long value) { + Word.fromObject(o).writeLong(offset, value); + } + + @Snippet + public static float readFloat1(Object o, int offset) { + return Word.fromObject(o).readFloat(offset, ID); + } + + @Snippet + public static float readFloat2(Object o, int offset) { + return Word.fromObject(o).readFloat(Word.signed(offset), ID); + } + + @Snippet + public static float readFloat3(Object o, int offset) { + return Word.fromObject(o).readFloat(offset); + } + + @Snippet + public static void writeFloat1(Object o, int offset, float value) { + Word.fromObject(o).writeFloat(offset, value, ID); + } + + @Snippet + public static void writeFloat2(Object o, int offset, float value) { + Word.fromObject(o).writeFloat(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeFloat3(Object o, int offset, float value) { + Word.fromObject(o).writeFloat(offset, value); + } + + @Snippet + public static double readDouble1(Object o, int offset) { + return Word.fromObject(o).readDouble(offset, ID); + } + + @Snippet + public static double readDouble2(Object o, int offset) { + return Word.fromObject(o).readDouble(Word.signed(offset), ID); + } + + @Snippet + public static double readDouble3(Object o, int offset) { + return Word.fromObject(o).readDouble(offset); + } + + @Snippet + public static void writeDouble1(Object o, int offset, double value) { + Word.fromObject(o).writeDouble(offset, value, ID); + } + + @Snippet + public static void writeDouble2(Object o, int offset, double value) { + Word.fromObject(o).writeDouble(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeDouble3(Object o, int offset, double value) { + Word.fromObject(o).writeDouble(offset, value); + } + + @Snippet + public static Object readObject1(Object o, int offset) { + return Word.fromObject(o).readObject(offset, ID); + } + + @Snippet + public static Object readObject2(Object o, int offset) { + return Word.fromObject(o).readObject(Word.signed(offset), ID); + } + + @Snippet + public static Object readObject3(Object o, int offset) { + return Word.fromObject(o).readObject(offset); + } + + @Snippet + public static void writeObject1(Object o, int offset, Object value) { + Word.fromObject(o).writeObject(offset, value, ID); + } + + @Snippet + public static void writeObject2(Object o, int offset, Object value) { + Word.fromObject(o).writeObject(Word.signed(offset), value, ID); + } + + @Snippet + public static void writeObject3(Object o, int offset, Object value) { + Word.fromObject(o).writeObject(offset, value); + } + +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,454 @@ +/* + * 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. + */ +package com.oracle.graal.replacements.test; + +import static com.oracle.graal.graph.UnsafeAccess.*; +import static com.oracle.graal.replacements.UnsafeSubstitutions.*; + +import java.lang.reflect.*; +import java.util.concurrent.atomic.*; + +import org.junit.*; + +import sun.misc.*; + +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.nodes.*; + +/** + * Tests the VM independent {@link MethodSubstitution}s. + */ +public class StandardMethodSubstitutionsTest extends MethodSubstitutionTest { + + static long off(Object o, String name) { + try { + return unsafe.objectFieldOffset(o.getClass().getDeclaredField(name)); + } catch (Exception e) { + Assert.fail(e.toString()); + return 0L; + } + } + + static class Foo { + + boolean z; + byte b; + short s; + char c; + int i; + long l; + float f; + double d; + Object o; + + void testGet(Field field, long offset, String getName, Object value) throws Exception { + field.set(this, value); + Method m1 = Unsafe.class.getDeclaredMethod(getName, Object.class, long.class); + Method m2 = UnsafeSubstitutions.class.getDeclaredMethod(getName, Object.class, Object.class, long.class); + Object expected = m1.invoke(unsafe, this, offset); + Object actual = m2.invoke(null, unsafe, this, offset); + Assert.assertEquals(expected, actual); + } + + void testDirect(Field field, long offset, String type, Object value) throws Exception { + if (type.equals("Boolean") || type.equals("Object")) { + // No direct memory access for these types + return; + } + + long address = unsafe.allocateMemory(offset + 16); + + String getName = "get" + type; + String putName = "put" + type; + Method m1 = Unsafe.class.getDeclaredMethod(putName, long.class, field.getType()); + Method m2 = Unsafe.class.getDeclaredMethod(getName, long.class); + + Method m3 = UnsafeSubstitutions.class.getDeclaredMethod(putName, Object.class, long.class, field.getType()); + Method m4 = UnsafeSubstitutions.class.getDeclaredMethod(getName, Object.class, long.class); + + m1.invoke(unsafe, address + offset, value); + Object expected = m2.invoke(unsafe, address + offset); + + m3.invoke(null, unsafe, address + offset, value); + Object actual = m4.invoke(null, unsafe, address + offset); + + unsafe.freeMemory(address); + Assert.assertEquals(expected, actual); + } + + void testPut(Field field, long offset, String putName, Object value) throws Exception { + Object initialValue = field.get(new Foo()); + field.set(this, initialValue); + + try { + Method m1 = Unsafe.class.getDeclaredMethod(putName, Object.class, long.class, field.getType()); + Method m2 = UnsafeSubstitutions.class.getDeclaredMethod(putName, Object.class, Object.class, long.class, field.getType()); + m1.invoke(unsafe, this, offset, value); + Object expected = field.get(this); + m2.invoke(null, unsafe, this, offset, value); + Object actual = field.get(this); + Assert.assertEquals(expected, actual); + } catch (NoSuchMethodException e) { + if (!putName.startsWith("putOrdered")) { + throw e; + } + } + } + + void test(String fieldName, String typeSuffix, Object value) { + try { + Field field = Foo.class.getDeclaredField(fieldName); + long offset = unsafe.objectFieldOffset(field); + testGet(field, offset, "get" + typeSuffix, value); + testGet(field, offset, "get" + typeSuffix + "Volatile", value); + testPut(field, offset, "put" + typeSuffix, value); + testPut(field, offset, "put" + typeSuffix + "Volatile", value); + testPut(field, offset, "putOrdered" + typeSuffix, value); + testDirect(field, offset, typeSuffix, value); + } catch (Exception e) { + throw new AssertionError(e); + } + } + } + + @Test + public void testUnsafeSubstitutions() throws Exception { + test("unsafeCompareAndSwapInt"); + test("unsafeCompareAndSwapLong"); + test("unsafeCompareAndSwapObject"); + + test("unsafeGetBoolean"); + test("unsafeGetByte"); + test("unsafeGetShort"); + test("unsafeGetChar"); + test("unsafeGetInt"); + test("unsafeGetLong"); + test("unsafeGetFloat"); + test("unsafeGetDouble"); + test("unsafeGetObject"); + + test("unsafePutBoolean"); + test("unsafePutByte"); + test("unsafePutShort"); + test("unsafePutChar"); + test("unsafePutInt"); + test("unsafePutFloat"); + test("unsafePutDouble"); + test("unsafePutObject"); + + test("unsafeDirectMemoryRead"); + test("unsafeDirectMemoryWrite"); + + AtomicInteger a1 = new AtomicInteger(42); + AtomicInteger a2 = new AtomicInteger(42); + assertEquals(unsafe.compareAndSwapInt(a1, off(a1, "value"), 42, 53), compareAndSwapInt(unsafe, a2, off(a2, "value"), 42, 53)); + assertEquals(a1.get(), a2.get()); + + AtomicLong l1 = new AtomicLong(42); + AtomicLong l2 = new AtomicLong(42); + assertEquals(unsafe.compareAndSwapLong(l1, off(l1, "value"), 42, 53), compareAndSwapLong(unsafe, l2, off(l2, "value"), 42, 53)); + assertEquals(l1.get(), l2.get()); + + AtomicReference o1 = new AtomicReference<>("42"); + AtomicReference o2 = new AtomicReference<>("42"); + assertEquals(unsafe.compareAndSwapObject(o1, off(o1, "value"), "42", "53"), compareAndSwapObject(unsafe, o2, off(o2, "value"), "42", "53")); + assertEquals(o1.get(), o2.get()); + + Foo f1 = new Foo(); + f1.test("z", "Boolean", Boolean.TRUE); + f1.test("b", "Byte", Byte.MIN_VALUE); + f1.test("s", "Short", Short.MAX_VALUE); + f1.test("c", "Char", '!'); + f1.test("i", "Int", 1010010); + f1.test("f", "Float", -34.5F); + f1.test("l", "Long", 99999L); + f1.test("d", "Double", 1234.5678D); + f1.test("o", "Object", "object"); + } + + @SuppressWarnings("all") + public static boolean unsafeCompareAndSwapInt(Unsafe unsafe, Object obj, long offset) { + return unsafe.compareAndSwapInt(obj, offset, 0, 1); + } + + @SuppressWarnings("all") + public static boolean unsafeCompareAndSwapLong(Unsafe unsafe, Object obj, long offset) { + return unsafe.compareAndSwapLong(obj, offset, 0, 1); + } + + @SuppressWarnings("all") + public static boolean unsafeCompareAndSwapObject(Unsafe unsafe, Object obj, long offset) { + return unsafe.compareAndSwapObject(obj, offset, null, new Object()); + } + + @SuppressWarnings("all") + public static boolean unsafeGetBoolean(Unsafe unsafe, Object obj, long offset) { + return unsafe.getBoolean(obj, offset) && unsafe.getBooleanVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static int unsafeGetByte(Unsafe unsafe, Object obj, long offset) { + return unsafe.getByte(obj, offset) + unsafe.getByteVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static int unsafeGetShort(Unsafe unsafe, Object obj, long offset) { + return unsafe.getShort(obj, offset) + unsafe.getShortVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static int unsafeGetChar(Unsafe unsafe, Object obj, long offset) { + return unsafe.getChar(obj, offset) + unsafe.getCharVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static int unsafeGetInt(Unsafe unsafe, Object obj, long offset) { + return unsafe.getInt(obj, offset) + unsafe.getIntVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static long unsafeGetLong(Unsafe unsafe, Object obj, long offset) { + return unsafe.getLong(obj, offset) + unsafe.getLongVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static float unsafeGetFloat(Unsafe unsafe, Object obj, long offset) { + return unsafe.getFloat(obj, offset) + unsafe.getFloatVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static double unsafeGetDouble(Unsafe unsafe, Object obj, long offset) { + return unsafe.getDouble(obj, offset) + unsafe.getDoubleVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static boolean unsafeGetObject(Unsafe unsafe, Object obj, long offset) { + return unsafe.getObject(obj, offset) == unsafe.getObjectVolatile(obj, offset); + } + + @SuppressWarnings("all") + public static void unsafePutBoolean(Unsafe unsafe, Object obj, long offset, boolean value) { + unsafe.putBoolean(obj, offset, value); + unsafe.putBooleanVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutByte(Unsafe unsafe, Object obj, long offset, byte value) { + unsafe.putByte(obj, offset, value); + unsafe.putByteVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutShort(Unsafe unsafe, Object obj, long offset, short value) { + unsafe.putShort(obj, offset, value); + unsafe.putShortVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutChar(Unsafe unsafe, Object obj, long offset, char value) { + unsafe.putChar(obj, offset, value); + unsafe.putCharVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutInt(Unsafe unsafe, Object obj, long offset, int value) { + unsafe.putInt(obj, offset, value); + unsafe.putIntVolatile(obj, offset, value); + unsafe.putOrderedInt(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutLong(Unsafe unsafe, Object obj, long offset, long value) { + unsafe.putLong(obj, offset, value); + unsafe.putLongVolatile(obj, offset, value); + unsafe.putOrderedLong(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutFloat(Unsafe unsafe, Object obj, long offset, float value) { + unsafe.putFloat(obj, offset, value); + unsafe.putFloatVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutDouble(Unsafe unsafe, Object obj, long offset, double value) { + unsafe.putDouble(obj, offset, value); + unsafe.putDoubleVolatile(obj, offset, value); + } + + @SuppressWarnings("all") + public static void unsafePutObject(Unsafe unsafe, Object obj, long offset, Object value) { + unsafe.putObject(obj, offset, value); + unsafe.putObjectVolatile(obj, offset, value); + unsafe.putOrderedObject(obj, offset, value); + } + + @SuppressWarnings("all") + public static double unsafeDirectMemoryRead(Unsafe unsafe, long address) { + // Unsafe.getBoolean(long) and Unsafe.getObject(long) do not exist + return unsafe.getByte(address) + unsafe.getShort(address) + unsafe.getChar(address) + unsafe.getInt(address) + unsafe.getLong(address) + unsafe.getFloat(address) + unsafe.getDouble(address); + } + + @SuppressWarnings("all") + public static void unsafeDirectMemoryWrite(Unsafe unsafe, long address, byte value) { + // Unsafe.putBoolean(long) and Unsafe.putObject(long) do not exist + unsafe.putByte(address, value); + unsafe.putShort(address, value); + unsafe.putChar(address, (char) value); + unsafe.putInt(address, value); + unsafe.putLong(address, value); + unsafe.putFloat(address, value); + unsafe.putDouble(address, value); + } + + @Test + public void testMathSubstitutions() { + assertInGraph(assertNotInGraph(test("mathAbs"), IfNode.class), MathIntrinsicNode.class); // Java + test("math"); + + double value = 34567.891D; + assertEquals(Math.sqrt(value), MathSubstitutionsX86.sqrt(value)); + assertEquals(Math.log(value), MathSubstitutionsX86.log(value)); + assertEquals(Math.log10(value), MathSubstitutionsX86.log10(value)); + assertEquals(Math.sin(value), MathSubstitutionsX86.sin(value)); + assertEquals(Math.cos(value), MathSubstitutionsX86.cos(value)); + assertEquals(Math.tan(value), MathSubstitutionsX86.tan(value)); + } + + @SuppressWarnings("all") + public static double mathAbs(double value) { + return Math.abs(value); + } + + @SuppressWarnings("all") + public static double math(double value) { + return Math.sqrt(value) + Math.log(value) + Math.log10(value) + Math.sin(value) + Math.cos(value) + Math.tan(value); + // Math.exp(value) + + // Math.pow(value, 13); + } + + @Test + public void testIntegerSubstitutions() { + assertInGraph(test("integerReverseBytes"), ReverseBytesNode.class); // Java + assertInGraph(test("integerNumberOfLeadingZeros"), BitScanReverseNode.class); // Java + assertInGraph(test("integerNumberOfTrailingZeros"), BitScanForwardNode.class); // Java + assertInGraph(test("integerBitCount"), BitCountNode.class); // Java + + for (int i : new int[]{Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE}) { + assertEquals(Integer.reverseBytes(i), IntegerSubstitutions.reverseBytes(i)); + assertEquals(Integer.numberOfLeadingZeros(i), IntegerSubstitutions.numberOfLeadingZeros(i)); + assertEquals(Integer.numberOfTrailingZeros(i), IntegerSubstitutions.numberOfTrailingZeros(i)); + assertEquals(Integer.bitCount(i), IntegerSubstitutions.bitCount(i)); + } + } + + @SuppressWarnings("all") + public static int integerReverseBytes(int value) { + return Integer.reverseBytes(value); + } + + @SuppressWarnings("all") + public static int integerNumberOfLeadingZeros(int value) { + return Integer.numberOfLeadingZeros(value); + } + + @SuppressWarnings("all") + public static int integerNumberOfTrailingZeros(int value) { + return Integer.numberOfTrailingZeros(value); + } + + @SuppressWarnings("all") + public static int integerBitCount(int value) { + return Integer.bitCount(value); + } + + @Test + public void testLongSubstitutions() { + assertInGraph(test("longReverseBytes"), ReverseBytesNode.class); // Java + assertInGraph(test("longNumberOfLeadingZeros"), BitScanReverseNode.class); // Java + assertInGraph(test("longNumberOfTrailingZeros"), BitScanForwardNode.class); // Java + assertInGraph(test("longBitCount"), BitCountNode.class); // Java + + for (long l : new long[]{Long.MIN_VALUE, -1L, 0L, 1L, Long.MAX_VALUE}) { + assertEquals(Long.reverseBytes(l), LongSubstitutions.reverseBytes(l)); + assertEquals(Long.numberOfLeadingZeros(l), LongSubstitutions.numberOfLeadingZeros(l)); + assertEquals(Long.numberOfTrailingZeros(l), LongSubstitutions.numberOfTrailingZeros(l)); + assertEquals(Long.bitCount(l), LongSubstitutions.bitCount(l)); + } + } + + @SuppressWarnings("all") + public static long longReverseBytes(long value) { + return Long.reverseBytes(value); + } + + @SuppressWarnings("all") + public static long longNumberOfLeadingZeros(long value) { + return Long.numberOfLeadingZeros(value); + } + + @SuppressWarnings("all") + public static long longNumberOfTrailingZeros(long value) { + return Long.numberOfTrailingZeros(value); + } + + @SuppressWarnings("all") + public static int longBitCount(long value) { + return Long.bitCount(value); + } + + @Test + public void testFloatSubstitutions() { + assertInGraph(test("floatToIntBits"), ConvertNode.class); // Java + test("intBitsToFloat"); + } + + @SuppressWarnings("all") + public static int floatToIntBits(float value) { + return Float.floatToIntBits(value); + } + + @SuppressWarnings("all") + public static float intBitsToFloat(int value) { + return Float.intBitsToFloat(value); + } + + @Test + public void testDoubleSubstitutions() { + assertInGraph(test("doubleToLongBits"), ConvertNode.class); // Java + test("longBitsToDouble"); + } + + @SuppressWarnings("all") + public static long doubleToLongBits(double value) { + return Double.doubleToLongBits(value); + } + + @SuppressWarnings("all") + public static double longBitsToDouble(long value) { + return Double.longBitsToDouble(value); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/TypeCheckTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/TypeCheckTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 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. + */ +package com.oracle.graal.replacements.test; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType; +import com.oracle.graal.api.meta.ProfilingInfo.TriState; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; + +/** + * Base class for checkcast and instanceof test classes. + */ +public abstract class TypeCheckTest extends GraalCompilerTest { + + protected abstract void replaceProfile(StructuredGraph graph, JavaTypeProfile profile); + + protected JavaTypeProfile currentProfile; + + @Override + protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) { + boolean forceCompile = false; + if (currentProfile != null) { + replaceProfile(graph, currentProfile); + forceCompile = true; + } + return super.getCode(method, graph, forceCompile); + } + + protected JavaTypeProfile profile(Class... types) { + return profile(TriState.UNKNOWN, types); + } + + protected JavaTypeProfile profile(TriState nullSeen, Class... types) { + if (types.length == 0) { + return null; + } + ProfiledType[] ptypes = new ProfiledType[types.length]; + for (int i = 0; i < types.length; i++) { + ptypes[i] = new ProfiledType(runtime.lookupJavaType(types[i]), 1.0D / types.length); + } + return new JavaTypeProfile(nullSeen, 0.0D, ptypes); + } + + protected void test(String name, JavaTypeProfile profile, Object... args) { + assert currentProfile == null; + currentProfile = profile; + try { + super.test(name, args); + } finally { + currentProfile = null; + } + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,228 @@ +/* + * Copyright (c) 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. + */ +package com.oracle.graal.replacements.test; + +import java.lang.reflect.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.word.*; + +/** + * Tests for the {@link Word} type. + */ +public class WordTest extends GraalCompilerTest implements Snippets { + + private final ReplacementsImpl installer; + + public WordTest() { + TargetDescription target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget(); + installer = new ReplacementsImpl(runtime, new Assumptions(false), target); + } + + private static final ThreadLocal inliningPolicy = new ThreadLocal<>(); + + @Override + protected StructuredGraph parse(Method m) { + ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); + return installer.makeGraph(resolvedMethod, null, inliningPolicy.get()); + } + + @LongTest + public void construction() { + long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L, + Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L}; + for (long word : words) { + test("unsigned_long", word); + test("unsigned_int", (int) word); + test("signed_long", word); + test("signed_int", (int) word); + } + } + + @LongTest + public void test_arithmetic() { + long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE, Integer.MAX_VALUE - 1L, Integer.MAX_VALUE, Integer.MAX_VALUE + 1L, + Integer.MIN_VALUE - 1L, Integer.MIN_VALUE, Integer.MIN_VALUE + 1L}; + for (long word : words) { + test("unsigned_not", word); + test("signed_not", word); + for (long addend : words) { + test("unsigned_plus_int", word, (int) addend); + test("unsigned_minus_int", word, (int) addend); + test("unsigned_plus_int", word, -((int) addend)); + test("unsigned_minus_int", word, -((int) addend)); + test("unsigned_plus_long", word, addend); + test("unsigned_minus_long", word, addend); + test("unsigned_plus_long", word, -addend); + test("unsigned_minus_long", word, -addend); + test("signed_plus_int", word, (int) addend); + test("signed_minus_int", word, (int) addend); + test("signed_plus_int", word, -((int) addend)); + test("signed_minus_int", word, -((int) addend)); + test("signed_plus_long", word, addend); + test("signed_minus_long", word, addend); + test("signed_plus_long", word, -addend); + test("signed_minus_long", word, -addend); + + test("and_int", word, (int) addend); + test("or_int", word, (int) addend); + test("and_int", word, -((int) addend)); + test("or_int", word, -((int) addend)); + test("and_long", word, addend); + test("or_long", word, addend); + test("and_long", word, -addend); + test("or_long", word, -addend); + } + } + } + + @LongTest + public void test_compare() { + long[] words = new long[]{Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE}; + for (long word1 : words) { + for (long word2 : words) { + for (String method : new String[]{"aboveOrEqual", "above", "belowOrEqual", "below"}) { + test(method, word1, word2); + test(method, word2, word1); + } + } + } + } + + @Snippet + public static long unsigned_long(long word) { + return Word.unsigned(word).rawValue(); + } + + @Snippet + public static long unsigned_int(int word) { + return Word.unsigned(word).rawValue(); + } + + @Snippet + public static long signed_long(long word) { + return Word.signed(word).rawValue(); + } + + @Snippet + public static long signed_int(int word) { + return Word.signed(word).rawValue(); + } + + @Snippet + public static long unsigned_plus_int(long word, int addend) { + return Word.unsigned(word).add(addend).rawValue(); + } + + @Snippet + public static long unsigned_minus_int(long word, int addend) { + return Word.unsigned(word).subtract(addend).rawValue(); + } + + @Snippet + public static long unsigned_plus_long(long word, long addend) { + return Word.unsigned(word).add(Word.unsigned(addend)).rawValue(); + } + + @Snippet + public static long unsigned_minus_long(long word, long addend) { + return Word.unsigned(word).subtract(Word.unsigned(addend)).rawValue(); + } + + @Snippet + public static long signed_plus_int(long word, int addend) { + return Word.signed(word).add(addend).rawValue(); + } + + @Snippet + public static long signed_minus_int(long word, int addend) { + return Word.signed(word).subtract(addend).rawValue(); + } + + @Snippet + public static long signed_plus_long(long word, long addend) { + return Word.signed(word).add(Word.signed(addend)).rawValue(); + } + + @Snippet + public static long signed_minus_long(long word, long addend) { + return Word.signed(word).subtract(Word.signed(addend)).rawValue(); + } + + @Snippet + public static long signed_not(long word) { + return Word.signed(word).not().rawValue(); + } + + @Snippet + public static long unsigned_not(long word) { + return Word.unsigned(word).not().rawValue(); + } + + @Snippet + public static boolean aboveOrEqual(long word1, long word2) { + return Word.unsigned(word1).aboveOrEqual(Word.unsigned(word2)); + } + + @Snippet + public static boolean above(long word1, long word2) { + return Word.unsigned(word1).aboveThan(Word.unsigned(word2)); + } + + @Snippet + public static boolean belowOrEqual(long word1, long word2) { + return Word.unsigned(word1).belowOrEqual(Word.unsigned(word2)); + } + + @Snippet + public static boolean below(long word1, long word2) { + return Word.unsigned(word1).belowThan(Word.unsigned(word2)); + } + + @Snippet + public static long and_int(long word, int addend) { + return Word.unsigned(word).and(addend).rawValue(); + } + + @Snippet + public static long or_int(long word, int addend) { + return Word.unsigned(word).or(addend).rawValue(); + } + + @Snippet + public static long and_long(long word, long addend) { + return Word.unsigned(word).and(Word.unsigned(addend)).rawValue(); + } + + @Snippet + public static long or_long(long word, long addend) { + return Word.unsigned(word).or(Word.unsigned(addend)).rawValue(); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,243 @@ +/* + * 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. + */ +package com.oracle.graal.replacements; + +import static com.oracle.graal.replacements.SnippetTemplate.*; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.replacements.Snippet.Fold; +import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; +import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; +import com.oracle.graal.word.*; + +public class BoxingSnippets implements Snippets { + + /** + * This snippet inlining policy differs from the default one in that it does normal inlining of + * boxing methods like {@link Integer#valueOf(int)} (as opposed to method substitution). + */ + public static class BoxingSnippetInliningPolicy implements SnippetInliningPolicy { + + @Override + public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) { + if (Modifier.isNative(method.getModifiers())) { + return false; + } + if (method.getAnnotation(Fold.class) != null) { + return false; + } + if (method.getAnnotation(NodeIntrinsic.class) != null) { + return false; + } + if (method.getAnnotation(Word.Operation.class) != null) { + return false; + } + return true; + } + + @Override + public boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse) { + return false; + } + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static Boolean booleanValueOf(boolean value) { + valueOfCounter.inc(); + return UnsafeCastNode.unsafeCast(Boolean.valueOf(value), StampFactory.forNodeIntrinsic()); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static Byte byteValueOf(byte value) { + valueOfCounter.inc(); + return UnsafeCastNode.unsafeCast(Byte.valueOf(value), StampFactory.forNodeIntrinsic()); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static Character charValueOf(char value) { + valueOfCounter.inc(); + return UnsafeCastNode.unsafeCast(Character.valueOf(value), StampFactory.forNodeIntrinsic()); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static Double doubleValueOf(double value) { + valueOfCounter.inc(); + return UnsafeCastNode.unsafeCast(Double.valueOf(value), StampFactory.forNodeIntrinsic()); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static Float floatValueOf(float value) { + valueOfCounter.inc(); + return UnsafeCastNode.unsafeCast(Float.valueOf(value), StampFactory.forNodeIntrinsic()); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static Integer intValueOf(int value) { + valueOfCounter.inc(); + return UnsafeCastNode.unsafeCast(Integer.valueOf(value), StampFactory.forNodeIntrinsic()); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static Long longValueOf(long value) { + valueOfCounter.inc(); + return UnsafeCastNode.unsafeCast(Long.valueOf(value), StampFactory.forNodeIntrinsic()); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static Short shortValueOf(short value) { + valueOfCounter.inc(); + return UnsafeCastNode.unsafeCast(Short.valueOf(value), StampFactory.forNodeIntrinsic()); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static boolean booleanValue(Boolean value) { + valueOfCounter.inc(); + return value.booleanValue(); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static byte byteValue(Byte value) { + valueOfCounter.inc(); + return value.byteValue(); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static char charValue(Character value) { + valueOfCounter.inc(); + return value.charValue(); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static double doubleValue(Double value) { + valueOfCounter.inc(); + return value.doubleValue(); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static float floatValue(Float value) { + valueOfCounter.inc(); + return value.floatValue(); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static int intValue(Integer value) { + valueOfCounter.inc(); + return value.intValue(); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static long longValue(Long value) { + valueOfCounter.inc(); + return value.longValue(); + } + + @Snippet(inlining = BoxingSnippetInliningPolicy.class) + public static short shortValue(Short value) { + valueOfCounter.inc(); + return value.shortValue(); + } + + public static FloatingNode canonicalizeBoxing(BoxNode box, MetaAccessProvider runtime) { + ValueNode value = box.getValue(); + if (value.isConstant()) { + Constant sourceConstant = value.asConstant(); + switch (box.getBoxingKind()) { + case Boolean: + return ConstantNode.forObject(Boolean.valueOf(sourceConstant.asInt() != 0), runtime, box.graph()); + case Byte: + return ConstantNode.forObject(Byte.valueOf((byte) sourceConstant.asInt()), runtime, box.graph()); + case Char: + return ConstantNode.forObject(Character.valueOf((char) sourceConstant.asInt()), runtime, box.graph()); + case Short: + return ConstantNode.forObject(Short.valueOf((short) sourceConstant.asInt()), runtime, box.graph()); + case Int: + return ConstantNode.forObject(Integer.valueOf(sourceConstant.asInt()), runtime, box.graph()); + case Long: + return ConstantNode.forObject(Long.valueOf(sourceConstant.asLong()), runtime, box.graph()); + case Float: + return ConstantNode.forObject(Float.valueOf(sourceConstant.asFloat()), runtime, box.graph()); + case Double: + return ConstantNode.forObject(Double.valueOf(sourceConstant.asDouble()), runtime, box.graph()); + default: + assert false : "Unexpected source kind for boxing"; + break; + } + } + return null; + } + + public static class Templates extends AbstractTemplates { + + private final EnumMap boxSnippets = new EnumMap<>(Kind.class); + private final EnumMap unboxSnippets = new EnumMap<>(Kind.class); + + public Templates(CodeCacheProvider runtime, Replacements replacements, TargetDescription target) { + super(runtime, replacements, target); + for (Kind kind : new Kind[]{Kind.Boolean, Kind.Byte, Kind.Char, Kind.Double, Kind.Float, Kind.Int, Kind.Long, Kind.Short}) { + boxSnippets.put(kind, snippet(BoxingSnippets.class, kind.getJavaName() + "ValueOf")); + unboxSnippets.put(kind, snippet(BoxingSnippets.class, kind.getJavaName() + "Value")); + } + } + + public void lower(BoxNode box) { + FloatingNode canonical = canonicalizeBoxing(box, runtime); + if (canonical != null) { + ((StructuredGraph) box.graph()).replaceFixedWithFloating(box, canonical); + } else { + Arguments args = new Arguments(boxSnippets.get(box.getBoxingKind())); + args.add("value", box.getValue()); + + SnippetTemplate template = template(args); + Debug.log("Lowering integerValueOf in %s: node=%s, template=%s, arguments=%s", box.graph(), box, template, args); + template.instantiate(runtime, box, DEFAULT_REPLACER, args); + } + } + + public void lower(UnboxNode unbox) { + Arguments args = new Arguments(unboxSnippets.get(unbox.getBoxingKind())); + args.add("value", unbox.getValue()); + + SnippetTemplate template = template(args); + Debug.log("Lowering integerValueOf in %s: node=%s, template=%s, arguments=%s", unbox.graph(), unbox, template, args); + template.instantiate(runtime, unbox, DEFAULT_REPLACER, args); + } + } + + private static final SnippetCounter.Group integerCounters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("Integer intrinsifications") : null; + private static final SnippetCounter valueOfCounter = new SnippetCounter(integerCounters, "valueOf", "valueOf intrinsification"); + +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSubstitutions.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2012, 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. + */ +package com.oracle.graal.replacements; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.nodes.extended.*; + +public class BoxingSubstitutions { + + @ClassSubstitution(Boolean.class) + private static class BooleanSubstitutions { + + @MethodSubstitution(forced = true) + public static Boolean valueOf(boolean value) { + return BoxNode.box(value, Boolean.class, Kind.Boolean); + } + + @MethodSubstitution(isStatic = false, forced = true) + public static boolean booleanValue(Boolean value) { + return UnboxNode.unbox(value, Kind.Boolean); + } + } + + @ClassSubstitution(Byte.class) + private static class ByteSubstitutions { + + @MethodSubstitution(forced = true) + public static Byte valueOf(byte value) { + return BoxNode.box(value, Byte.class, Kind.Byte); + } + + @MethodSubstitution(isStatic = false, forced = true) + public static byte byteValue(Byte value) { + return UnboxNode.unbox(value, Kind.Byte); + } + } + + @ClassSubstitution(Character.class) + private static class CharacterSubstitutions { + + @MethodSubstitution(forced = true) + public static Character valueOf(char value) { + return BoxNode.box(value, Character.class, Kind.Char); + } + + @MethodSubstitution(isStatic = false, forced = true) + public static char charValue(Character value) { + return UnboxNode.unbox(value, Kind.Char); + } + } + + @ClassSubstitution(Double.class) + private static class DoubleSubstitutions { + + @MethodSubstitution(forced = true) + public static Double valueOf(double value) { + return BoxNode.box(value, Double.class, Kind.Double); + } + + @MethodSubstitution(isStatic = false, forced = true) + public static double doubleValue(Double value) { + return UnboxNode.unbox(value, Kind.Double); + } + } + + @ClassSubstitution(Float.class) + private static class FloatSubstitutions { + + @MethodSubstitution(forced = true) + public static Float valueOf(float value) { + return BoxNode.box(value, Float.class, Kind.Float); + } + + @MethodSubstitution(isStatic = false, forced = true) + public static float floatValue(Float value) { + return UnboxNode.unbox(value, Kind.Float); + } + } + + @ClassSubstitution(Integer.class) + private static class IntegerSubstitutions { + + @MethodSubstitution(forced = true) + public static Integer valueOf(int value) { + return BoxNode.box(value, Integer.class, Kind.Int); + } + + @MethodSubstitution(isStatic = false, forced = true) + public static int intValue(Integer value) { + return UnboxNode.unbox(value, Kind.Int); + } + } + + @ClassSubstitution(Long.class) + private static class LongSubstitutions { + + @MethodSubstitution(forced = true) + public static Long valueOf(long value) { + return BoxNode.box(value, Long.class, Kind.Long); + } + + @MethodSubstitution(isStatic = false, forced = true) + public static long longValue(Long value) { + return UnboxNode.unbox(value, Kind.Long); + } + } + + @ClassSubstitution(Short.class) + private static class ShortSubstitutions { + + @MethodSubstitution(forced = true) + public static Short valueOf(short value) { + return BoxNode.box(value, Short.class, Kind.Short); + } + + @MethodSubstitution(isStatic = false, forced = true) + public static short shortValue(Short value) { + return UnboxNode.unbox(value, Kind.Short); + } + } + + public static Class[] getClasses() { + return new Class[]{BooleanSubstitutions.class, ByteSubstitutions.class, CharacterSubstitutions.class, DoubleSubstitutions.class, FloatSubstitutions.class, IntegerSubstitutions.class, + LongSubstitutions.class, ShortSubstitutions.class}; + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java Mon Apr 15 08:51:19 2013 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.replacements; import com.oracle.graal.api.runtime.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; /** @@ -31,15 +32,19 @@ @ServiceProvider(ReplacementsProvider.class) public class GraalMethodSubstitutions implements ReplacementsProvider { - public void installReplacements(ReplacementsInstaller installer) { + public void registerReplacements(Replacements replacements) { + for (Class clazz : BoxingSubstitutions.getClasses()) { + replacements.registerSubstitutions(clazz); + } + if (GraalOptions.Intrinsify) { - installer.installSubstitutions(MathSubstitutionsX86.class); - installer.installSubstitutions(DoubleSubstitutions.class); - installer.installSubstitutions(FloatSubstitutions.class); - installer.installSubstitutions(NodeClassSubstitutions.class); - installer.installSubstitutions(LongSubstitutions.class); - installer.installSubstitutions(IntegerSubstitutions.class); - installer.installSubstitutions(UnsignedMathSubstitutions.class); + replacements.registerSubstitutions(MathSubstitutionsX86.class); + replacements.registerSubstitutions(DoubleSubstitutions.class); + replacements.registerSubstitutions(FloatSubstitutions.class); + replacements.registerSubstitutions(NodeClassSubstitutions.class); + replacements.registerSubstitutions(LongSubstitutions.class); + replacements.registerSubstitutions(IntegerSubstitutions.class); + replacements.registerSubstitutions(UnsignedMathSubstitutions.class); } } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java Mon Apr 15 08:51:19 2013 +0200 @@ -34,7 +34,9 @@ import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; -import com.oracle.graal.replacements.SnippetTemplate.*; +import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; +import com.oracle.graal.replacements.SnippetTemplate.Arguments; +import com.oracle.graal.replacements.SnippetTemplate.UsageReplacer; /** * Helper class for lowering {@link InstanceOfNode}s with snippets. The majority of the complexity @@ -49,31 +51,16 @@ * {@link IfNode}. This avoids materializing the instanceof test as a boolean which is then retested * by the {@link IfNode}. */ -public abstract class InstanceOfSnippetsTemplates extends AbstractTemplates { +public abstract class InstanceOfSnippetsTemplates extends AbstractTemplates { - public InstanceOfSnippetsTemplates(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target, Class snippetsClass) { - super(runtime, assumptions, target, snippetsClass); + public InstanceOfSnippetsTemplates(MetaAccessProvider runtime, Replacements replacements, TargetDescription target) { + super(runtime, replacements, target); } /** - * The key and arguments used to retrieve and instantiate an instanceof snippet template. + * Gets the arguments used to retrieve and instantiate an instanceof snippet template. */ - public static class KeyAndArguments { - - public final Key key; - public final Arguments arguments; - - public KeyAndArguments(Key key, Arguments arguments) { - this.key = key; - this.arguments = arguments; - } - - } - - /** - * Gets the key and arguments used to retrieve and instantiate an instanceof snippet template. - */ - protected abstract KeyAndArguments getKeyAndArguments(InstanceOfUsageReplacer replacer, LoweringTool tool); + protected abstract Arguments makeArguments(InstanceOfUsageReplacer replacer, LoweringTool tool); public void lower(FloatingNode instanceOf, LoweringTool tool) { assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode; @@ -90,9 +77,8 @@ // No need to re-instantiate the snippet - just re-use its result replacer.replaceUsingInstantiation(); } else { - KeyAndArguments keyAndArguments = getKeyAndArguments(replacer, tool); - SnippetTemplate template = cache.get(keyAndArguments.key, assumptions); - template.instantiate(runtime, instanceOf, replacer, tool, keyAndArguments.arguments); + Arguments args = makeArguments(replacer, tool); + template(args).instantiate(runtime, instanceOf, replacer, tool, args); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MacroSubstitution.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MacroSubstitution.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +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. - */ -package com.oracle.graal.replacements; - -import java.lang.annotation.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.replacements.nodes.*; - -/** - * Denotes a macro substitute method. This replaces a method invocation with an instance of the - * specified node class. - * - * A macro substitution can be combined with a normal substitution, so that the macro node can be - * replaced with the actual substitution code during lowering. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface MacroSubstitution { - - /** - * Gets the name of the substituted method. - *

- * If the default value is specified for this element, then the name of the substituted method - * is same as the substitute method. - */ - String value() default ""; - - /** - * Determines if the substituted method is static. - */ - boolean isStatic() default true; - - /** - * Gets the {@linkplain MetaUtil#signatureToMethodDescriptor signature} of the substituted - * method. - *

- * If the default value is specified for this element, then the signature of the substituted - * method is the same as the substitute method. - */ - String signature() default ""; - - /** - * The node class with which the method invocation should be replaced. It needs to be a subclass - * of {@link FixedWithNextNode}, and it is expected to provide a public constructor that takes - * an InvokeNode as a parameter. For most cases this class should subclass {@link MacroNode} and - * use its constructor. - */ - Class macro(); -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,22 +22,22 @@ */ package com.oracle.graal.replacements; -import static com.oracle.graal.api.meta.MetaUtil.*; - import java.lang.reflect.*; import java.util.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; -import com.oracle.graal.replacements.Snippet.*; +import com.oracle.graal.replacements.Snippet.Fold; /** * Replaces calls to {@link NodeIntrinsic}s with nodes and calls to methods annotated with @@ -46,90 +46,77 @@ public class NodeIntrinsificationPhase extends Phase { private final MetaAccessProvider runtime; - private final BoxingMethodPool pool; - public NodeIntrinsificationPhase(MetaAccessProvider runtime, BoxingMethodPool pool) { + public NodeIntrinsificationPhase(MetaAccessProvider runtime) { this.runtime = runtime; - this.pool = pool; } @Override protected void run(StructuredGraph graph) { + ArrayList cleanUpReturnList = new ArrayList<>(); for (Invoke i : graph.getInvokes()) { if (i.callTarget() instanceof MethodCallTargetNode) { - tryIntrinsify(i); + tryIntrinsify(i, cleanUpReturnList); } } + + for (Node node : cleanUpReturnList) { + cleanUpReturnCheckCast(node); + } } - public static Class[] signatureToTypes(Signature signature, JavaType receiverType, ResolvedJavaType accessingClass) { - int count = signature.getParameterCount(receiverType != null); - Class[] result = new Class[count]; - int j = 0; - if (receiverType != null) { - result[0] = getMirrorOrFail(receiverType.resolve(accessingClass), Thread.currentThread().getContextClassLoader()); - j = 1; - } - for (int i = 0; i + j < result.length; ++i) { - result[i + j] = getMirrorOrFail(signature.getParameterType(i, accessingClass).resolve(accessingClass), Thread.currentThread().getContextClassLoader()); - } - return result; - } - - private boolean tryIntrinsify(Invoke invoke) { + private boolean tryIntrinsify(Invoke invoke, List cleanUpReturnList) { ResolvedJavaMethod target = invoke.methodCallTarget().targetMethod(); NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class); ResolvedJavaType declaringClass = target.getDeclaringClass(); - JavaType receiverType = invoke.methodCallTarget().isStatic() ? null : declaringClass; if (intrinsic != null) { assert target.getAnnotation(Fold.class) == null; + assert Modifier.isStatic(target.getModifiers()) : "node intrinsic must be static: " + target; - // TODO mjj non-static intrinsic? - Class[] parameterTypes = signatureToTypes(target.getSignature(), null, declaringClass); + ResolvedJavaType[] parameterTypes = MetaUtil.resolveJavaTypes(MetaUtil.signatureToTypes(target), declaringClass); ResolvedJavaType returnType = target.getSignature().getReturnType(declaringClass).resolve(declaringClass); // Prepare the arguments for the reflective constructor call on the node class. - Object[] nodeConstructorArguments = prepareArguments(invoke, parameterTypes, target, false); + Constant[] nodeConstructorArguments = prepareArguments(invoke, parameterTypes, target, false); if (nodeConstructorArguments == null) { return false; } // Create the new node instance. - Class c = getNodeClass(target, intrinsic); - Node newInstance = createNodeInstance(runtime, c, parameterTypes, returnType, intrinsic.setStampFromReturnType(), nodeConstructorArguments); + ResolvedJavaType c = getNodeClass(target, intrinsic); + Node newInstance = createNodeInstance(c, parameterTypes, returnType, intrinsic.setStampFromReturnType(), nodeConstructorArguments); // Replace the invoke with the new node. - invoke.node().graph().add(newInstance); + invoke.asNode().graph().add(newInstance); invoke.intrinsify(newInstance); // Clean up checkcast instructions inserted by javac if the return type is generic. - cleanUpReturnCheckCast(newInstance); + cleanUpReturnList.add(newInstance); } else if (target.getAnnotation(Fold.class) != null) { - Class[] parameterTypes = signatureToTypes(target.getSignature(), receiverType, declaringClass); + ResolvedJavaType[] parameterTypes = MetaUtil.resolveJavaTypes(MetaUtil.signatureToTypes(target), declaringClass); // Prepare the arguments for the reflective method call - Object[] arguments = prepareArguments(invoke, parameterTypes, target, true); + Constant[] arguments = prepareArguments(invoke, parameterTypes, target, true); if (arguments == null) { return false; } - Object receiver = null; + Constant receiver = null; if (!invoke.methodCallTarget().isStatic()) { receiver = arguments[0]; - arguments = Arrays.asList(arguments).subList(1, arguments.length).toArray(); - parameterTypes = Arrays.asList(parameterTypes).subList(1, parameterTypes.length).toArray(new Class[parameterTypes.length - 1]); + arguments = Arrays.copyOfRange(arguments, 1, arguments.length); + parameterTypes = Arrays.copyOfRange(parameterTypes, 1, parameterTypes.length); } // Call the method - Constant constant = callMethod(target.getSignature().getReturnKind(), getMirrorOrFail(declaringClass, Thread.currentThread().getContextClassLoader()), target.getName(), parameterTypes, - receiver, arguments); + Constant constant = target.invoke(receiver, arguments); if (constant != null) { // Replace the invoke with the result of the call - ConstantNode node = ConstantNode.forConstant(constant, runtime, invoke.node().graph()); + ConstantNode node = ConstantNode.forConstant(constant, runtime, invoke.asNode().graph()); invoke.intrinsify(node); // Clean up checkcast instructions inserted by javac if the return type is generic. - cleanUpReturnCheckCast(node); + cleanUpReturnList.add(node); } else { // Remove the invoke invoke.intrinsify(null); @@ -146,15 +133,15 @@ * @return the arguments for the reflective invocation or null if an argument of {@code invoke} * that is expected to be constant isn't */ - private Object[] prepareArguments(Invoke invoke, Class[] parameterTypes, ResolvedJavaMethod target, boolean folding) { + private Constant[] prepareArguments(Invoke invoke, ResolvedJavaType[] parameterTypes, ResolvedJavaMethod target, boolean folding) { NodeInputList arguments = invoke.callTarget().arguments(); - Object[] reflectionCallArguments = new Object[arguments.size()]; + Constant[] reflectionCallArguments = new Constant[arguments.size()]; for (int i = 0; i < reflectionCallArguments.length; ++i) { int parameterIndex = i; if (!invoke.methodCallTarget().isStatic()) { parameterIndex--; } - ValueNode argument = tryBoxingElimination(parameterIndex, target, arguments.get(i)); + ValueNode argument = arguments.get(i); if (folding || MetaUtil.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex, target) != null) { if (!(argument instanceof ConstantNode)) { return null; @@ -163,171 +150,63 @@ Constant constant = constantNode.asConstant(); Object o = constant.asBoxedValue(); if (o instanceof Class) { - reflectionCallArguments[i] = runtime.lookupJavaType((Class) o); - parameterTypes[i] = ResolvedJavaType.class; + reflectionCallArguments[i] = Constant.forObject(runtime.lookupJavaType((Class) o)); + parameterTypes[i] = runtime.lookupJavaType(ResolvedJavaType.class); } else { - if (parameterTypes[i] == boolean.class) { - reflectionCallArguments[i] = Boolean.valueOf(constant.asInt() != 0); - } else if (parameterTypes[i] == byte.class) { - reflectionCallArguments[i] = Byte.valueOf((byte) constant.asInt()); - } else if (parameterTypes[i] == short.class) { - reflectionCallArguments[i] = Short.valueOf((short) constant.asInt()); - } else if (parameterTypes[i] == char.class) { - reflectionCallArguments[i] = Character.valueOf((char) constant.asInt()); + if (parameterTypes[i].getKind() == Kind.Boolean) { + reflectionCallArguments[i] = Constant.forObject(Boolean.valueOf(constant.asInt() != 0)); + } else if (parameterTypes[i].getKind() == Kind.Byte) { + reflectionCallArguments[i] = Constant.forObject(Byte.valueOf((byte) constant.asInt())); + } else if (parameterTypes[i].getKind() == Kind.Short) { + reflectionCallArguments[i] = Constant.forObject(Short.valueOf((short) constant.asInt())); + } else if (parameterTypes[i].getKind() == Kind.Char) { + reflectionCallArguments[i] = Constant.forObject(Character.valueOf((char) constant.asInt())); } else { - reflectionCallArguments[i] = o; + reflectionCallArguments[i] = constant; } } } else { - reflectionCallArguments[i] = argument; - parameterTypes[i] = ValueNode.class; + reflectionCallArguments[i] = Constant.forObject(argument); + parameterTypes[i] = runtime.lookupJavaType(ValueNode.class); } } return reflectionCallArguments; } - private static Class getNodeClass(ResolvedJavaMethod target, NodeIntrinsic intrinsic) { - Class result = intrinsic.value(); - if (result == NodeIntrinsic.class) { - return getMirrorOrFail(target.getDeclaringClass(), Thread.currentThread().getContextClassLoader()); + private ResolvedJavaType getNodeClass(ResolvedJavaMethod target, NodeIntrinsic intrinsic) { + ResolvedJavaType result; + if (intrinsic.value() == NodeIntrinsic.class) { + result = target.getDeclaringClass(); + } else { + result = runtime.lookupJavaType(intrinsic.value()); } - assert Node.class.isAssignableFrom(result); + assert runtime.lookupJavaType(ValueNode.class).isAssignableFrom(result); return result; } - private ValueNode tryBoxingElimination(int parameterIndex, ResolvedJavaMethod target, ValueNode node) { - if (parameterIndex >= 0) { - Type type = target.getGenericParameterTypes()[parameterIndex]; - if (type instanceof TypeVariable) { - TypeVariable typeVariable = (TypeVariable) type; - if (typeVariable.getBounds().length == 1) { - Type boundType = typeVariable.getBounds()[0]; - if (boundType instanceof Class && ((Class) boundType).getSuperclass() == null) { - // Unbound generic => try boxing elimination - if (node.usages().count() == 2) { - if (node instanceof Invoke) { - Invoke invokeNode = (Invoke) node; - MethodCallTargetNode callTarget = invokeNode.methodCallTarget(); - if (pool.isBoxingMethod(callTarget.targetMethod())) { - FrameState stateAfter = invokeNode.stateAfter(); - assert stateAfter.usages().count() == 1; - invokeNode.node().replaceAtUsages(null); - ValueNode result = callTarget.arguments().get(0); - StructuredGraph graph = (StructuredGraph) node.graph(); - if (invokeNode instanceof InvokeWithExceptionNode) { - // Destroy exception edge & clear stateAfter. - InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode; + private Node createNodeInstance(ResolvedJavaType nodeClass, ResolvedJavaType[] parameterTypes, ResolvedJavaType returnType, boolean setStampFromReturnType, Constant[] nodeConstructorArguments) { + ResolvedJavaMethod constructor = null; + Constant[] arguments = null; - invokeWithExceptionNode.killExceptionEdge(); - graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next()); - } else { - graph.removeFixed((InvokeNode) invokeNode); - } - stateAfter.safeDelete(); - GraphUtil.propagateKill(callTarget); - return result; - } - } - } - } - } - } - } - return node; - } - - private static Class asBoxedType(Class type) { - if (!type.isPrimitive()) { - return type; - } + for (ResolvedJavaMethod c : nodeClass.getDeclaredConstructors()) { + Constant[] match = match(c, parameterTypes, nodeConstructorArguments); - if (Boolean.TYPE == type) { - return Boolean.class; - } - if (Character.TYPE == type) { - return Character.class; - } - if (Byte.TYPE == type) { - return Byte.class; - } - if (Short.TYPE == type) { - return Short.class; - } - if (Integer.TYPE == type) { - return Integer.class; - } - if (Long.TYPE == type) { - return Long.class; - } - if (Float.TYPE == type) { - return Float.class; - } - assert Double.TYPE == type; - return Double.class; - } - - static final int VARARGS = 0x00000080; - - private static Node createNodeInstance(MetaAccessProvider runtime, Class nodeClass, Class[] parameterTypes, ResolvedJavaType returnType, boolean setStampFromReturnType, - Object[] nodeConstructorArguments) { - Object[] arguments = null; - Constructor constructor = null; - boolean needsMetaAccessProviderArgument = false; - nextConstructor: for (Constructor c : nodeClass.getDeclaredConstructors()) { - needsMetaAccessProviderArgument = false; - Class[] signature = c.getParameterTypes(); - if (signature.length != 0 && signature[0] == MetaAccessProvider.class) { - // Chop off the MetaAccessProvider first parameter - signature = Arrays.copyOfRange(signature, 1, signature.length); - needsMetaAccessProviderArgument = true; - } - if ((c.getModifiers() & VARARGS) != 0) { - int fixedArgs = signature.length - 1; - if (parameterTypes.length < fixedArgs) { - continue nextConstructor; + if (match != null) { + if (constructor == null) { + constructor = c; + arguments = match; + } else { + throw new GraalInternalError("Found multiple constructors in " + nodeClass + " compatible with signature " + Arrays.toString(parameterTypes) + ": " + constructor + ", " + c); } - - for (int i = 0; i < fixedArgs; i++) { - if (!parameterTypes[i].equals(signature[i])) { - continue nextConstructor; - } - } - - Class componentType = signature[fixedArgs].getComponentType(); - assert componentType != null : "expected last parameter of varargs constructor " + c + " to be an array type"; - Class boxedType = asBoxedType(componentType); - for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) { - if (!boxedType.isInstance(nodeConstructorArguments[i])) { - continue nextConstructor; - } - } - arguments = Arrays.copyOf(nodeConstructorArguments, fixedArgs + 1); - int varargsLength = nodeConstructorArguments.length - fixedArgs; - Object varargs = Array.newInstance(componentType, varargsLength); - for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) { - Array.set(varargs, i - fixedArgs, nodeConstructorArguments[i]); - } - arguments[fixedArgs] = varargs; - constructor = c; - break; - } else if (Arrays.equals(parameterTypes, signature)) { - arguments = nodeConstructorArguments; - constructor = c; - break; } } if (constructor == null) { throw new GraalInternalError("Could not find constructor in " + nodeClass + " compatible with signature " + Arrays.toString(parameterTypes)); } - if (needsMetaAccessProviderArgument) { - Object[] copy = new Object[arguments.length + 1]; - System.arraycopy(arguments, 0, copy, 1, arguments.length); - copy[0] = runtime; - arguments = copy; - } - constructor.setAccessible(true); + try { - ValueNode intrinsicNode = (ValueNode) constructor.newInstance(arguments); + ValueNode intrinsicNode = (ValueNode) constructor.newInstance(arguments).asObject(); + if (setStampFromReturnType) { if (returnType.getKind() == Kind.Object) { intrinsicNode.setStamp(StampFactory.declared(returnType)); @@ -341,26 +220,58 @@ } } - /** - * Calls a Java method via reflection. - */ - private static Constant callMethod(Kind returnKind, Class holder, String name, Class[] parameterTypes, Object receiver, Object[] arguments) { - Method method; - try { - method = holder.getDeclaredMethod(name, parameterTypes); - method.setAccessible(true); - } catch (Exception e) { - throw new RuntimeException(e); + private Constant[] match(ResolvedJavaMethod c, ResolvedJavaType[] parameterTypes, Constant[] nodeConstructorArguments) { + Constant[] arguments = null; + boolean needsMetaAccessProviderArgument = false; + + ResolvedJavaType[] signature = MetaUtil.resolveJavaTypes(MetaUtil.signatureToTypes(c.getSignature(), null), c.getDeclaringClass()); + if (signature.length != 0 && signature[0].equals(runtime.lookupJavaType(MetaAccessProvider.class))) { + // Chop off the MetaAccessProvider first parameter + signature = Arrays.copyOfRange(signature, 1, signature.length); + needsMetaAccessProviderArgument = true; } - try { - Object result = method.invoke(receiver, arguments); - if (result == null) { + + if (Arrays.equals(parameterTypes, signature)) { + // Exact match + arguments = nodeConstructorArguments; + + } else if (signature.length > 0 && signature[signature.length - 1].isArray()) { + // Last constructor parameter is an array, so check if we have a vararg match + int fixedArgs = signature.length - 1; + if (parameterTypes.length < fixedArgs) { return null; } - return Constant.forBoxed(returnKind, result); - } catch (Exception e) { - throw new RuntimeException(e); + for (int i = 0; i < fixedArgs; i++) { + if (!parameterTypes[i].equals(signature[i])) { + return null; + } + } + + ResolvedJavaType componentType = signature[fixedArgs].getComponentType(); + assert componentType != null; + for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) { + if (!parameterTypes[i].equals(componentType)) { + return null; + } + } + arguments = Arrays.copyOf(nodeConstructorArguments, fixedArgs + 1); + arguments[fixedArgs] = componentType.newArray(nodeConstructorArguments.length - fixedArgs); + + Object varargs = arguments[fixedArgs].asObject(); + for (int i = fixedArgs; i < nodeConstructorArguments.length; i++) { + Array.set(varargs, i - fixedArgs, nodeConstructorArguments[i].asBoxedValue()); + } + } else { + return null; } + + if (needsMetaAccessProviderArgument) { + Constant[] copy = new Constant[arguments.length + 1]; + System.arraycopy(arguments, 0, copy, 1, arguments.length); + copy[0] = Constant.forObject(runtime); + arguments = copy; + } + return arguments; } private static String sourceLocation(Node n) { @@ -379,32 +290,25 @@ if (checkCastUsage instanceof ValueAnchorNode) { ValueAnchorNode valueAnchorNode = (ValueAnchorNode) checkCastUsage; graph.removeFixed(valueAnchorNode); + } else if (checkCastUsage instanceof UnboxNode) { + UnboxNode unbox = (UnboxNode) checkCastUsage; + unbox.replaceAtUsages(newInstance); + graph.removeFixed(unbox); } else if (checkCastUsage instanceof MethodCallTargetNode) { MethodCallTargetNode checkCastCallTarget = (MethodCallTargetNode) checkCastUsage; - if (pool.isUnboxingMethod(checkCastCallTarget.targetMethod())) { - Invoke invokeNode = checkCastCallTarget.invoke(); - invokeNode.node().replaceAtUsages(newInstance); - if (invokeNode instanceof InvokeWithExceptionNode) { - // Destroy exception edge & clear stateAfter. - InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode; - - invokeWithExceptionNode.killExceptionEdge(); - graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next()); - } else { - graph.removeFixed((InvokeNode) invokeNode); - } - checkCastCallTarget.safeDelete(); - } else { - assert checkCastCallTarget.targetMethod().getAnnotation(NodeIntrinsic.class) != null : "checkcast at " + sourceLocation(checkCastNode) + - " not used by an unboxing method or node intrinsic, but by a call at " + sourceLocation(checkCastCallTarget.usages().first()) + " to " + - checkCastCallTarget.targetMethod(); - checkCastUsage.replaceFirstInput(checkCastNode, checkCastNode.object()); - } + assert checkCastCallTarget.targetMethod().getAnnotation(NodeIntrinsic.class) != null : "checkcast at " + sourceLocation(checkCastNode) + + " not used by an unboxing method or node intrinsic, but by a call at " + sourceLocation(checkCastCallTarget.usages().first()) + " to " + + checkCastCallTarget.targetMethod(); + checkCastUsage.replaceFirstInput(checkCastNode, checkCastNode.object()); } else if (checkCastUsage instanceof FrameState) { checkCastUsage.replaceFirstInput(checkCastNode, null); } else if (checkCastUsage instanceof ReturnNode && checkCastNode.object().stamp() == StampFactory.forNodeIntrinsic()) { checkCastUsage.replaceFirstInput(checkCastNode, checkCastNode.object()); + } else if (checkCastUsage instanceof IsNullNode) { + assert checkCastUsage.usages().count() == 1 && checkCastUsage.usages().first().predecessor() == checkCastNode; + graph.replaceFloating((FloatingNode) checkCastUsage, LogicConstantNode.contradiction(graph)); } else { + Debug.dump(graph, "exception"); assert false : sourceLocation(checkCastUsage) + " has unexpected usage " + checkCastUsage + " of checkcast at " + sourceLocation(checkCastNode); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,483 @@ +/* + * 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. + */ +package com.oracle.graal.replacements; + +import static com.oracle.graal.api.meta.MetaUtil.*; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; + +import sun.misc.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.replacements.Snippet.DefaultSnippetInliningPolicy; +import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; +import com.oracle.graal.word.phases.*; + +public class ReplacementsImpl implements Replacements { + + protected final MetaAccessProvider runtime; + protected final TargetDescription target; + protected final Assumptions assumptions; + + /** + * The preprocessed replacement graphs. + */ + private final ConcurrentMap graphs; + + // These data structures are all fully initialized during single-threaded + // compiler startup and so do not need to be concurrent. + private final Map registeredMethodSubstitutions; + private final Map> registerMacroSubstitutions; + private final Set forcedSubstitutions; + + public ReplacementsImpl(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target) { + this.runtime = runtime; + this.target = target; + this.assumptions = assumptions; + this.graphs = new ConcurrentHashMap<>(); + this.registeredMethodSubstitutions = new HashMap<>(); + this.registerMacroSubstitutions = new HashMap<>(); + this.forcedSubstitutions = new HashSet<>(); + } + + public StructuredGraph getSnippet(ResolvedJavaMethod method) { + assert method.getAnnotation(Snippet.class) != null : "Snippet must be annotated with @" + Snippet.class.getSimpleName(); + assert !Modifier.isAbstract(method.getModifiers()) && !Modifier.isNative(method.getModifiers()) : "Snippet must not be abstract or native"; + + StructuredGraph graph = graphs.get(method); + if (graph == null) { + graphs.putIfAbsent(method, makeGraph(method, null, inliningPolicy(method))); + graph = graphs.get(method); + } + return graph; + } + + public StructuredGraph getMethodSubstitution(ResolvedJavaMethod original) { + ResolvedJavaMethod substitute = registeredMethodSubstitutions.get(original); + if (substitute == null) { + return null; + } + StructuredGraph graph = graphs.get(substitute); + if (graph == null) { + graphs.putIfAbsent(substitute, makeGraph(substitute, original, inliningPolicy(substitute))); + graph = graphs.get(substitute); + } + return graph; + + } + + public Class getMacroSubstitution(ResolvedJavaMethod method) { + return registerMacroSubstitutions.get(method); + } + + public Assumptions getAssumptions() { + return assumptions; + } + + public void registerSubstitutions(Class substitutions) { + ClassSubstitution classSubstitution = substitutions.getAnnotation(ClassSubstitution.class); + assert classSubstitution != null; + assert !Snippets.class.isAssignableFrom(substitutions); + for (Method substituteMethod : substitutions.getDeclaredMethods()) { + MethodSubstitution methodSubstitution = substituteMethod.getAnnotation(MethodSubstitution.class); + MacroSubstitution macroSubstitution = substituteMethod.getAnnotation(MacroSubstitution.class); + if (methodSubstitution == null && macroSubstitution == null) { + continue; + } + + int modifiers = substituteMethod.getModifiers(); + if (!Modifier.isStatic(modifiers)) { + throw new RuntimeException("Substitution methods must be static: " + substituteMethod); + } + + if (methodSubstitution != null) { + if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + throw new RuntimeException("Substitution method must not be abstract or native: " + substituteMethod); + } + String originalName = originalName(substituteMethod, methodSubstitution.value()); + Class[] originalParameters = originalParameters(substituteMethod, methodSubstitution.signature(), methodSubstitution.isStatic()); + Member originalMethod = originalMethod(classSubstitution, methodSubstitution.optional(), originalName, originalParameters); + if (originalMethod != null) { + ResolvedJavaMethod original = registerMethodSubstitution(originalMethod, substituteMethod); + if (original != null && methodSubstitution.forced()) { + forcedSubstitutions.add(original); + } + } + } + if (macroSubstitution != null) { + String originalName = originalName(substituteMethod, macroSubstitution.value()); + Class[] originalParameters = originalParameters(substituteMethod, macroSubstitution.signature(), macroSubstitution.isStatic()); + Member originalMethod = originalMethod(classSubstitution, macroSubstitution.optional(), originalName, originalParameters); + if (originalMethod != null) { + ResolvedJavaMethod original = registerMacroSubstitution(originalMethod, macroSubstitution.macro()); + if (original != null && macroSubstitution.forced()) { + forcedSubstitutions.add(original); + } + } + } + } + } + + /** + * Registers a method substitution. + * + * @param originalMember a method or constructor being substituted + * @param substituteMethod the substitute method + * @return the original method + */ + protected ResolvedJavaMethod registerMethodSubstitution(Member originalMember, Method substituteMethod) { + ResolvedJavaMethod substitute = runtime.lookupJavaMethod(substituteMethod); + ResolvedJavaMethod original; + if (originalMember instanceof Method) { + original = runtime.lookupJavaMethod((Method) originalMember); + } else { + original = runtime.lookupJavaConstructor((Constructor) originalMember); + } + Debug.log("substitution: " + MetaUtil.format("%H.%n(%p)", original) + " --> " + MetaUtil.format("%H.%n(%p)", substitute)); + + registeredMethodSubstitutions.put(original, substitute); + return original; + } + + /** + * Registers a macro substitution. + * + * @param originalMethod a method or constructor being substituted + * @param macro the substitute macro node class + * @return the original method + */ + protected ResolvedJavaMethod registerMacroSubstitution(Member originalMethod, Class macro) { + ResolvedJavaMethod originalJavaMethod; + if (originalMethod instanceof Method) { + originalJavaMethod = runtime.lookupJavaMethod((Method) originalMethod); + } else { + originalJavaMethod = runtime.lookupJavaConstructor((Constructor) originalMethod); + } + registerMacroSubstitutions.put(originalJavaMethod, macro); + return originalJavaMethod; + } + + private SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) { + Class policyClass = SnippetInliningPolicy.class; + Snippet snippet = method.getAnnotation(Snippet.class); + if (snippet != null) { + policyClass = snippet.inlining(); + } + if (policyClass == SnippetInliningPolicy.class) { + return new DefaultSnippetInliningPolicy(runtime); + } + try { + return policyClass.getConstructor().newInstance(); + } catch (Exception e) { + throw new GraalInternalError(e); + } + } + + /** + * Creates a preprocessed graph for a snippet or method substitution. + * + * @param method the snippet or method substitution for which a graph will be created + * @param original the original method if {@code method} is a {@linkplain MethodSubstitution + * substitution} otherwise null + * @param policy the inlining policy to use during preprocessing + */ + public StructuredGraph makeGraph(ResolvedJavaMethod method, ResolvedJavaMethod original, SnippetInliningPolicy policy) { + return createGraphMaker(method, original).makeGraph(policy); + } + + /** + * Can be overridden to return an object that specializes various parts of graph preprocessing. + */ + protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original) { + return new GraphMaker(substitute, original); + } + + /** + * Cache to speed up preprocessing of replacement graphs. + */ + final ConcurrentMap graphCache = new ConcurrentHashMap<>(); + + /** + * Creates and preprocesses a graph for a replacement. + */ + protected class GraphMaker { + + /** + * The method for which a graph is being created. + */ + protected final ResolvedJavaMethod method; + + /** + * The original method if {@link #method} is a {@linkplain MethodSubstitution substitution} + * otherwise null. + */ + protected final ResolvedJavaMethod original; + + boolean substituteCallsOriginal; + + protected GraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original) { + this.method = substitute; + this.original = original; + } + + public StructuredGraph makeGraph(final SnippetInliningPolicy policy) { + return Debug.scope("BuildSnippetGraph", new Object[]{method}, new Callable() { + + @Override + public StructuredGraph call() throws Exception { + StructuredGraph graph = parseGraph(method, policy); + + // Cannot have a finalized version of a graph in the cache + graph = graph.copy(); + + finalizeGraph(graph); + + Debug.dump(graph, "%s: Final", method.getName()); + + return graph; + } + }); + } + + /** + * Does final processing of a snippet graph. + */ + protected void finalizeGraph(StructuredGraph graph) { + new NodeIntrinsificationPhase(runtime).apply(graph); + assert SnippetTemplate.hasConstantParameter(method) || NodeIntrinsificationVerificationPhase.verify(graph); + + if (original == null) { + new SnippetFrameStateCleanupPhase().apply(graph); + new DeadCodeEliminationPhase().apply(graph); + new InsertStateAfterPlaceholderPhase().apply(graph); + } else { + new DeadCodeEliminationPhase().apply(graph); + } + } + + private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy) { + StructuredGraph graph = graphCache.get(methodToParse); + if (graph == null) { + graphCache.putIfAbsent(methodToParse, buildGraph(methodToParse, policy == null ? inliningPolicy(methodToParse) : policy)); + graph = graphCache.get(methodToParse); + assert graph != null; + } + return graph; + } + + /** + * Builds the initial graph for a snippet. + */ + protected StructuredGraph buildInitialGraph(final ResolvedJavaMethod methodToParse) { + final StructuredGraph graph = new StructuredGraph(methodToParse); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(); + GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE); + graphBuilder.apply(graph); + + Debug.dump(graph, "%s: %s", methodToParse.getName(), GraphBuilderPhase.class.getSimpleName()); + + new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph); + + return graph; + } + + /** + * Called after a graph is inlined. + * + * @param caller the graph into which {@code callee} was inlined + * @param callee the graph that was inlined into {@code caller} + */ + protected void afterInline(StructuredGraph caller, StructuredGraph callee) { + if (GraalOptions.OptCanonicalizer) { + new WordTypeRewriterPhase(runtime, target.wordKind).apply(caller); + new CanonicalizerPhase.Instance(runtime, assumptions).apply(caller); + } + } + + /** + * Called after all inlining for a given graph is complete. + */ + protected void afterInlining(StructuredGraph graph) { + new NodeIntrinsificationPhase(runtime).apply(graph); + + new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph); + + new DeadCodeEliminationPhase().apply(graph); + if (GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase.Instance(runtime, assumptions).apply(graph); + } + } + + private StructuredGraph buildGraph(final ResolvedJavaMethod methodToParse, final SnippetInliningPolicy policy) { + assert !Modifier.isAbstract(methodToParse.getModifiers()) && !Modifier.isNative(methodToParse.getModifiers()) : methodToParse; + final StructuredGraph graph = buildInitialGraph(methodToParse); + + for (Invoke invoke : graph.getInvokes()) { + MethodCallTargetNode callTarget = invoke.methodCallTarget(); + ResolvedJavaMethod callee = callTarget.targetMethod(); + if (callee == method) { + final StructuredGraph originalGraph = new StructuredGraph(original); + new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(originalGraph); + InliningUtil.inline(invoke, originalGraph, true); + + Debug.dump(graph, "after inlining %s", callee); + afterInline(graph, originalGraph); + substituteCallsOriginal = true; + } else { + if ((callTarget.invokeKind() == InvokeKind.Static || callTarget.invokeKind() == InvokeKind.Special) && policy.shouldInline(callee, methodToParse)) { + StructuredGraph targetGraph; + StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(ReplacementsImpl.this, callee); + if (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)) { + targetGraph = intrinsicGraph; + } else { + targetGraph = parseGraph(callee, policy); + } + InliningUtil.inline(invoke, targetGraph, true); + Debug.dump(graph, "after inlining %s", callee); + afterInline(graph, targetGraph); + } + } + } + + afterInlining(graph); + + for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) { + end.disableSafepoint(); + } + + if (GraalOptions.ProbabilityAnalysis) { + new DeadCodeEliminationPhase().apply(graph); + new ComputeProbabilityPhase().apply(graph); + } + return graph; + } + } + + private static String originalName(Method substituteMethod, String methodSubstitution) { + if (methodSubstitution.isEmpty()) { + return substituteMethod.getName(); + } else { + return methodSubstitution; + } + } + + /** + * Resolves a name to a class. + * + * @param className the name of the class to resolve + * @param optional if true, resolution failure returns null + * @return the resolved class or null if resolution fails and {@code optional} is true + */ + static Class resolveType(String className, boolean optional) { + try { + // Need to use launcher class path to handle classes + // that are not on the boot class path + ClassLoader cl = Launcher.getLauncher().getClassLoader(); + return Class.forName(className, false, cl); + } catch (ClassNotFoundException e) { + if (optional) { + return null; + } + throw new GraalInternalError("Could not resolve type " + className); + } + } + + private static Class resolveType(JavaType type) { + JavaType base = type; + int dimensions = 0; + while (base.getComponentType() != null) { + base = base.getComponentType(); + dimensions++; + } + + Class baseClass = base.getKind() != Kind.Object ? base.getKind().toJavaClass() : resolveType(toJavaName(base), false); + return dimensions == 0 ? baseClass : Array.newInstance(baseClass, new int[dimensions]).getClass(); + } + + private Class[] originalParameters(Method substituteMethod, String methodSubstitution, boolean isStatic) { + Class[] parameters; + if (methodSubstitution.isEmpty()) { + parameters = substituteMethod.getParameterTypes(); + if (!isStatic) { + assert parameters.length > 0 : "must be a static method with the 'this' object as its first parameter"; + parameters = Arrays.copyOfRange(parameters, 1, parameters.length); + } + } else { + Signature signature = runtime.parseMethodDescriptor(methodSubstitution); + parameters = new Class[signature.getParameterCount(false)]; + for (int i = 0; i < parameters.length; i++) { + parameters[i] = resolveType(signature.getParameterType(i, null)); + } + } + return parameters; + } + + private static Member originalMethod(ClassSubstitution classSubstitution, boolean optional, String name, Class[] parameters) { + Class originalClass = classSubstitution.value(); + if (originalClass == ClassSubstitution.class) { + originalClass = resolveType(classSubstitution.className(), classSubstitution.optional()); + if (originalClass == null) { + // optional class was not found + return null; + } + } + try { + if (name.equals("")) { + return originalClass.getDeclaredConstructor(parameters); + } else { + return originalClass.getDeclaredMethod(name, parameters); + } + } catch (NoSuchMethodException | SecurityException e) { + if (optional) { + return null; + } + throw new GraalInternalError(e); + } + } + + @Override + public Collection getAllReplacements() { + HashSet result = new HashSet<>(); + result.addAll(registeredMethodSubstitutions.keySet()); + result.addAll(registerMacroSubstitutions.keySet()); + return result; + } + + @Override + public boolean isForcedSubstitution(ResolvedJavaMethod method) { + return forcedSubstitutions.contains(method); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsInstaller.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsInstaller.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,410 +0,0 @@ -/* - * Copyright (c) 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. - */ -package com.oracle.graal.replacements; - -import static com.oracle.graal.api.meta.MetaUtil.*; - -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.*; - -import sun.misc.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.replacements.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.java.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.java.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.replacements.Snippet.DefaultSnippetInliningPolicy; -import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy; -import com.oracle.graal.word.phases.*; - -/** - * Utility for managing the pre-processing and installation of replacements. Replacements are either - * {@linkplain Snippets snippets}, {@linkplain MethodSubstitution method substitutions} or - * {@link MacroSubstitution macro substitutions}. - */ -public class ReplacementsInstaller { - - protected final MetaAccessProvider runtime; - protected final TargetDescription target; - protected final Assumptions assumptions; - protected final BoxingMethodPool pool; - private final Thread owner; - - /** - * A graph cache used by this installer to avoid using the compiler storage for each method - * processed during snippet installation. Without this, all processed methods are to be - * determined as {@linkplain InliningUtil#canIntrinsify intrinsifiable}. - */ - private final Map graphCache; - - public ReplacementsInstaller(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target) { - this.runtime = runtime; - this.target = target; - this.assumptions = assumptions; - this.pool = new BoxingMethodPool(runtime); - this.graphCache = new HashMap<>(); - this.owner = Thread.currentThread(); - } - - /** - * Finds all the snippet methods in a given class, builds a graph for them and installs the - * graph with the key value of {@code Snippet.class} in the - * {@linkplain ResolvedJavaMethod#getCompilerStorage() compiler storage} of each method. - */ - public void installSnippets(Class snippets) { - for (Method method : snippets.getDeclaredMethods()) { - if (method.getAnnotation(Snippet.class) != null) { - int modifiers = method.getModifiers(); - if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { - throw new RuntimeException("Snippet must not be abstract or native"); - } - ResolvedJavaMethod snippet = runtime.lookupJavaMethod(method); - assert snippet.getCompilerStorage().get(Snippet.class) == null : method; - StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet)); - // System.out.println("snippet: " + graph); - snippet.getCompilerStorage().put(Snippet.class, graph); - } - } - } - - /** - * Finds all the methods in a given class annotated with {@link MethodSubstitution} or - * {@link MacroSubstitution}. It builds graphs for the former and installs them in the - * {@linkplain ResolvedJavaMethod#getCompilerStorage() compiler storage} of the original (i.e., - * substituted) method with a key of {@code MethodSubstitution.class}. For the latter, the - * denoted {@linkplain MacroSubstitution#macro() macro} node type is install in the compiler - * storage with a key of {@code Node.class}. - */ - public void installSubstitutions(Class substitutions) { - assert owner == Thread.currentThread() : "substitution installation must be single threaded"; - ClassSubstitution classSubstitution = substitutions.getAnnotation(ClassSubstitution.class); - assert classSubstitution != null; - assert !Snippets.class.isAssignableFrom(substitutions); - for (Method substituteMethod : substitutions.getDeclaredMethods()) { - MethodSubstitution methodSubstitution = substituteMethod.getAnnotation(MethodSubstitution.class); - MacroSubstitution macroSubstitution = substituteMethod.getAnnotation(MacroSubstitution.class); - if (methodSubstitution == null && macroSubstitution == null) { - continue; - } - - int modifiers = substituteMethod.getModifiers(); - if (!Modifier.isStatic(modifiers)) { - throw new RuntimeException("Substitution methods must be static: " + substituteMethod); - } - - if (methodSubstitution != null) { - if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { - throw new RuntimeException("Substitution method must not be abstract or native: " + substituteMethod); - } - String originalName = originalName(substituteMethod, methodSubstitution.value()); - Class[] originalParameters = originalParameters(substituteMethod, methodSubstitution.signature(), methodSubstitution.isStatic()); - Member originalMethod = originalMethod(classSubstitution, originalName, originalParameters); - if (originalMethod != null) { - installMethodSubstitution(originalMethod, substituteMethod); - } - } - if (macroSubstitution != null) { - String originalName = originalName(substituteMethod, macroSubstitution.value()); - Class[] originalParameters = originalParameters(substituteMethod, macroSubstitution.signature(), macroSubstitution.isStatic()); - Member originalMethod = originalMethod(classSubstitution, originalName, originalParameters); - if (originalMethod != null) { - installMacroSubstitution(originalMethod, macroSubstitution.macro()); - } - } - } - } - - // These fields are used to detect calls from the substitute method to the original method. - ResolvedJavaMethod substitute; - ResolvedJavaMethod original; - boolean substituteCallsOriginal; - - /** - * Installs a method substitution. - * - * @param originalMember a method or constructor being substituted - * @param substituteMethod the substitute method - */ - protected void installMethodSubstitution(Member originalMember, Method substituteMethod) { - substitute = runtime.lookupJavaMethod(substituteMethod); - if (originalMember instanceof Method) { - original = runtime.lookupJavaMethod((Method) originalMember); - } else { - original = runtime.lookupJavaConstructor((Constructor) originalMember); - } - try { - Debug.log("substitution: " + MetaUtil.format("%H.%n(%p)", original) + " --> " + MetaUtil.format("%H.%n(%p)", substitute)); - StructuredGraph graph = makeGraph(substitute, inliningPolicy(substitute)); - Object oldValue = original.getCompilerStorage().put(MethodSubstitution.class, graph); - assert oldValue == null; - } finally { - substitute = null; - original = null; - substituteCallsOriginal = false; - } - } - - /** - * Installs a macro substitution. - * - * @param originalMethod a method or constructor being substituted - * @param macro the substitute macro node class - */ - protected void installMacroSubstitution(Member originalMethod, Class macro) { - ResolvedJavaMethod originalJavaMethod; - if (originalMethod instanceof Method) { - originalJavaMethod = runtime.lookupJavaMethod((Method) originalMethod); - } else { - originalJavaMethod = runtime.lookupJavaConstructor((Constructor) originalMethod); - } - Object oldValue = originalJavaMethod.getCompilerStorage().put(Node.class, macro); - assert oldValue == null; - } - - private SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) { - Class policyClass = SnippetInliningPolicy.class; - Snippet snippet = method.getAnnotation(Snippet.class); - if (snippet != null) { - policyClass = snippet.inlining(); - } - if (policyClass == SnippetInliningPolicy.class) { - return new DefaultSnippetInliningPolicy(runtime, pool); - } - try { - return policyClass.getConstructor().newInstance(); - } catch (Exception e) { - throw new GraalInternalError(e); - } - } - - /** - * Does final processing of a snippet graph. - */ - protected void finalizeGraph(ResolvedJavaMethod method, StructuredGraph graph) { - new NodeIntrinsificationPhase(runtime, pool).apply(graph); - assert SnippetTemplate.hasConstantParameter(method) || NodeIntrinsificationVerificationPhase.verify(graph); - - if (substitute == null) { - new SnippetFrameStateCleanupPhase().apply(graph); - new DeadCodeEliminationPhase().apply(graph); - new InsertStateAfterPlaceholderPhase().apply(graph); - } else { - new DeadCodeEliminationPhase().apply(graph); - } - } - - public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { - return Debug.scope("BuildSnippetGraph", new Object[]{method}, new Callable() { - - @Override - public StructuredGraph call() throws Exception { - StructuredGraph graph = parseGraph(method, policy); - - finalizeGraph(method, graph); - - Debug.dump(graph, "%s: Final", method.getName()); - - return graph; - } - }); - } - - private StructuredGraph parseGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { - StructuredGraph graph = graphCache.get(method); - if (graph == null) { - graph = buildGraph(method, policy == null ? inliningPolicy(method) : policy); - graphCache.put(method, graph); - } - return graph; - } - - /** - * Builds the initial graph for a snippet. - */ - protected StructuredGraph buildInitialGraph(final ResolvedJavaMethod method) { - final StructuredGraph graph = new StructuredGraph(method); - GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(); - GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE); - graphBuilder.apply(graph); - - Debug.dump(graph, "%s: %s", method.getName(), GraphBuilderPhase.class.getSimpleName()); - - new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph); - new NodeIntrinsificationPhase(runtime, pool).apply(graph); - - return graph; - } - - /** - * Called after a graph is inlined. - * - * @param caller the graph into which {@code callee} was inlined - * @param callee the graph that was inlined into {@code caller} - */ - protected void afterInline(StructuredGraph caller, StructuredGraph callee) { - if (GraalOptions.OptCanonicalizer) { - new WordTypeRewriterPhase(runtime, target.wordKind).apply(caller); - new CanonicalizerPhase(runtime, assumptions).apply(caller); - } - } - - /** - * Called after all inlining for a given graph is complete. - */ - protected void afterInlining(StructuredGraph graph) { - new NodeIntrinsificationPhase(runtime, pool).apply(graph); - - new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph); - - new DeadCodeEliminationPhase().apply(graph); - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(runtime, assumptions).apply(graph); - } - } - - private StructuredGraph buildGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { - assert !Modifier.isAbstract(method.getModifiers()) && !Modifier.isNative(method.getModifiers()) : method; - final StructuredGraph graph = buildInitialGraph(method); - - for (Invoke invoke : graph.getInvokes()) { - MethodCallTargetNode callTarget = invoke.methodCallTarget(); - ResolvedJavaMethod callee = callTarget.targetMethod(); - if (callee == substitute) { - final StructuredGraph originalGraph = new StructuredGraph(original); - new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(originalGraph); - InliningUtil.inline(invoke, originalGraph, true); - - Debug.dump(graph, "after inlining %s", callee); - afterInline(graph, originalGraph); - substituteCallsOriginal = true; - } else { - if ((callTarget.invokeKind() == InvokeKind.Static || callTarget.invokeKind() == InvokeKind.Special) && policy.shouldInline(callee, method)) { - StructuredGraph targetGraph = parseGraph(callee, policy); - InliningUtil.inline(invoke, targetGraph, true); - Debug.dump(graph, "after inlining %s", callee); - afterInline(graph, targetGraph); - } - } - } - - afterInlining(graph); - - for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) { - end.disableSafepoint(); - } - - if (GraalOptions.ProbabilityAnalysis) { - new DeadCodeEliminationPhase().apply(graph); - new ComputeProbabilityPhase().apply(graph); - } - return graph; - } - - private static String originalName(Method substituteMethod, String methodSubstitution) { - if (methodSubstitution.isEmpty()) { - return substituteMethod.getName(); - } else { - return methodSubstitution; - } - } - - /** - * Resolves a name to a class. - * - * @param className the name of the class to resolve - * @param optional if true, resolution failure returns null - * @return the resolved class or null if resolution fails and {@code optional} is true - */ - static Class resolveType(String className, boolean optional) { - try { - // Need to use launcher class path to handle classes - // that are not on the boot class path - ClassLoader cl = Launcher.getLauncher().getClassLoader(); - return Class.forName(className, false, cl); - } catch (ClassNotFoundException e) { - if (optional) { - return null; - } - throw new GraalInternalError("Could not resolve type " + className); - } - } - - private static Class resolveType(JavaType type) { - JavaType base = type; - int dimensions = 0; - while (base.getComponentType() != null) { - base = base.getComponentType(); - dimensions++; - } - - Class baseClass = base.getKind() != Kind.Object ? base.getKind().toJavaClass() : resolveType(toJavaName(base), false); - return dimensions == 0 ? baseClass : Array.newInstance(baseClass, new int[dimensions]).getClass(); - } - - private Class[] originalParameters(Method substituteMethod, String methodSubstitution, boolean isStatic) { - Class[] parameters; - if (methodSubstitution.isEmpty()) { - parameters = substituteMethod.getParameterTypes(); - if (!isStatic) { - assert parameters.length > 0 : "must be a static method with the 'this' object as its first parameter"; - parameters = Arrays.copyOfRange(parameters, 1, parameters.length); - } - } else { - Signature signature = runtime.parseMethodDescriptor(methodSubstitution); - parameters = new Class[signature.getParameterCount(false)]; - for (int i = 0; i < parameters.length; i++) { - parameters[i] = resolveType(signature.getParameterType(i, null)); - } - } - return parameters; - } - - private static Member originalMethod(ClassSubstitution classSubstitution, String name, Class[] parameters) { - Class originalClass = classSubstitution.value(); - if (originalClass == ClassSubstitution.class) { - originalClass = resolveType(classSubstitution.className(), classSubstitution.optional()); - if (originalClass == null) { - // optional class was not found - return null; - } - } - try { - if (name.equals("")) { - return originalClass.getDeclaredConstructor(parameters); - } else { - return originalClass.getDeclaredMethod(name, parameters); - } - } catch (NoSuchMethodException | SecurityException e) { - throw new GraalInternalError(e); - } - } -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsProvider.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsProvider.java Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +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. - */ -package com.oracle.graal.replacements; - -/** - * Interface for service providers that install replacements into the compiler. - */ -public interface ReplacementsProvider { - - void installReplacements(ReplacementsInstaller installer); -} diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java Mon Apr 15 08:51:19 2013 +0200 @@ -27,8 +27,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.Node.NodeIntrinsic; -import com.oracle.graal.nodes.extended.*; -import com.oracle.graal.nodes.type.*; import com.oracle.graal.replacements.nodes.*; import com.oracle.graal.word.*; @@ -55,6 +53,13 @@ * Determines if {@code method} should be inlined into {@code caller}. */ boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller); + + /** + * Determines if {@code method} should be inlined using its replacement graph. + * + * @return true if the replacement graph should be used, false for normal inlining. + */ + boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse); } /** @@ -70,11 +75,9 @@ public static class DefaultSnippetInliningPolicy implements SnippetInliningPolicy { private final MetaAccessProvider metaAccess; - private final BoxingMethodPool pool; - public DefaultSnippetInliningPolicy(MetaAccessProvider metaAccess, BoxingMethodPool pool) { + public DefaultSnippetInliningPolicy(MetaAccessProvider metaAccess) { this.metaAccess = metaAccess; - this.pool = pool; } @Override @@ -89,16 +92,18 @@ return false; } if (metaAccess.lookupJavaType(Throwable.class).isAssignableFrom(method.getDeclaringClass())) { - if (method.getName().equals("")) { + if (method.isConstructor()) { return false; } } if (method.getAnnotation(Word.Operation.class) != null) { return false; } - if (pool.isSpecialMethod(method)) { - return false; - } + return true; + } + + @Override + public boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse) { return true; } } @@ -116,20 +121,6 @@ } /** - * Denotes a snippet parameter that will be bound during snippet template - * {@linkplain SnippetTemplate#instantiate instantiation}. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.PARAMETER) - public @interface Parameter { - - /** - * The name of this parameter. - */ - String value(); - } - - /** * Denotes a snippet parameter representing 0 or more arguments that will be bound during * snippet template {@linkplain SnippetTemplate#instantiate instantiation}. During snippet * template creation, its value must be an array whose length specifies the number of arguments @@ -143,11 +134,6 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface VarargsParameter { - - /** - * The name of this parameter. - */ - String value(); } /** @@ -157,61 +143,5 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface ConstantParameter { - - /** - * The name of this constant. - */ - String value(); - } - - /** - * Wrapper for the prototype value of a {@linkplain VarargsParameter varargs} parameter. - */ - public static class Varargs { - - private final Object args; - private final Class argType; - private final int length; - private final Stamp argStamp; - - public static Varargs vargargs(Object array, Stamp argStamp) { - return new Varargs(array, argStamp); - } - - public Varargs(Object array, Stamp argStamp) { - assert array != null; - this.argType = array.getClass().getComponentType(); - this.argStamp = argStamp; - assert this.argType != null; - this.length = java.lang.reflect.Array.getLength(array); - this.args = array; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof Varargs) { - Varargs other = (Varargs) obj; - return other.argType == argType && other.length == length; - } - return false; - } - - public Object getArray() { - return args; - } - - public Stamp getArgStamp() { - return argStamp; - } - - @Override - public int hashCode() { - return argType.hashCode() ^ length; - } - - @Override - public String toString() { - return argType.getName() + "[" + length + "]"; - } } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Mon Apr 15 08:51:19 2013 +0200 @@ -24,7 +24,6 @@ import java.lang.reflect.*; import java.util.*; -import java.util.Map.Entry; import java.util.concurrent.*; import com.oracle.graal.api.code.*; @@ -34,14 +33,13 @@ import com.oracle.graal.loop.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.common.*; -import com.oracle.graal.replacements.Snippet.*; -import com.oracle.graal.replacements.Snippet.Parameter; +import com.oracle.graal.replacements.Snippet.ConstantParameter; +import com.oracle.graal.replacements.Snippet.VarargsParameter; import com.oracle.graal.replacements.nodes.*; import com.oracle.graal.word.*; import com.oracle.graal.word.phases.*; @@ -50,171 +48,274 @@ * A snippet template is a graph created by parsing a snippet method and then specialized by binding * constants to the snippet's {@link ConstantParameter} parameters. * - * Snippet templates can be managed in a {@link Cache}. + * Snippet templates can be managed in a cache maintained by {@link AbstractTemplates}. */ public class SnippetTemplate { /** - * A snippet template key encapsulates the method from which a snippet was built and the - * arguments used to specialize the snippet. - * - * @see Cache + * Holds the {@link ResolvedJavaMethod} of the snippet, together with some information about the + * method that needs to be computed only once. The {@link SnippetInfo} should be created once + * per snippet an then cached. */ - public static class Key implements Iterable> { + public static class SnippetInfo { + + protected final ResolvedJavaMethod method; + protected final boolean[] constantParameters; + protected final boolean[] varargsParameters; + + /** + * The parameter names, taken from the local variables table. Only used for assertion + * checking, so use only within an assert statement. + */ + protected final String[] names; + + protected SnippetInfo(ResolvedJavaMethod method) { + this.method = method; - public final ResolvedJavaMethod method; - private final HashMap map = new HashMap<>(); - private int hash; + assert Modifier.isStatic(method.getModifiers()) : "snippet method must be static: " + MetaUtil.format("%H.%n", method); + int count = method.getSignature().getParameterCount(false); + constantParameters = new boolean[count]; + varargsParameters = new boolean[count]; + for (int i = 0; i < count; i++) { + constantParameters[i] = MetaUtil.getParameterAnnotation(ConstantParameter.class, i, method) != null; + varargsParameters[i] = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method) != null; + + assert !isConstantParameter(i) || !isVarargsParameter(i) : "Parameter cannot be annotated with both @" + ConstantParameter.class.getSimpleName() + " and @" + + VarargsParameter.class.getSimpleName(); + } - public Key(ResolvedJavaMethod method) { - this.method = method; - this.hash = method.hashCode(); + names = new String[count]; + // Retrieve the names only when assertions are turned on. + assert initNames(); + } + + private boolean initNames() { + int slotIdx = 0; + for (int i = 0; i < names.length; i++) { + names[i] = method.getLocalVariableTable().getLocal(slotIdx, 0).getName(); + + Kind kind = method.getSignature().getParameterKind(i); + slotIdx += kind == Kind.Long || kind == Kind.Double ? 2 : 1; + } + return true; } - public Key add(String name, Object value) { - assert !map.containsKey(name); - map.put(name, value); - hash = hash ^ name.hashCode(); - if (value != null) { - hash *= (value.hashCode() + 1); - } + public ResolvedJavaMethod getMethod() { + return method; + } + + public int getParameterCount() { + return constantParameters.length; + } + + public boolean isConstantParameter(int paramIdx) { + return constantParameters[paramIdx]; + } + + public boolean isVarargsParameter(int paramIdx) { + return varargsParameters[paramIdx]; + } + } + + /** + * Values that are bound to the snippet method parameters. The methods {@link #add}, + * {@link #addConst}, and {@link #addVarargs} must be called in the same order as in the + * signature of the snippet method. The parameter name is passed to the add methods for + * assertion checking, i.e., to enforce that the order matches. Which method needs to be called + * depends on the annotation of the snippet method parameter: + *

    + *
  • Use {@link #add} for a parameter without an annotation. The value is bound when the + * {@link SnippetTemplate} is {@link SnippetTemplate#instantiate instantiated}. + *
  • Use {@link #addConst} for a parameter annotated with {@link ConstantParameter}. The value + * is bound when the {@link SnippetTemplate} is {@link SnippetTemplate#SnippetTemplate created}. + *
  • Use {@link #addVarargs} for an array parameter annotated with {@link VarargsParameter}. A + * separate {@link SnippetTemplate} is {@link SnippetTemplate#SnippetTemplate created} for every + * distinct array length. The actual values are bound when the {@link SnippetTemplate} is + * {@link SnippetTemplate#instantiate instantiated} + *
+ */ + public static class Arguments { + + protected final SnippetInfo info; + protected final CacheKey cacheKey; + protected final Object[] values; + + protected int nextParamIdx; + + public Arguments(SnippetInfo info) { + this.info = info; + this.cacheKey = new CacheKey(info); + this.values = new Object[info.getParameterCount()]; + } + + public Arguments add(String name, Object value) { + assert check(name, false, false); + values[nextParamIdx] = value; + nextParamIdx++; return this; } - public int length() { - return map.size(); + public Arguments addConst(String name, Object value) { + assert check(name, true, false); + values[nextParamIdx] = value; + cacheKey.setParam(nextParamIdx, value); + nextParamIdx++; + return this; } - public Object get(String name) { - return map.get(name); + public Arguments addVarargs(String name, Class componentType, Stamp argStamp, Object value) { + assert check(name, false, true); + Varargs varargs = new Varargs(componentType, argStamp, value); + values[nextParamIdx] = varargs; + // A separate template is necessary for every distinct array length + cacheKey.setParam(nextParamIdx, varargs.length); + nextParamIdx++; + return this; + } + + private boolean check(String name, boolean constParam, boolean varargsParam) { + assert nextParamIdx < info.getParameterCount() : "too many parameters: " + name + " " + this; + assert info.names[nextParamIdx].equals(name) : "wrong parameter name: " + name + " " + this; + assert constParam == info.isConstantParameter(nextParamIdx) : "Parameter " + (constParam ? "not " : "") + "annotated with @" + ConstantParameter.class.getSimpleName() + ": " + name + + " " + this; + assert varargsParam == info.isVarargsParameter(nextParamIdx) : "Parameter " + (varargsParam ? "not " : "") + "annotated with @" + VarargsParameter.class.getSimpleName() + ": " + name + + " " + this; + return true; } @Override - public Iterator> iterator() { - return map.entrySet().iterator(); + public String toString() { + StringBuilder result = new StringBuilder(); + result.append("Parameters<").append(MetaUtil.format("%H.%n", info.method)).append(" ["); + String sep = ""; + for (int i = 0; i < info.getParameterCount(); i++) { + result.append(sep); + if (info.isConstantParameter(i)) { + result.append("const "); + } else if (info.isVarargsParameter(i)) { + result.append("varargs "); + } + result.append(info.names[i]).append(" = ").append(values[i]); + sep = ", "; + } + result.append(">"); + return result.toString(); + } + } + + /** + * Wrapper for the prototype value of a {@linkplain VarargsParameter varargs} parameter. + */ + static class Varargs { + + protected final Class componentType; + protected final Stamp stamp; + protected final Object value; + protected final int length; + + protected Varargs(Class componentType, Stamp stamp, Object value) { + this.componentType = componentType; + this.stamp = stamp; + this.value = value; + if (value instanceof List) { + this.length = ((List) value).size(); + } else { + this.length = Array.getLength(value); + } + } + } + + static class CacheKey { + + private final ResolvedJavaMethod method; + private final Object[] values; + private int hash; + + protected CacheKey(SnippetInfo info) { + this.method = info.method; + this.values = new Object[info.getParameterCount()]; + this.hash = info.method.hashCode(); + } + + protected void setParam(int paramIdx, Object value) { + values[paramIdx] = value; + hash = (hash * 31) ^ (value == null ? 0 : value.hashCode()); } @Override public boolean equals(Object obj) { - if (obj instanceof Key) { - Key other = (Key) obj; - return other.method == method && other.map.equals(map); + if (!(obj instanceof CacheKey)) { + return false; + } + CacheKey other = (CacheKey) obj; + if (method != other.method) { + return false; } - return false; + for (int i = 0; i < values.length; i++) { + if (values[i] != null && !values[i].equals(other.values[i])) { + return false; + } + } + return true; } @Override public int hashCode() { return hash; } - - @Override - public String toString() { - return MetaUtil.format("%h.%n", method) + map.toString(); - } - - public Set names() { - return map.keySet(); - } } /** - * Arguments used to instantiate a template. + * Base class for snippet classes. It provides a cache for {@link SnippetTemplate}s. */ - public static class Arguments implements Iterable> { - - private final HashMap map = new HashMap<>(); + public abstract static class AbstractTemplates { - public static Arguments arguments(String name, Object value) { - return new Arguments().add(name, value); - } + protected final MetaAccessProvider runtime; + protected final Replacements replacements; + protected final TargetDescription target; + private final ConcurrentHashMap templates; - public Arguments add(String name, Object value) { - assert !map.containsKey(name); - map.put(name, value); - return this; - } - - public int length() { - return map.size(); + protected AbstractTemplates(MetaAccessProvider runtime, Replacements replacements, TargetDescription target) { + this.runtime = runtime; + this.replacements = replacements; + this.target = target; + this.templates = new ConcurrentHashMap<>(); } - @Override - public Iterator> iterator() { - return map.entrySet().iterator(); - } - - @Override - public String toString() { - return map.toString(); - } - } + protected SnippetInfo snippet(Class declaringClass, String methodName) { + Method found = null; + for (Method method : declaringClass.getDeclaredMethods()) { + if (method.getAnnotation(Snippet.class) != null && method.getName().equals(methodName)) { + assert found == null : "found more than one @" + Snippet.class.getSimpleName() + " method " + methodName + " in " + declaringClass; + found = method; + } + } + assert found != null : "did not find @" + Snippet.class.getSimpleName() + " method " + methodName + " in " + declaringClass; - /** - * A collection of snippet templates accessed by a {@link Key} instance. - */ - public static class Cache { - - private final ConcurrentHashMap templates = new ConcurrentHashMap<>(); - private final MetaAccessProvider runtime; - private final TargetDescription target; - - public Cache(MetaAccessProvider runtime, TargetDescription target) { - this.runtime = runtime; - this.target = target; + return new SnippetInfo(runtime.lookupJavaMethod(found)); } /** * Gets a template for a given key, creating it first if necessary. */ - public SnippetTemplate get(final SnippetTemplate.Key key, final Assumptions assumptions) { - SnippetTemplate template = templates.get(key); + protected SnippetTemplate template(final Arguments args) { + SnippetTemplate template = templates.get(args.cacheKey); if (template == null) { - template = Debug.scope("SnippetSpecialization", key.method, new Callable() { + template = Debug.scope("SnippetSpecialization", args.info.method, new Callable() { @Override public SnippetTemplate call() throws Exception { - return new SnippetTemplate(runtime, assumptions, target, key); + return new SnippetTemplate(runtime, replacements, target, args); } }); - // System.out.println(key + " -> " + template); - templates.put(key, template); + templates.put(args.cacheKey, template); } return template; } } - public abstract static class AbstractTemplates { - - protected final Cache cache; - protected final MetaAccessProvider runtime; - protected final Assumptions assumptions; - protected Class snippetsClass; - - public AbstractTemplates(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target, Class snippetsClass) { - this.runtime = runtime; - this.assumptions = assumptions; - if (snippetsClass == null) { - assert this instanceof Snippets; - this.snippetsClass = getClass(); - } else { - this.snippetsClass = snippetsClass; - } - this.cache = new Cache(runtime, target); - } - - protected ResolvedJavaMethod snippet(String name, Class... parameterTypes) { - try { - ResolvedJavaMethod snippet = runtime.lookupJavaMethod(snippetsClass.getDeclaredMethod(name, parameterTypes)); - assert snippet.getAnnotation(Snippet.class) != null : "snippet is not annotated with @" + Snippet.class.getSimpleName(); - return snippet; - } catch (NoSuchMethodException e) { - throw new GraalInternalError(e); - } - } - } - private static final Object UNUSED_PARAMETER = "DEAD PARAMETER"; + private static final Object CONSTANT_PARAMETER = "CONSTANT"; /** * Determines if any parameter of a given method is annotated with {@link ConstantParameter}. @@ -231,28 +332,25 @@ /** * Creates a snippet template. */ - public SnippetTemplate(MetaAccessProvider runtime, Assumptions assumptions, TargetDescription target, SnippetTemplate.Key key) { - ResolvedJavaMethod method = key.method; - assert Modifier.isStatic(method.getModifiers()) : "snippet method must be static: " + method; + protected SnippetTemplate(MetaAccessProvider runtime, Replacements replacements, TargetDescription target, Arguments args) { + StructuredGraph snippetGraph = replacements.getSnippet(args.info.method); + + ResolvedJavaMethod method = snippetGraph.method(); Signature signature = method.getSignature(); // Copy snippet graph, replacing constant parameters with given arguments - StructuredGraph snippetGraph = (StructuredGraph) method.getCompilerStorage().get(Snippet.class); StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method()); - IdentityHashMap replacements = new IdentityHashMap<>(); - replacements.put(snippetGraph.start(), snippetCopy.start()); + IdentityHashMap nodeReplacements = new IdentityHashMap<>(); + nodeReplacements.put(snippetGraph.start(), snippetCopy.start()); - int parameterCount = signature.getParameterCount(false); - assert checkTemplate(runtime, key, parameterCount, method, signature); + assert checkTemplate(runtime, args, method, signature); - Parameter[] parameterAnnotations = new Parameter[parameterCount]; - VarargsParameter[] varargsParameterAnnotations = new VarargsParameter[parameterCount]; + int parameterCount = args.info.getParameterCount(); ConstantNode[] placeholders = new ConstantNode[parameterCount]; + for (int i = 0; i < parameterCount; i++) { - ConstantParameter c = MetaUtil.getParameterAnnotation(ConstantParameter.class, i, method); - if (c != null) { - String name = c.value(); - Object arg = key.get(name); + if (args.info.isConstantParameter(i)) { + Object arg = args.values[i]; Kind kind = signature.getParameterKind(i); Constant constantArg; if (arg instanceof Constant) { @@ -260,52 +358,45 @@ } else { constantArg = Constant.forBoxed(kind, arg); } - replacements.put(snippetGraph.getLocal(i), ConstantNode.forConstant(constantArg, runtime, snippetCopy)); - } else { - VarargsParameter vp = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method); - if (vp != null) { - String name = vp.value(); - Varargs varargs = (Varargs) key.get(name); - Object array = varargs.getArray(); - ConstantNode placeholder = ConstantNode.forObject(array, runtime, snippetCopy); - replacements.put(snippetGraph.getLocal(i), placeholder); - placeholders[i] = placeholder; - varargsParameterAnnotations[i] = vp; - } else { - parameterAnnotations[i] = MetaUtil.getParameterAnnotation(Parameter.class, i, method); - } + nodeReplacements.put(snippetGraph.getLocal(i), ConstantNode.forConstant(constantArg, runtime, snippetCopy)); + } else if (args.info.isVarargsParameter(i)) { + Varargs varargs = (Varargs) args.values[i]; + Object array = Array.newInstance(varargs.componentType, varargs.length); + ConstantNode placeholder = ConstantNode.forObject(array, runtime, snippetCopy); + nodeReplacements.put(snippetGraph.getLocal(i), placeholder); + placeholders[i] = placeholder; } } - snippetCopy.addDuplicates(snippetGraph.getNodes(), replacements); + snippetCopy.addDuplicates(snippetGraph.getNodes(), nodeReplacements); Debug.dump(snippetCopy, "Before specialization"); - if (!replacements.isEmpty()) { + if (!nodeReplacements.isEmpty()) { // Do deferred intrinsification of node intrinsics - new NodeIntrinsificationPhase(runtime, new BoxingMethodPool(runtime)).apply(snippetCopy); + new NodeIntrinsificationPhase(runtime).apply(snippetCopy); new WordTypeRewriterPhase(runtime, target.wordKind).apply(snippetCopy); - new CanonicalizerPhase(runtime, assumptions, 0, null).apply(snippetCopy); + new CanonicalizerPhase.Instance(runtime, replacements.getAssumptions(), 0, null).apply(snippetCopy); } assert NodeIntrinsificationVerificationPhase.verify(snippetCopy); // Gather the template parameters - parameters = new HashMap<>(); + parameters = new Object[parameterCount]; for (int i = 0; i < parameterCount; i++) { - VarargsParameter vp = varargsParameterAnnotations[i]; - if (vp != null) { + if (args.info.isConstantParameter(i)) { + parameters[i] = CONSTANT_PARAMETER; + } else if (args.info.isVarargsParameter(i)) { assert snippetCopy.getLocal(i) == null; - Varargs varargs = (Varargs) key.get(vp.value()); - Object array = varargs.getArray(); - int length = Array.getLength(array); + Varargs varargs = (Varargs) args.values[i]; + int length = varargs.length; LocalNode[] locals = new LocalNode[length]; - Stamp stamp = varargs.getArgStamp(); + Stamp stamp = varargs.stamp; for (int j = 0; j < length; j++) { assert (parameterCount & 0xFFFF) == parameterCount; int idx = i << 16 | j; LocalNode local = snippetCopy.unique(new LocalNode(idx, stamp)); locals[j] = local; } - parameters.put(vp.value(), locals); + parameters[i] = locals; ConstantNode placeholder = placeholders[i]; assert placeholder != null; @@ -319,15 +410,12 @@ } } } else { - Parameter p = parameterAnnotations[i]; - if (p != null) { - LocalNode local = snippetCopy.getLocal(i); - if (local == null) { - // Parameter value was eliminated - parameters.put(p.value(), UNUSED_PARAMETER); - } else { - parameters.put(p.value(), local); - } + LocalNode local = snippetCopy.getLocal(i); + if (local == null) { + // Parameter value was eliminated + parameters[i] = UNUSED_PARAMETER; + } else { + parameters[i] = local; } } } @@ -344,7 +432,7 @@ LoopEx loop = new LoopsData(snippetCopy).loop(loopBegin); int mark = snippetCopy.getMark(); LoopTransformations.fullUnroll(loop, runtime, null); - new CanonicalizerPhase(runtime, assumptions, mark, null).apply(snippetCopy); + new CanonicalizerPhase.Instance(runtime, replacements.getAssumptions(), mark, null).apply(snippetCopy); } FixedNode explodeLoopNext = explodeLoop.next(); explodeLoop.clearSuccessors(); @@ -426,11 +514,11 @@ return true; } - private static boolean checkVarargs(final ResolvedJavaMethod method, Signature signature, int i, String name, Varargs varargs) { - Object arg = varargs.getArray(); + private static boolean checkVarargs(MetaAccessProvider runtime, final ResolvedJavaMethod method, Signature signature, int i, String name, Varargs varargs) { ResolvedJavaType type = (ResolvedJavaType) signature.getParameterType(i, method.getDeclaringClass()); assert type.isArray() : "varargs parameter must be an array type"; - assert type.isInstance(Constant.forObject(arg)) : "value for " + name + " is not a " + MetaUtil.toJavaName(type) + " instance: " + arg; + assert type.getComponentType().isAssignableFrom(runtime.lookupJavaType(varargs.componentType)) : "componentType for " + name + " not matching " + MetaUtil.toJavaName(type) + " instance: " + + varargs.componentType; return true; } @@ -445,7 +533,7 @@ * {@link LocalNode} instance or a {@link LocalNode} array. For an eliminated parameter, the * value is identical to the key. */ - private final Map parameters; + private final Object[] parameters; /** * The return node (if any) of the snippet. @@ -473,33 +561,33 @@ * * @return the map that will be used to bind arguments to parameters when inlining this template */ - private IdentityHashMap bind(StructuredGraph replaceeGraph, MetaAccessProvider runtime, SnippetTemplate.Arguments args) { + private IdentityHashMap bind(StructuredGraph replaceeGraph, MetaAccessProvider runtime, Arguments args) { IdentityHashMap replacements = new IdentityHashMap<>(); - assert args.length() == parameters.size() : "number of args (" + args.length() + ") != number of parameters (" + parameters.size() + ")"; - for (Map.Entry e : args) { - String name = e.getKey(); - Object parameter = parameters.get(name); - assert parameter != null : this + " has no parameter named " + name; - Object argument = e.getValue(); + assert args.info.getParameterCount() == parameters.length : "number of args (" + args.info.getParameterCount() + ") != number of parameters (" + parameters.length + ")"; + for (int i = 0; i < parameters.length; i++) { + Object parameter = parameters[i]; + assert parameter != null : this + " has no parameter named " + args.info.names[i]; + Object argument = args.values[i]; if (parameter instanceof LocalNode) { if (argument instanceof ValueNode) { replacements.put((LocalNode) parameter, (ValueNode) argument); } else { Kind kind = ((LocalNode) parameter).kind(); - assert argument != null || kind == Kind.Object : this + " cannot accept null for non-object parameter named " + name; - Constant constant = Constant.forBoxed(kind, argument); + assert argument != null || kind == Kind.Object : this + " cannot accept null for non-object parameter named " + args.info.names[i]; + Constant constant = forBoxed(argument, kind); replacements.put((LocalNode) parameter, ConstantNode.forConstant(constant, runtime, replaceeGraph)); } } else if (parameter instanceof LocalNode[]) { LocalNode[] locals = (LocalNode[]) parameter; + Varargs varargs = (Varargs) argument; int length = locals.length; List list = null; Object array = null; - if (argument instanceof List) { - list = (List) argument; + if (varargs.value instanceof List) { + list = (List) varargs.value; assert list.size() == length : length + " != " + list.size(); } else { - array = argument; + array = varargs.value; assert array != null && array.getClass().isArray(); assert Array.getLength(array) == length : length + " != " + Array.getLength(array); } @@ -511,19 +599,45 @@ if (value instanceof ValueNode) { replacements.put(local, (ValueNode) value); } else { - Constant constant = Constant.forBoxed(local.kind(), value); + Constant constant = forBoxed(value, local.kind()); ConstantNode element = ConstantNode.forConstant(constant, runtime, replaceeGraph); replacements.put(local, element); } } } else { - assert parameter == UNUSED_PARAMETER : "unexpected entry for parameter: " + name + " -> " + parameter; + assert parameter == CONSTANT_PARAMETER || parameter == UNUSED_PARAMETER : "unexpected entry for parameter: " + args.info.names[i] + " -> " + parameter; } } return replacements; } /** + * Converts a Java boxed value to a {@link Constant} of the right kind. This adjusts for the + * limitation that a {@link Local}'s kind is a {@linkplain Kind#getStackKind() stack kind} and + * so cannot be used for re-boxing primitives smaller than an int. + * + * @param argument a Java boxed value + * @param localKind the kind of the {@link Local} to which {@code argument} will be bound + */ + protected Constant forBoxed(Object argument, Kind localKind) { + assert localKind == localKind.getStackKind(); + if (localKind == Kind.Int && !(argument instanceof Integer)) { + if (argument instanceof Boolean) { + return Constant.forBoxed(Kind.Boolean, argument); + } + if (argument instanceof Byte) { + return Constant.forBoxed(Kind.Byte, argument); + } + if (argument instanceof Short) { + return Constant.forBoxed(Kind.Short, argument); + } + assert argument instanceof Character; + return Constant.forBoxed(Kind.Char, argument); + } + return Constant.forBoxed(localKind, argument); + } + + /** * Logic for replacing a snippet-lowered node at its usages with the return value of the * snippet. An alternative to the {@linkplain SnippetTemplate#DEFAULT_REPLACER default} * replacement logic can be used to handle mismatches between the stamp of the node being @@ -558,7 +672,7 @@ * @param args the arguments to be bound to the flattened positional parameters of the snippet * @return the map of duplicated nodes (original -> duplicate) */ - public Map instantiate(MetaAccessProvider runtime, FixedNode replacee, UsageReplacer replacer, SnippetTemplate.Arguments args) { + public Map instantiate(MetaAccessProvider runtime, FixedNode replacee, UsageReplacer replacer, Arguments args) { // Inline the snippet nodes, replacing parameters with the given args in the process String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}"; @@ -634,7 +748,7 @@ * @param replacer object that replaces the usages of {@code replacee} * @param args the arguments to be bound to the flattened positional parameters of the snippet */ - public void instantiate(MetaAccessProvider runtime, FloatingNode replacee, UsageReplacer replacer, LoweringTool tool, SnippetTemplate.Arguments args) { + public void instantiate(MetaAccessProvider runtime, FloatingNode replacee, UsageReplacer replacer, LoweringTool tool, Arguments args) { // Inline the snippet nodes, replacing parameters with the given args in the process String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}"; @@ -693,13 +807,17 @@ public String toString() { StringBuilder buf = new StringBuilder(snippet.toString()).append('('); String sep = ""; - for (Map.Entry e : parameters.entrySet()) { - String name = e.getKey(); - Object value = e.getValue(); + for (int i = 0; i < parameters.length; i++) { + String name = "[" + i + "]"; + Object value = parameters[i]; buf.append(sep); sep = ", "; - if (value == UNUSED_PARAMETER) { + if (value == null) { + buf.append(" ").append(name); + } else if (value == UNUSED_PARAMETER) { buf.append(" ").append(name); + } else if (value == CONSTANT_PARAMETER) { + buf.append(" ").append(name); } else if (value instanceof LocalNode) { LocalNode local = (LocalNode) value; buf.append(local.kind().getJavaName()).append(' ').append(name); @@ -712,42 +830,18 @@ return buf.append(')').toString(); } - private static boolean checkTemplate(MetaAccessProvider runtime, SnippetTemplate.Key key, int parameterCount, ResolvedJavaMethod method, Signature signature) { - Set expected = new HashSet<>(); - for (int i = 0; i < parameterCount; i++) { - ConstantParameter c = MetaUtil.getParameterAnnotation(ConstantParameter.class, i, method); - VarargsParameter vp = MetaUtil.getParameterAnnotation(VarargsParameter.class, i, method); - Parameter p = MetaUtil.getParameterAnnotation(Parameter.class, i, method); - if (c != null) { - assert vp == null && p == null; - String name = c.value(); - expected.add(name); + private static boolean checkTemplate(MetaAccessProvider runtime, Arguments args, ResolvedJavaMethod method, Signature signature) { + for (int i = 0; i < args.info.getParameterCount(); i++) { + if (args.info.isConstantParameter(i)) { Kind kind = signature.getParameterKind(i); - assert key.names().contains(name) : "key for " + method + " is missing \"" + name + "\": " + key; - assert checkConstantArgument(runtime, method, signature, i, c.value(), key.get(name), kind); - } else if (vp != null) { - assert p == null; - String name = vp.value(); - expected.add(name); - assert key.names().contains(name) : "key for " + method + " is missing \"" + name + "\": " + key; - assert key.get(name) instanceof Varargs; - Varargs varargs = (Varargs) key.get(name); - assert checkVarargs(method, signature, i, name, varargs); - } else { - assert p != null : method + ": parameter " + i + " must be annotated with exactly one of " + "@" + ConstantParameter.class.getSimpleName() + " or " + "@" + - VarargsParameter.class.getSimpleName() + " or " + "@" + Parameter.class.getSimpleName(); + assert checkConstantArgument(runtime, method, signature, i, args.info.names[i], args.values[i], kind); + + } else if (args.info.isVarargsParameter(i)) { + assert args.values[i] instanceof Varargs; + Varargs varargs = (Varargs) args.values[i]; + assert checkVarargs(runtime, method, signature, i, args.info.names[i], varargs); } } - if (!key.names().containsAll(expected)) { - expected.removeAll(key.names()); - assert false : expected + " missing from key " + key; - } - if (!expected.containsAll(key.names())) { - Set namesCopy = new HashSet<>(key.names()); - namesCopy.removeAll(expected); - assert false : "parameter(s) " + namesCopy + " should be annotated with @" + ConstantParameter.class.getSimpleName() + " or @" + VarargsParameter.class.getSimpleName() + " in " + - MetaUtil.format("%H.%n(%p)", method); - } return true; } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -24,6 +24,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.WriteNode.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.word.*; @@ -63,7 +64,7 @@ public void lower(LoweringTool tool) { StructuredGraph graph = (StructuredGraph) this.graph(); IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), displacement, offset, graph, 1); - WriteNode write = graph.add(new WriteNode(object, value, location)); + WriteNode write = graph.add(new WriteNode(object, value, location, WriteBarrierType.NONE)); graph.replaceFixedWithFixed(this, write); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -47,7 +47,7 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitLoad(readKind, gen.operand(address), 0, Value.ILLEGAL, 0, false)); + gen.setResult(this, gen.emitLoad(readKind, gen.operand(address), 0, Value.ILLEGAL, 0, null)); } @SuppressWarnings("unchecked") diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -50,7 +50,7 @@ @Override public void generate(LIRGeneratorTool gen) { Value v = gen.operand(value); - gen.emitStore(kind, gen.operand(address), 0, Value.ILLEGAL, 0, v, false); + gen.emitStore(kind, gen.operand(address), 0, Value.ILLEGAL, 0, v, null); } /* diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -41,7 +41,7 @@ private final JavaType returnType; protected MacroNode(Invoke invoke) { - super(invoke.node().stamp(), invoke.stateAfter()); + super(invoke.asNode().stamp(), invoke.stateAfter()); this.arguments = new NodeInputList<>(this, invoke.methodCallTarget().arguments()); this.bci = invoke.bci(); this.targetMethod = invoke.methodCallTarget().targetMethod(); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -107,6 +107,8 @@ return ConstantNode.forDouble(Math.cos(value), graph()); case TAN: return ConstantNode.forDouble(Math.tan(value), graph()); + default: + throw GraalInternalError.shouldNotReachHere(); } } return this; diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.service.processor/src/com/oracle/graal/service/processor/ServiceProviderProcessor.java --- a/graal/com.oracle.graal.service.processor/src/com/oracle/graal/service/processor/ServiceProviderProcessor.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.service.processor/src/com/oracle/graal/service/processor/ServiceProviderProcessor.java Mon Apr 15 08:51:19 2013 +0200 @@ -29,6 +29,7 @@ import javax.lang.model.*; import javax.lang.model.element.*; import javax.lang.model.type.*; +import javax.lang.model.util.*; import javax.tools.Diagnostic.Kind; import javax.tools.*; @@ -81,27 +82,57 @@ return true; } + private void processElement(TypeElement serviceProvider) { + ServiceProvider annotation = serviceProvider.getAnnotation(ServiceProvider.class); + if (annotation != null) { + try { + annotation.value(); + } catch (MirroredTypeException ex) { + TypeMirror serviceInterface = ex.getTypeMirror(); + if (verifyAnnotation(serviceInterface, serviceProvider)) { + String interfaceName = ex.getTypeMirror().toString(); + addProvider(interfaceName, serviceProvider); + } + } + } + } + + private void processOldElements() { + Filer filer = processingEnv.getFiler(); + Elements elements = processingEnv.getElementUtils(); + for (String key : serviceMap.keySet()) { + String filename = "META-INF/services/" + key; + try { + FileObject servicesFile = filer.getResource(StandardLocation.CLASS_OUTPUT, "", filename); + BufferedReader reader = new BufferedReader(new InputStreamReader(servicesFile.openInputStream(), "UTF-8")); + String line; + while ((line = reader.readLine()) != null) { + TypeElement serviceProvider = elements.getTypeElement(line); + if (serviceProvider != null) { + processElement(serviceProvider); + } + } + reader.close(); + servicesFile.delete(); + } catch (IOException e) { + // old services file not found: do nothing + } + } + } + @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { if (roundEnv.processingOver()) { + processOldElements(); generateServicesFiles(); return true; } for (Element element : roundEnv.getElementsAnnotatedWith(ServiceProvider.class)) { assert element.getKind().isClass(); - ServiceProvider annotation = element.getAnnotation(ServiceProvider.class); - try { - annotation.value(); - } catch (MirroredTypeException ex) { - TypeMirror serviceInterface = ex.getTypeMirror(); - TypeElement serviceProvider = (TypeElement) element; - if (verifyAnnotation(serviceInterface, serviceProvider)) { - String interfaceName = ex.getTypeMirror().toString(); - addProvider(interfaceName, serviceProvider); - } - } + processElement((TypeElement) element); } + return true; } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/CyclicMaterializeStoreNode.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/CyclicMaterializeStoreNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/CyclicMaterializeStoreNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -30,9 +30,6 @@ import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.virtual.*; -/** - * The {@code StoreFieldNode} represents a write to a static or instance field. - */ @NodeInfo(nameTemplate = "MaterializeStore#{p#target/s}") public final class CyclicMaterializeStoreNode extends FixedWithNextNode implements Lowerable, Virtualizable { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializeObjectNode.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializeObjectNode.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializeObjectNode.java Mon Apr 15 08:51:19 2013 +0200 @@ -25,7 +25,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.virtual.*; @@ -44,10 +43,18 @@ this.values = new NodeInputList<>(this, virtualObject.entryCount()); } - public NodeInputList values() { + public NodeInputList getValues() { return values; } + public VirtualObjectNode getVirtualObject() { + return virtualObject; + } + + public int getLockCount() { + return lockCount; + } + @Override public ValueNode length() { assert virtualObject.type().isArray(); @@ -73,38 +80,7 @@ @Override public void lower(LoweringTool tool) { - StructuredGraph graph = (StructuredGraph) graph(); - - boolean defaultValuesOnly = isDefault(); - - if (virtualObject instanceof VirtualInstanceNode) { - VirtualInstanceNode virtual = (VirtualInstanceNode) virtualObject; - - NewInstanceNode newInstance = graph.add(new NewInstanceNode(virtual.type(), defaultValuesOnly, lockCount > 0)); - this.replaceAtUsages(newInstance); - graph.addBeforeFixed(this, newInstance); - - if (!defaultValuesOnly) { - for (int i = 0; i < virtual.entryCount(); i++) { - graph.addBeforeFixed(this, graph.add(new StoreFieldNode(newInstance, virtual.field(i), values.get(i)))); - } - } - } else { - assert virtualObject instanceof VirtualArrayNode; - VirtualArrayNode virtual = (VirtualArrayNode) virtualObject; - - ResolvedJavaType element = virtual.componentType(); - NewArrayNode newArray = graph.add(new NewArrayNode(element, ConstantNode.forInt(virtual.entryCount(), graph), defaultValuesOnly, lockCount > 0)); - this.replaceAtUsages(newArray); - graph.addBeforeFixed(this, newArray); - - if (!defaultValuesOnly) { - for (int i = 0; i < virtual.entryCount(); i++) { - graph.addBeforeFixed(this, graph.add(new StoreIndexedNode(newArray, ConstantNode.forInt(i, graph), element.getKind(), values.get(i)))); - } - } - } - graph.removeFixed(this); + virtualObject.materializeAt(this, values, isDefault(), lockCount); } @Override diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java Mon Apr 15 08:51:19 2013 +0200 @@ -40,7 +40,7 @@ private final IdentityHashMap objectStates = new IdentityHashMap<>(); private final IdentityHashMap objectAliases; private final IdentityHashMap scalarAliases; - private final HashMap readCache; + final HashMap readCache; static class ReadCacheEntry { @@ -167,8 +167,6 @@ ValueNode[] fieldState = obj.getEntries(); - // some entries are not default constants - do the materialization - virtual.materializeAt(fixed); MaterializeObjectNode materialize = new MaterializeObjectNode(virtual, obj.getLockCount()); ValueNode[] values = new ValueNode[obj.getEntries().length]; materialize.setProbability(fixed.probability()); @@ -249,70 +247,13 @@ return objectStates.values(); } - public Iterable getVirtualObjects() { + public Collection getVirtualObjects() { return objectAliases.values(); } @Override public String toString() { - return objectStates.toString(); - } - - public void mergeReadCache(List states, MergeNode merge, GraphEffectList effects) { - for (Map.Entry entry : states.get(0).readCache.entrySet()) { - ReadCacheEntry key = entry.getKey(); - ValueNode value = entry.getValue(); - boolean phi = false; - for (int i = 1; i < states.size(); i++) { - ValueNode otherValue = states.get(i).readCache.get(key); - if (otherValue == null) { - value = null; - phi = false; - break; - } - if (!phi && otherValue != value) { - phi = true; - } - } - if (phi) { - PhiNode phiNode = new PhiNode(value.kind(), merge); - effects.addFloatingNode(phiNode); - for (int i = 0; i < states.size(); i++) { - effects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity)); - } - readCache.put(key, phiNode); - } else if (value != null) { - readCache.put(key, value); - } - } - for (PhiNode phi : merge.phis()) { - if (phi.kind() == Kind.Object) { - for (Map.Entry entry : states.get(0).readCache.entrySet()) { - if (entry.getKey().object == phi.valueAt(0)) { - mergeReadCachePhi(phi, entry.getKey().identity, states, merge, effects); - } - } - - } - } - } - - private void mergeReadCachePhi(PhiNode phi, Object identity, List states, MergeNode merge, GraphEffectList effects) { - ValueNode[] values = new ValueNode[phi.valueCount()]; - for (int i = 0; i < phi.valueCount(); i++) { - ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity); - if (value == null) { - return; - } - values[i] = value; - } - - PhiNode phiNode = new PhiNode(values[0].kind(), merge); - effects.addFloatingNode(phiNode); - for (int i = 0; i < values.length; i++) { - effects.addPhiInput(phiNode, values[i]); - } - readCache.put(new ReadCacheEntry(identity, phi), phiNode); + return objectStates + " " + readCache; } public static BlockState meetAliases(List states) { @@ -349,4 +290,38 @@ return readCache; } + public boolean equivalentTo(BlockState other) { + if (this == other) { + return true; + } + boolean objectAliasesEqual = compareMaps(objectAliases, other.objectAliases); + boolean objectStatesEqual = compareMaps(objectStates, other.objectStates); + boolean readCacheEqual = compareMapsNoSize(readCache, other.readCache); + boolean scalarAliasesEqual = scalarAliases.equals(other.scalarAliases); + return objectAliasesEqual && objectStatesEqual && readCacheEqual && scalarAliasesEqual; + } + + private static boolean compareMaps(Map left, Map right) { + if (left.size() != right.size()) { + return false; + } + return compareMapsNoSize(left, right); + } + + private static boolean compareMapsNoSize(Map left, Map right) { + if (left == right) { + return true; + } + for (Map.Entry entry : right.entrySet()) { + K key = entry.getKey(); + V value = entry.getValue(); + assert value != null; + V otherValue = left.get(key); + if (otherValue != value && !value.equals(otherValue)) { + return false; + } + } + return true; + } + } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectList.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectList.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectList.java Mon Apr 15 08:51:19 2013 +0200 @@ -73,48 +73,47 @@ public abstract void apply(StructuredGraph graph, ArrayList obsoleteNodes); } - private Effect[] effects = new Effect[16]; - private int[] level = new int[16]; + private static final Effect[] EMPTY_ARRAY = new Effect[0]; + + private Effect[] effects = EMPTY_ARRAY; private int size; - private int currentLevel; + + private void enlarge(int elements) { + int length = effects.length; + if (size + elements > length) { + while (size + elements > length) { + length = Math.max(length * 2, 4); + } + effects = Arrays.copyOf(effects, length); + } + } public void add(Effect effect) { - if (effects.length == size) { - effects = Arrays.copyOf(effects, effects.length * 2); - level = Arrays.copyOf(level, effects.length); - } - level[size] = currentLevel; + assert effect != null; + enlarge(1); effects[size++] = effect; } public void addAll(Collection list) { - int length = effects.length; - if (size + list.size() > length) { - while (size + list.size() > length) { - length *= 2; - } - effects = Arrays.copyOf(effects, length); - level = Arrays.copyOf(level, effects.length); - } + enlarge(list.size()); for (Effect effect : list) { - level[size] = currentLevel; + assert effect != null; effects[size++] = effect; } } public void addAll(EffectList list) { - int length = effects.length; - if (size + list.size > length) { - while (size + list.size > length) { - length *= 2; - } - effects = Arrays.copyOf(effects, length); - level = Arrays.copyOf(level, effects.length); - } - for (Effect effect : list) { - level[size] = currentLevel; - effects[size++] = effect; - } + enlarge(list.size); + System.arraycopy(list.effects, 0, effects, size, list.size); + size += list.size; + } + + public void insertAll(EffectList list, int position) { + assert position >= 0 && position <= size; + enlarge(list.size); + System.arraycopy(effects, position, effects, position + list.size, size - position); + System.arraycopy(list.effects, 0, effects, position, list.size); + size += list.size; } public int checkpoint() { @@ -154,14 +153,6 @@ }; } - public void incLevel() { - currentLevel++; - } - - public void decLevel() { - currentLevel--; - } - public Effect get(int index) { if (index >= size) { throw new IndexOutOfBoundsException(); @@ -169,13 +160,6 @@ return effects[index]; } - public int levelAt(int index) { - if (index >= size) { - throw new IndexOutOfBoundsException(); - } - return level[index]; - } - public void clear() { size = 0; } @@ -190,9 +174,6 @@ for (int i = 0; i < size(); i++) { Effect effect = get(i); if (effect.isVisible()) { - for (int i2 = 0; i2 < levelAt(i); i2++) { - str.append(" "); - } str.append(effect).append('\n'); } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Mon Apr 15 08:51:19 2013 +0200 @@ -104,17 +104,17 @@ * * @param node The floating node to be added. */ - public void addFloatingNode(final ValueNode node) { + public void addFloatingNode(final ValueNode node, final String cause) { add(new Effect() { @Override public String name() { - return "addFloatingNode"; + return "addFloatingNode " + cause; } @Override public void apply(StructuredGraph graph, ArrayList obsoleteNodes) { - assert !node.isAlive() && !node.isDeleted(); + assert !node.isAlive() && !node.isDeleted() : node + " " + cause; graph.add(node); } }); @@ -142,7 +142,7 @@ graph.addBeforeFixed(position, graph.add(node)); node.setProbability(position.probability()); for (int i = 0; i < values.length; i++) { - node.values().set(i, values[i]); + node.getValues().set(i, values[i]); } } }); @@ -164,7 +164,7 @@ @Override public void apply(StructuredGraph graph, ArrayList obsoleteNodes) { - assert node.isAlive() && value.isAlive(); + assert node.isAlive() && value.isAlive() : node + " " + value; node.addInput(value); } }); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -25,26 +25,24 @@ import java.util.*; import java.util.concurrent.*; -import com.oracle.graal.api.code.*; import com.oracle.graal.debug.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; -public class IterativeInliningPhase extends Phase { +public class IterativeInliningPhase extends BasePhase { private final PhasePlan plan; - private final GraalCodeCacheProvider runtime; - private final Assumptions assumptions; + private final Replacements replacements; private final GraphCache cache; private final OptimisticOptimizations optimisticOpts; private final boolean readElimination; - public IterativeInliningPhase(GraalCodeCacheProvider runtime, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts, boolean readElimination) { - this.runtime = runtime; - this.assumptions = assumptions; + public IterativeInliningPhase(Replacements replacements, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts, boolean readElimination) { + this.replacements = replacements; this.cache = cache; this.plan = plan; this.optimisticOpts = optimisticOpts; @@ -58,12 +56,12 @@ } @Override - protected void run(final StructuredGraph graph) { - runIterations(graph, true); - runIterations(graph, false); + protected void run(final StructuredGraph graph, final HighTierContext context) { + runIterations(graph, true, context); + runIterations(graph, false, context); } - private void runIterations(final StructuredGraph graph, final boolean simple) { + private void runIterations(final StructuredGraph graph, final boolean simple, final HighTierContext context) { Boolean continueIteration = true; for (int iteration = 0; iteration < GraalOptions.EscapeAnalysisIterations && continueIteration; iteration++) { continueIteration = Debug.scope("iteration " + iteration, new Callable() { @@ -71,13 +69,13 @@ @Override public Boolean call() { boolean progress = false; - PartialEscapeAnalysisPhase ea = new PartialEscapeAnalysisPhase(runtime, assumptions, false, readElimination); - ea.apply(graph); - progress |= ea.hasChanged(); + PartialEscapeAnalysisPhase ea = new PartialEscapeAnalysisPhase(false, readElimination); + boolean eaResult = ea.runAnalysis(graph, context); + progress |= eaResult; Map hints = GraalOptions.PEAInliningHints ? PartialEscapeAnalysisPhase.getHints(graph) : null; - InliningPhase inlining = new InliningPhase(runtime, hints, assumptions, cache, plan, optimisticOpts); + InliningPhase inlining = new InliningPhase(context.getRuntime(), hints, replacements, context.getAssumptions(), cache, plan, optimisticOpts); inlining.setMaxMethodsPerInlining(simple ? 1 : Integer.MAX_VALUE); inlining.apply(graph); progress |= inlining.getInliningCount() > 0; @@ -85,8 +83,8 @@ new DeadCodeEliminationPhase().apply(graph); if (GraalOptions.ConditionalElimination && GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(runtime, assumptions).apply(graph); - new IterativeConditionalEliminationPhase(runtime, assumptions).apply(graph); + new CanonicalizerPhase().apply(graph, context); + new IterativeConditionalEliminationPhase(context.getRuntime(), context.getAssumptions()).apply(graph); } return progress; diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,6 +22,8 @@ */ package com.oracle.graal.virtual.phases.ea; +import java.util.*; + import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; @@ -144,4 +146,48 @@ return str.append('}').toString(); } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Arrays.hashCode(entries); + result = prime * result + lockCount; + result = prime * result + ((materializedValue == null) ? 0 : materializedValue.hashCode()); + result = prime * result + ((state == null) ? 0 : state.hashCode()); + result = prime * result + ((virtual == null) ? 0 : virtual.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + ObjectState other = (ObjectState) obj; + if (!Arrays.equals(entries, other.entries)) { + return false; + } + if (lockCount != other.lockCount) { + return false; + } + if (materializedValue == null) { + if (other.materializedValue != null) { + return false; + } + } else if (!materializedValue.equals(other.materializedValue)) { + return false; + } + if (state != other.state) { + return false; + } + assert virtual != null && other.virtual != null; + if (!virtual.equals(other.virtual)) { + return false; + } + return true; + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -25,12 +25,10 @@ import java.util.*; import java.util.concurrent.*; -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.debug.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; @@ -38,34 +36,25 @@ import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer; import com.oracle.graal.phases.graph.*; import com.oracle.graal.phases.schedule.*; +import com.oracle.graal.phases.tiers.*; import com.oracle.graal.virtual.nodes.*; -import com.oracle.graal.virtual.phases.ea.EffectList.Effect; -public class PartialEscapeAnalysisPhase extends Phase { +public class PartialEscapeAnalysisPhase extends BasePhase { - private final MetaAccessProvider runtime; - private final Assumptions assumptions; - private CustomCanonicalizer customCanonicalizer; + private final CustomCanonicalizer customCanonicalizer; private final boolean iterative; private final boolean readElimination; - private boolean changed; + public PartialEscapeAnalysisPhase(boolean iterative, boolean readElimination) { + this(null, iterative, readElimination); + } - public PartialEscapeAnalysisPhase(MetaAccessProvider runtime, Assumptions assumptions, boolean iterative, boolean readElimination) { - this.runtime = runtime; - this.assumptions = assumptions; + public PartialEscapeAnalysisPhase(CustomCanonicalizer customCanonicalizer, boolean iterative, boolean readElimination) { + this.customCanonicalizer = customCanonicalizer; this.iterative = iterative; this.readElimination = readElimination; } - public boolean hasChanged() { - return changed; - } - - public void setCustomCanonicalizer(CustomCanonicalizer customCanonicalizer) { - this.customCanonicalizer = customCanonicalizer; - } - public static final void trace(String format, Object... obj) { if (GraalOptions.TraceEscapeAnalysis) { Debug.log(format, obj); @@ -73,9 +62,13 @@ } @Override - protected void run(final StructuredGraph graph) { + protected void run(StructuredGraph graph, HighTierContext context) { + runAnalysis(graph, context); + } + + public boolean runAnalysis(final StructuredGraph graph, final HighTierContext context) { if (!matches(graph, GraalOptions.EscapeAnalyzeOnly)) { - return; + return false; } if (!readElimination) { @@ -87,33 +80,29 @@ } } if (!analyzableNodes) { - return; + return false; } } - Boolean continueIteration = true; + boolean continueIteration = true; + boolean changed = false; for (int iteration = 0; iteration < GraalOptions.EscapeAnalysisIterations && continueIteration; iteration++) { - continueIteration = Debug.scope("iteration " + iteration, new Callable() { + boolean currentChanged = Debug.scope("iteration " + iteration, new Callable() { @Override public Boolean call() { SchedulePhase schedule = new SchedulePhase(); schedule.apply(graph, false); - PartialEscapeClosure closure = new PartialEscapeClosure(graph.createNodeBitMap(), schedule, runtime, assumptions); + PartialEscapeClosure closure = new PartialEscapeClosure(graph.createNodeBitMap(), schedule, context.getRuntime(), context.getAssumptions()); ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock(), new BlockState(), null); if (!closure.hasChanged()) { return false; } - changed = true; // apply the effects collected during the escape analysis iteration - ArrayList obsoleteNodes = new ArrayList<>(); - for (Effect effect : closure.getEffects()) { - effect.apply(graph, obsoleteNodes); - } - trace("%s\n", closure.getEffects()); + List obsoleteNodes = closure.applyEffects(graph); Debug.dump(graph, "after PartialEscapeAnalysis iteration"); assert noObsoleteNodes(graph, obsoleteNodes); @@ -121,21 +110,17 @@ new DeadCodeEliminationPhase().apply(graph); if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(runtime, assumptions, null, customCanonicalizer).apply(graph); + new CanonicalizerPhase.Instance(context.getRuntime(), context.getAssumptions(), null, customCanonicalizer).apply(graph); } - return iterative; + return true; } }); + continueIteration = currentChanged && iterative; + changed |= currentChanged; } - if (DynamicCounterNode.enabled && readElimination) { - for (Node node : graph.getNodes()) { - if (node instanceof LoadFieldNode) { - DynamicCounterNode.addCounterBefore("load non-elim", 1, false, (FixedNode) node); - } - } - } + return changed; } private static boolean matches(StructuredGraph graph, String filter) { @@ -146,7 +131,7 @@ return true; } - static boolean noObsoleteNodes(StructuredGraph graph, ArrayList obsoleteNodes) { + static boolean noObsoleteNodes(StructuredGraph graph, List obsoleteNodes) { // helper code that determines the paths that keep obsolete nodes alive: NodeFlood flood = graph.createNodeFlood(); @@ -196,14 +181,13 @@ } } } - boolean success = true; for (Node node : obsoleteNodes) { if (flood.isMarked(node)) { - System.out.print("offending node path:"); + TTY.print("offending node path:"); Node current = node; while (current != null) { - System.out.println(current.toString()); + TTY.println(current.toString()); current = path.get(current); if (current != null && current instanceof FixedNode && !obsoleteNodes.contains(current)) { break; diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Mon Apr 15 08:51:19 2013 +0200 @@ -46,6 +46,7 @@ import com.oracle.graal.phases.schedule.*; import com.oracle.graal.virtual.nodes.*; import com.oracle.graal.virtual.phases.ea.BlockState.ReadCacheEntry; +import com.oracle.graal.virtual.phases.ea.EffectList.Effect; class PartialEscapeClosure extends BlockIteratorClosure { @@ -65,7 +66,8 @@ private final NodeBitMap usages; private final SchedulePhase schedule; - private final GraphEffectList effects = new GraphEffectList(); + private final BlockMap blockEffects; + private final IdentityHashMap loopMergeEffects = new IdentityHashMap<>(); private final VirtualizerToolImpl tool; @@ -76,19 +78,57 @@ public PartialEscapeClosure(NodeBitMap usages, SchedulePhase schedule, MetaAccessProvider metaAccess, Assumptions assumptions) { this.usages = usages; this.schedule = schedule; - tool = new VirtualizerToolImpl(effects, usages, metaAccess, assumptions); + this.tool = new VirtualizerToolImpl(usages, metaAccess, assumptions); + this.blockEffects = new BlockMap<>(schedule.getCFG()); + for (Block block : schedule.getCFG().getBlocks()) { + blockEffects.put(block, new GraphEffectList()); + } } public boolean hasChanged() { return changed; } - public GraphEffectList getEffects() { - return effects; - } + public List applyEffects(final StructuredGraph graph) { + final ArrayList obsoleteNodes = new ArrayList<>(); + BlockIteratorClosure closure = new BlockIteratorClosure() { + + private void apply(GraphEffectList effects, Object context) { + if (!effects.isEmpty()) { + Debug.log(" ==== effects for %s", context); + for (Effect effect : effects) { + effect.apply(graph, obsoleteNodes); + if (effect.isVisible()) { + Debug.log(" %s", effect); + } + } + } + } - public int getNewVirtualObjectCount() { - return tool.getNewVirtualObjectCount(); + @Override + protected void processBlock(Block block, Object currentState) { + apply(blockEffects.get(block), block); + } + + @Override + protected Object merge(Block merge, List states) { + return new Object(); + } + + @Override + protected Object cloneState(Object oldState) { + return oldState; + } + + @Override + protected List processLoop(Loop loop, Object initialState) { + LoopInfo info = ReentrantBlockIterator.processLoop(this, loop, initialState); + apply(loopMergeEffects.get(loop), loop); + return info.exitStates; + } + }; + ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock(), new Object(), null); + return obsoleteNodes; } public Map getHints() { @@ -97,6 +137,9 @@ @Override protected void processBlock(Block block, BlockState state) { + GraphEffectList effects = blockEffects.get(block); + tool.setEffects(effects); + trace("\nBlock: %s (", block); List nodeList = schedule.getBlockToNodesMap().get(block); @@ -105,7 +148,7 @@ boolean deleted; if (usages.isMarked(node) || node instanceof VirtualizableAllocation) { trace("[[%s]] ", node); - deleted = processNode((ValueNode) node, lastFixedNode == null ? null : lastFixedNode.next(), state); + deleted = processNode((ValueNode) node, lastFixedNode == null ? null : lastFixedNode.next(), state, effects); } else { trace("%s ", node); deleted = false; @@ -119,7 +162,6 @@ state.killReadCache(store.field()); if (cachedValue == store.value()) { - effects.addCounterBefore("store elim", 1, false, lastFixedNode.next()); effects.deleteFixedNode(store); changed = true; } else { @@ -130,7 +172,6 @@ ValueNode cachedValue = state.getReadCache(load.object(), load.field()); if (cachedValue != null) { METRIC_LOADFIELD_ELIMINATED.increment(); - effects.addCounterBefore("load elim", 1, false, lastFixedNode.next()); effects.replaceAtUsages(load, cachedValue); state.addScalarAlias(load, cachedValue); changed = true; @@ -154,7 +195,7 @@ trace(")\n end state: %s\n", state); } - private boolean processNode(final ValueNode node, FixedNode insertBefore, final BlockState state) { + private boolean processNode(final ValueNode node, FixedNode insertBefore, final BlockState state, final GraphEffectList effects) { tool.reset(state, node); if (node instanceof Virtualizable) { ((Virtualizable) node).virtualize(tool); @@ -250,13 +291,13 @@ hints.put(invoke, 5d); } trace("replacing input %s at %s: %s", input, node, obj); - replaceWithMaterialized(input, node, insertBefore, state, obj, METRIC_MATERIALIZATIONS_UNHANDLED); + replaceWithMaterialized(input, node, insertBefore, state, obj, effects, METRIC_MATERIALIZATIONS_UNHANDLED); } } return false; } - private void ensureMaterialized(BlockState state, ObjectState obj, FixedNode materializeBefore, DebugMetric metric) { + private static void ensureMaterialized(BlockState state, ObjectState obj, FixedNode materializeBefore, GraphEffectList effects, DebugMetric metric) { assert obj != null; if (obj.getState() == EscapeState.Virtual) { metric.increment(); @@ -267,34 +308,204 @@ assert !obj.isVirtual(); } - private void replaceWithMaterialized(ValueNode value, Node usage, FixedNode materializeBefore, BlockState state, ObjectState obj, DebugMetric metric) { - ensureMaterialized(state, obj, materializeBefore, metric); + private static void replaceWithMaterialized(ValueNode value, Node usage, FixedNode materializeBefore, BlockState state, ObjectState obj, GraphEffectList effects, DebugMetric metric) { + ensureMaterialized(state, obj, materializeBefore, effects, metric); effects.replaceFirstInput(usage, value, obj.getMaterializedValue()); } @Override - protected BlockState merge(MergeNode merge, List states) { - BlockState newState = BlockState.meetAliases(states); + protected BlockState merge(Block merge, List states) { + assert blockEffects.get(merge).isEmpty(); + MergeProcessor processor = new MergeProcessor(merge, usages, blockEffects); + processor.merge(states); + blockEffects.get(merge).addAll(processor.mergeEffects); + blockEffects.get(merge).addAll(processor.afterMergeEffects); + return processor.newState; + + } + + @Override + protected BlockState cloneState(BlockState oldState) { + return oldState.cloneState(); + } + + @Override + protected List processLoop(Loop loop, BlockState initialState) { + BlockState loopEntryState = initialState; + BlockState lastMergedState = initialState; + MergeProcessor mergeProcessor = new MergeProcessor(loop.header, usages, blockEffects); + for (int iteration = 0; iteration < 10; iteration++) { + LoopInfo info = ReentrantBlockIterator.processLoop(this, loop, lastMergedState.cloneState()); + + List states = new ArrayList<>(); + states.add(initialState); + states.addAll(info.endStates); + mergeProcessor.merge(states); - // Iterative processing: - // Merging the materialized/virtual state of virtual objects can lead to new - // materializations, which can - // lead to new materializations because of phis, and so on. + Debug.log("================== %s", loop.header); + Debug.log("%s", mergeProcessor.newState); + Debug.log("===== vs."); + Debug.log("%s", lastMergedState); + + if (mergeProcessor.newState.equivalentTo(lastMergedState)) { + blockEffects.get(loop.header).insertAll(mergeProcessor.mergeEffects, 0); + loopMergeEffects.put(loop, mergeProcessor.afterMergeEffects); + + assert info.exitStates.size() == loop.exits.size(); + for (int i = 0; i < loop.exits.size(); i++) { + BlockState exitState = info.exitStates.get(i); + assert exitState != null : "no loop exit state at " + loop.exits.get(i) + " / " + loop.header; + processLoopExit((LoopExitNode) loop.exits.get(i).getBeginNode(), loopEntryState, exitState, blockEffects.get(loop.exits.get(i))); + } + + return info.exitStates; + } else { + lastMergedState = mergeProcessor.newState; + for (Block block : loop.blocks) { + blockEffects.get(block).clear(); + } + } + } + throw new GraalInternalError("too many iterations at %s", loop); + } + + private static void processLoopExit(LoopExitNode exitNode, BlockState initialState, BlockState exitState, GraphEffectList effects) { + HashMap proxies = new HashMap<>(); - boolean materialized; - do { - materialized = false; - // use a hash set to make the values distinct... - for (VirtualObjectNode object : newState.getVirtualObjects()) { - ObjectState resultState = newState.getObjectStateOptional(object); - if (resultState == null || resultState.isVirtual()) { + for (ProxyNode proxy : exitNode.proxies()) { + ObjectState obj = exitState.getObjectState(proxy.value()); + if (obj != null) { + proxies.put(obj.virtual, proxy); + } + } + for (ObjectState obj : exitState.getStates()) { + ObjectState initialObj = initialState.getObjectStateOptional(obj.virtual); + if (obj.isVirtual()) { + for (int i = 0; i < obj.getEntries().length; i++) { + ValueNode value = obj.getEntry(i); + ObjectState valueObj = exitState.getObjectState(value); + if (valueObj == null) { + if (exitNode.loopBegin().isPhiAtMerge(value) || initialObj == null || !initialObj.isVirtual() || initialObj.getEntry(i) != value) { + ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value, null); + obj.setEntry(i, proxy); + effects.addFloatingNode(proxy, "virtualProxy"); + } + } + } + } else { + if (initialObj == null || initialObj.isVirtual()) { + ProxyNode proxy = proxies.get(obj.virtual); + if (proxy == null) { + proxy = new ProxyNode(obj.getMaterializedValue(), exitNode, PhiType.Value, null); + effects.addFloatingNode(proxy, "proxy"); + } else { + effects.replaceFirstInput(proxy, proxy.value(), obj.getMaterializedValue()); + // nothing to do - will be handled in processNode + } + obj.updateMaterializedValue(proxy); + } else { + if (initialObj.getMaterializedValue() == obj.getMaterializedValue()) { + Debug.log("materialized value changes within loop: %s vs. %s at %s", initialObj.getMaterializedValue(), obj.getMaterializedValue(), exitNode); + } + } + } + } + + for (Map.Entry entry : exitState.getReadCache().entrySet()) { + if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) { + ProxyNode proxy = new ProxyNode(exitState.getReadCache(entry.getKey().object, entry.getKey().identity), exitNode, PhiType.Value, null); + effects.addFloatingNode(proxy, "readCacheProxy"); + entry.setValue(proxy); + } + } + } + + private static class MergeProcessor { + + private final Block mergeBlock; + private final MergeNode merge; + private final NodeBitMap usages; + private final BlockMap blockEffects; + private final GraphEffectList mergeEffects; + private final GraphEffectList afterMergeEffects; + + private final HashMap materializedPhis = new HashMap<>(); + private final IdentityHashMap valuePhis = new IdentityHashMap<>(); + private final IdentityHashMap valueObjectMergePhis = new IdentityHashMap<>(); + private final IdentityHashMap valueObjectVirtuals = new IdentityHashMap<>(); + private BlockState newState; + + public MergeProcessor(Block mergeBlock, NodeBitMap usages, BlockMap blockEffects) { + this.usages = usages; + this.mergeBlock = mergeBlock; + this.blockEffects = blockEffects; + this.merge = (MergeNode) mergeBlock.getBeginNode(); + this.mergeEffects = new GraphEffectList(); + this.afterMergeEffects = new GraphEffectList(); + } + + private PhiNode getCachedPhi(T virtual, Kind kind) { + PhiNode result = materializedPhis.get(virtual); + if (result == null) { + result = new PhiNode(kind, merge); + materializedPhis.put(virtual, result); + } + return result; + } + + private PhiNode[] getValuePhis(VirtualObjectNode virtual) { + PhiNode[] result = valuePhis.get(virtual); + if (result == null) { + result = new PhiNode[virtual.entryCount()]; + valuePhis.put(virtual, result); + } + return result; + } + + private PhiNode[] getValueObjectMergePhis(PhiNode phi, int entryCount) { + PhiNode[] result = valueObjectMergePhis.get(phi); + if (result == null) { + result = new PhiNode[entryCount]; + valueObjectMergePhis.put(phi, result); + } + return result; + } + + private VirtualObjectNode getValueObjectVirtual(PhiNode phi, VirtualObjectNode virtual) { + VirtualObjectNode result = valueObjectVirtuals.get(phi); + if (result == null) { + result = virtual.duplicate(); + valueObjectVirtuals.put(phi, result); + } + return result; + } + + private void merge(List states) { + newState = BlockState.meetAliases(states); + + /* + * Iterative processing: Merging the materialized/virtual state of virtual objects can + * lead to new materializations, which can lead to new materializations because of phis, + * and so on. + */ + + HashSet virtualObjects = new HashSet<>(newState.getVirtualObjects()); + boolean materialized; + do { + mergeEffects.clear(); + afterMergeEffects.clear(); + materialized = false; + for (VirtualObjectNode object : virtualObjects) { + ObjectState[] objStates = new ObjectState[states.size()]; + for (int i = 0; i < states.size(); i++) { + objStates[i] = states.get(i).getObjectState(object); + } int virtual = 0; - ObjectState startObj = states.get(0).getObjectState(object); + ObjectState startObj = objStates[0]; int lockCount = startObj.getLockCount(); boolean locksMatch = true; ValueNode singleValue = startObj.isVirtual() ? null : startObj.getMaterializedValue(); - for (BlockState state : states) { - ObjectState obj = state.getObjectState(object); + for (ObjectState obj : objStates) { if (obj.isVirtual()) { virtual++; singleValue = null; @@ -310,14 +521,15 @@ if (virtual < states.size()) { if (singleValue == null) { - PhiNode materializedValuePhi = new PhiNode(Kind.Object, merge); - effects.addFloatingNode(materializedValuePhi); + PhiNode materializedValuePhi = getCachedPhi(object, Kind.Object); + mergeEffects.addFloatingNode(materializedValuePhi, "materializedPhi"); for (int i = 0; i < states.size(); i++) { BlockState state = states.get(i); - ObjectState obj = state.getObjectState(object); + ObjectState obj = objStates[i]; materialized |= obj.isVirtual(); - ensureMaterialized(state, obj, merge.forwardEndAt(i), METRIC_MATERIALIZATIONS_MERGE); - effects.addPhiInput(materializedValuePhi, obj.getMaterializedValue()); + Block predecessor = mergeBlock.getPredecessors().get(i); + ensureMaterialized(state, obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); + afterMergeEffects.addPhiInput(materializedValuePhi, obj.getMaterializedValue()); } newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Global, lockCount)); } else { @@ -326,428 +538,188 @@ } else { assert virtual == states.size(); ValueNode[] values = startObj.getEntries().clone(); - PhiNode[] phis = new PhiNode[values.length]; - int mismatch = 0; - for (int i = 1; i < states.size(); i++) { - BlockState state = states.get(i); - ValueNode[] fields = state.getObjectState(object).getEntries(); - for (int index = 0; index < values.length; index++) { + PhiNode[] phis = getValuePhis(object); + for (int index = 0; index < values.length; index++) { + for (int i = 1; i < states.size(); i++) { + ValueNode[] fields = objStates[i].getEntries(); if (phis[index] == null && values[index] != fields[index]) { - mismatch++; phis[index] = new PhiNode(values[index].kind(), merge); - effects.addFloatingNode(phis[index]); } } } - if (mismatch > 0) { - for (int i = 0; i < states.size(); i++) { - BlockState state = states.get(i); - ValueNode[] fields = state.getObjectState(object).getEntries(); - for (int index = 0; index < values.length; index++) { - if (phis[index] != null) { - ObjectState obj = state.getObjectState(fields[index]); - if (obj != null) { - materialized |= obj.isVirtual(); - ensureMaterialized(state, obj, merge.forwardEndAt(i), METRIC_MATERIALIZATIONS_MERGE); - fields[index] = obj.getMaterializedValue(); - } - effects.addPhiInput(phis[index], fields[index]); + outer: for (int index = 0; index < values.length; index++) { + if (phis[index] != null) { + mergeEffects.addFloatingNode(phis[index], "virtualMergePhi"); + for (int i = 0; i < states.size(); i++) { + if (!objStates[i].isVirtual()) { + break outer; } + ValueNode[] fields = objStates[i].getEntries(); + ObjectState obj = states.get(i).getObjectState(fields[index]); + if (obj != null) { + materialized |= obj.isVirtual(); + Block predecessor = mergeBlock.getPredecessors().get(i); + ensureMaterialized(states.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); + fields[index] = obj.getMaterializedValue(); + } + afterMergeEffects.addPhiInput(phis[index], fields[index]); } - } - for (int index = 0; index < values.length; index++) { - if (phis[index] != null) { - values[index] = phis[index]; - } + values[index] = phis[index]; } } newState.addObject(object, new ObjectState(object, values, EscapeState.Virtual, lockCount)); } } - } - - for (PhiNode phi : merge.phis()) { - if (usages.isMarked(phi) && phi.type() == PhiType.Value) { - materialized |= processPhi(newState, merge, phi, states); - } - } - } while (materialized); - - newState.mergeReadCache(states, merge, effects); - - return newState; - } - private boolean processPhi(BlockState newState, MergeNode merge, PhiNode phi, List states) { - assert states.size() == phi.valueCount(); - int virtualInputs = 0; - boolean materialized = false; - VirtualObjectNode sameObject = null; - ResolvedJavaType sameType = null; - int sameEntryCount = -1; - for (int i = 0; i < phi.valueCount(); i++) { - ValueNode value = phi.valueAt(i); - ObjectState obj = states.get(i).getObjectState(value); - if (obj != null) { - if (obj.isVirtual()) { - virtualInputs++; - if (i == 0) { - sameObject = obj.virtual; - sameType = obj.virtual.type(); - sameEntryCount = obj.virtual.entryCount(); - } else { - if (sameObject != obj.virtual) { - sameObject = null; - } - if (sameType != obj.virtual.type()) { - sameType = null; - } - if (sameEntryCount != obj.virtual.entryCount()) { - sameEntryCount = -1; - } + for (PhiNode phi : merge.phis()) { + if (usages.isMarked(phi) && phi.type() == PhiType.Value) { + materialized |= processPhi(phi, states); } - } else { - effects.setPhiInput(phi, i, obj.getMaterializedValue()); } - } - } - boolean materialize = false; - if (virtualInputs == 0) { - // nothing to do... - } else if (virtualInputs == phi.valueCount()) { - if (sameObject != null) { - newState.addAndMarkAlias(sameObject, phi, usages); - } else if (sameType != null && sameEntryCount != -1) { - materialize = true; - // throw new GraalInternalError("merge required for %s", sameType); - } else { - materialize = true; - } - } else { - materialize = true; + } while (materialized); + + mergeReadCache(states); } - if (materialize) { + private boolean processPhi(PhiNode phi, List states) { + assert states.size() == phi.valueCount(); + int virtualInputs = 0; + boolean materialized = false; + VirtualObjectNode sameObject = null; + ResolvedJavaType sameType = null; + int sameEntryCount = -1; + boolean hasIdentity = false; for (int i = 0; i < phi.valueCount(); i++) { ValueNode value = phi.valueAt(i); ObjectState obj = states.get(i).getObjectState(value); if (obj != null) { - materialized |= obj.isVirtual(); - replaceWithMaterialized(value, phi, merge.forwardEndAt(i), states.get(i), obj, METRIC_MATERIALIZATIONS_PHI); - } - } - } - return materialized; - } - - @Override - protected BlockState cloneState(BlockState oldState) { - return oldState.cloneState(); - } - - @Override - protected List processLoop(Loop loop, BlockState initialState) { - GraphEffectList successEffects = new GraphEffectList(); - HashSet phis = new HashSet<>(); - for (int iteration = 0; iteration < 10; iteration++) { - BlockState state = initialState.cloneState(); - int checkpoint = effects.checkpoint(); - - for (PhiDesc desc : phis) { - ObjectState obj = state.getObjectState(desc.virtualObject); - if (obj.isVirtual()) { - ValueNode value = obj.getEntry(desc.fieldIndex); - ObjectState valueObj = state.getObjectState(value); - if (valueObj != null) { - assert !valueObj.isVirtual(); - value = valueObj.getMaterializedValue(); - } - - PhiNode phiNode = new PhiNode(value.kind(), loop.loopBegin()); - effects.addFloatingNode(phiNode); - effects.addPhiInput(phiNode, value); - obj.setEntry(desc.fieldIndex, phiNode); - } - } - - for (PhiNode phi : loop.loopBegin().phis()) { - if (usages.isMarked(phi) && phi.type() == PhiType.Value) { - ObjectState initialObj = initialState.getObjectState(phi.valueAt(0)); - if (initialObj != null) { - if (initialObj.isVirtual()) { - state.addAndMarkAlias(initialObj.virtual, phi, usages); + if (obj.isVirtual()) { + virtualInputs++; + if (i == 0) { + sameObject = obj.virtual; + sameType = obj.virtual.type(); + sameEntryCount = obj.virtual.entryCount(); } else { - successEffects.setPhiInput(phi, 0, initialObj.getMaterializedValue()); + if (sameObject != obj.virtual) { + sameObject = null; + } + if (sameType != obj.virtual.type()) { + sameType = null; + } + if (sameEntryCount != obj.virtual.entryCount()) { + sameEntryCount = -1; + } + hasIdentity |= obj.virtual.hasIdentity(); } + } else { + afterMergeEffects.setPhiInput(phi, i, obj.getMaterializedValue()); } } } - - effects.incLevel(); - LoopInfo info = ReentrantBlockIterator.processLoop(this, loop, state.cloneState()); - - List loopEndStates = info.endStates; - List predecessors = loop.header.getPredecessors(); - HashSet additionalMaterializations = new HashSet<>(); - HashSet additionalKilledReads = new HashSet<>(); - int oldPhiCount = phis.size(); - for (int i = 1; i < predecessors.size(); i++) { - processLoopEnd(loop.loopBegin(), (LoopEndNode) predecessors.get(i).getEndNode(), state, loopEndStates.get(i - 1), successEffects, additionalMaterializations, additionalKilledReads, - phis); - } - if (additionalMaterializations.isEmpty() && additionalKilledReads.isEmpty() && oldPhiCount == phis.size()) { - effects.addAll(successEffects); + boolean materialize = false; + if (virtualInputs == 0) { + // nothing to do... + } else if (virtualInputs == phi.valueCount()) { + if (sameObject != null) { + newState.addAndMarkAlias(sameObject, phi, usages); + } else if (sameType != null && sameEntryCount != -1) { + if (!hasIdentity) { + VirtualObjectNode virtual = getValueObjectVirtual(phi, states.get(0).getObjectState(phi.valueAt(0)).virtual); - assert info.exitStates.size() == loop.exits.size(); - for (int i = 0; i < loop.exits.size(); i++) { - BlockState exitState = info.exitStates.get(i); - assert exitState != null : "no loop exit state at " + loop.exits.get(i) + " / " + loop.header; - processLoopExit((LoopExitNode) loop.exits.get(i).getBeginNode(), state, exitState); + PhiNode[] phis = getValueObjectMergePhis(phi, virtual.entryCount()); + for (int i = 0; i < virtual.entryCount(); i++) { + assert virtual.entryKind(i) != Kind.Object; + if (phis[i] == null) { + phis[i] = new PhiNode(virtual.entryKind(i), merge); + } + mergeEffects.addFloatingNode(phis[i], "valueObjectPhi"); + for (int i2 = 0; i2 < phi.valueCount(); i2++) { + afterMergeEffects.addPhiInput(phis[i], states.get(i2).getObjectState(phi.valueAt(i2)).getEntry(i)); + } + } + mergeEffects.addFloatingNode(virtual, "valueObjectNode"); + newState.addObject(virtual, new ObjectState(virtual, Arrays.copyOf(phis, phis.length, ValueNode[].class), EscapeState.Virtual, 0)); + newState.addAndMarkAlias(virtual, virtual, usages); + newState.addAndMarkAlias(virtual, phi, usages); + } else { + materialize = true; + } + } else { + materialize = true; } - - effects.decLevel(); - return info.exitStates; } else { - successEffects.clear(); - effects.backtrack(checkpoint); - effects.decLevel(); - for (VirtualObjectNode virtualObject : additionalMaterializations) { - ObjectState obj = initialState.getObjectState(virtualObject); - if (obj.isVirtual()) { - METRIC_MATERIALIZATIONS_LOOP_REITERATION.increment(); - initialState.materializeBefore(loop.loopBegin().forwardEnd(), virtualObject, EscapeState.Global, effects); - } else { - assert obj.getState() == EscapeState.Global; + materialize = true; + } + + if (materialize) { + for (int i = 0; i < phi.valueCount(); i++) { + ValueNode value = phi.valueAt(i); + ObjectState obj = states.get(i).getObjectState(value); + if (obj != null) { + materialized |= obj.isVirtual(); + Block predecessor = mergeBlock.getPredecessors().get(i); + replaceWithMaterialized(value, phi, predecessor.getEndNode(), states.get(i), obj, blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_PHI); } } - for (ReadCacheEntry entry : additionalKilledReads) { - initialState.getReadCache().remove(entry); + } + return materialized; + } + + private void mergeReadCache(List states) { + for (Map.Entry entry : states.get(0).readCache.entrySet()) { + ReadCacheEntry key = entry.getKey(); + ValueNode value = entry.getValue(); + boolean phi = false; + for (int i = 1; i < states.size(); i++) { + ValueNode otherValue = states.get(i).readCache.get(key); + if (otherValue == null) { + value = null; + phi = false; + break; + } + if (!phi && otherValue != value) { + phi = true; + } + } + if (phi) { + PhiNode phiNode = getCachedPhi(entry, value.kind()); + mergeEffects.addFloatingNode(phiNode, "mergeReadCache"); + for (int i = 0; i < states.size(); i++) { + afterMergeEffects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity)); + } + newState.readCache.put(key, phiNode); + } else if (value != null) { + newState.readCache.put(key, value); + } + } + for (PhiNode phi : merge.phis()) { + if (phi.kind() == Kind.Object) { + for (Map.Entry entry : states.get(0).readCache.entrySet()) { + if (entry.getKey().object == phi.valueAt(0)) { + mergeReadCachePhi(phi, entry.getKey().identity, states); + } + } + } } } - throw new GraalInternalError("too many iterations at %s", loop); - } - - private void processLoopExit(LoopExitNode exitNode, BlockState initialState, BlockState exitState) { - HashMap proxies = new HashMap<>(); - - for (ProxyNode proxy : exitNode.proxies()) { - ObjectState obj = exitState.getObjectState(proxy.value()); - if (obj != null) { - proxies.put(obj.virtual, proxy); - } - } - for (ObjectState obj : exitState.getStates()) { - ObjectState initialObj = initialState.getObjectStateOptional(obj.virtual); - if (obj.isVirtual()) { - for (int i = 0; i < obj.getEntries().length; i++) { - ValueNode value = obj.getEntry(i); - ObjectState valueObj = exitState.getObjectState(value); - if (valueObj == null) { - if ((value instanceof PhiNode && ((PhiNode) value).merge() == exitNode.loopBegin()) || initialObj == null || !initialObj.isVirtual() || initialObj.getEntry(i) != value) { - ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value, null); - obj.setEntry(i, proxy); - effects.addFloatingNode(proxy); - } - } + private void mergeReadCachePhi(PhiNode phi, Object identity, List states) { + ValueNode[] values = new ValueNode[phi.valueCount()]; + for (int i = 0; i < phi.valueCount(); i++) { + ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity); + if (value == null) { + return; } - } else { - if (initialObj == null || initialObj.isVirtual()) { - ProxyNode proxy = proxies.get(obj.virtual); - if (proxy == null) { - proxy = new ProxyNode(obj.getMaterializedValue(), exitNode, PhiType.Value, null); - effects.addFloatingNode(proxy); - } else { - effects.replaceFirstInput(proxy, proxy.value(), obj.getMaterializedValue()); - // nothing to do - will be handled in processNode - } - obj.updateMaterializedValue(proxy); - } else { - assert initialObj.getMaterializedValue() == obj.getMaterializedValue() : "materialized value is not allowed to change within loops: " + initialObj.getMaterializedValue() + - " vs. " + obj.getMaterializedValue() + " at " + exitNode; - } - } - } - - for (Map.Entry entry : exitState.getReadCache().entrySet()) { - if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) { - ProxyNode proxy = new ProxyNode(exitState.getReadCache(entry.getKey().object, entry.getKey().identity), exitNode, PhiType.Value, null); - effects.addFloatingNode(proxy); - entry.setValue(proxy); + values[i] = value; } - } - } - - private final class PhiDesc { - - public final VirtualObjectNode virtualObject; - public final int fieldIndex; - - public PhiDesc(VirtualObjectNode virtualObject, int fieldIndex) { - this.virtualObject = virtualObject; - this.fieldIndex = fieldIndex; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = fieldIndex; - result = prime * result + ((virtualObject == null) ? 0 : virtualObject.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - PhiDesc other = (PhiDesc) obj; - return virtualObject == other.virtualObject && fieldIndex == other.fieldIndex; - } - } - - private void processLoopEnd(LoopBeginNode loopBegin, LoopEndNode loopEnd, BlockState initialState, BlockState loopEndState, GraphEffectList successEffects, - Set additionalMaterializations, HashSet additionalKilledReads, HashSet phis) { - assert loopEnd.loopBegin() == loopBegin; - boolean materialized; - do { - materialized = false; - for (ObjectState state : initialState.getStates()) { - ObjectState endState = loopEndState.getObjectState(state.virtual); - if (state.isVirtual()) { - if (endState.isVirtual()) { - assert state.getEntries().length == endState.getEntries().length; - for (int i = 0; endState.isVirtual() && i < state.getEntries().length; i++) { - ValueNode value = state.getEntry(i); - ValueNode endValue = endState.getEntry(i); - ObjectState valueObj = initialState.getObjectState(value); - ObjectState endValueObj = loopEndState.getObjectState(endValue); - if (valueObj != null) { - if (valueObj.isVirtual()) { - if (endValueObj == null || !endValueObj.isVirtual() || valueObj.virtual != endValueObj.virtual) { - additionalMaterializations.add(valueObj.virtual); - } else { - // endValue is also virtual and refers to the same virtual - // object, so we're - // good. - } - } - } else { - if (value instanceof PhiNode && ((PhiNode) value).merge() == loopBegin) { - if (endValueObj != null) { - if (endValueObj.isVirtual()) { - METRIC_MATERIALIZATIONS_LOOP_END.increment(); - loopEndState.materializeBefore(loopEnd, endValueObj.virtual, EscapeState.Global, successEffects); - materialized = true; - } - } - } - } - } - } else { - additionalMaterializations.add(state.virtual); - } - } - } - for (PhiNode phi : loopBegin.phis()) { - if (usages.isMarked(phi) && phi.type() == PhiType.Value) { - ObjectState initialObj = initialState.getObjectState(phi.valueAt(0)); - boolean initialMaterialized = initialObj == null || !initialObj.isVirtual(); - - ObjectState loopEndObj = loopEndState.getObjectState(phi.valueAt(loopEnd)); - if (loopEndObj == null || !loopEndObj.isVirtual()) { - if (loopEndObj != null) { - successEffects.setPhiInput(phi, loopBegin.phiPredecessorIndex(loopEnd), loopEndObj.getMaterializedValue()); - } - if (!initialMaterialized) { - additionalMaterializations.add(initialObj.virtual); - } - } else { - if (initialMaterialized) { - loopEndState.materializeBefore(loopEnd, loopEndObj.virtual, EscapeState.Global, successEffects); - materialized = true; - } else { - if (loopEndObj.virtual != initialObj.virtual) { - additionalMaterializations.add(initialObj.virtual); - } - } - } - } + PhiNode phiNode = getCachedPhi(new ReadCacheEntry(identity, phi), values[0].kind()); + mergeEffects.addFloatingNode(phiNode, "mergeReadCachePhi"); + for (int i = 0; i < values.length; i++) { + afterMergeEffects.addPhiInput(phiNode, values[i]); } - } while (materialized); - - for (ObjectState state : initialState.getStates()) { - ObjectState endState = loopEndState.getObjectState(state.virtual); - if (state.isVirtual()) { - if (endState.isVirtual()) { - assert state.getEntries().length == endState.getEntries().length; - for (int i = 0; i < state.getEntries().length; i++) { - ValueNode value = state.getEntry(i); - ValueNode endValue = endState.getEntry(i); - ObjectState valueObj = initialState.getObjectState(value); - ObjectState endValueObj = loopEndState.getObjectState(endValue); - - if (valueObj != null) { - if (valueObj.isVirtual()) { - if (endValueObj == null || !endValueObj.isVirtual() || valueObj.virtual != endValueObj.virtual) { - assert !additionalMaterializations.isEmpty(); - } else { - // endValue is also virtual and refers to the same virtual - // object, so we're - // good. - } - } else { - if ((endValueObj != null && endValueObj.getMaterializedValue() != valueObj.getMaterializedValue()) || - (endValueObj == null && valueObj.getMaterializedValue() != endValue)) { - phis.add(new PhiDesc(state.virtual, i)); - } else { - // either endValue has the same materialized value as value or - // endValue is the - // same as the materialized value, so we're good. - } - } - } else { - if (value instanceof PhiNode && ((PhiNode) value).merge() == loopBegin) { - if (endValueObj != null) { - if (endValueObj.isVirtual()) { - assert !additionalMaterializations.isEmpty(); - } - successEffects.addPhiInput((PhiNode) value, endValueObj.getMaterializedValue()); - } else { - successEffects.addPhiInput((PhiNode) value, endValue); - } - } else if (value != endValue) { - phis.add(new PhiDesc(state.virtual, i)); - } - } - } - } else { - // endState.materializedValue != null - assert !additionalMaterializations.isEmpty(); - } - } else { - // state.materializedValue != null - if (endState.isVirtual()) { - // throw new GraalInternalError("un-materialized object state at %s", loopEnd); - } else { - if (state.getMaterializedValue() != endState.getMaterializedValue()) { - // throw new - // GraalInternalError("changed materialized value during loop: %s vs %s", - // state.materializedValue, endState.materializedValue); - } - } - } - } - - for (Map.Entry entry : initialState.getReadCache().entrySet()) { - if (loopEndState.getReadCache().get(entry.getKey()) != entry.getValue()) { - additionalKilledReads.add(entry.getKey()); - } + newState.readCache.put(new ReadCacheEntry(identity, phi), phiNode); } } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Mon Apr 15 08:51:19 2013 +0200 @@ -36,13 +36,12 @@ class VirtualizerToolImpl implements VirtualizerTool { - private final GraphEffectList effects; private final NodeBitMap usages; private final MetaAccessProvider metaAccess; private final Assumptions assumptions; + private GraphEffectList effects; - VirtualizerToolImpl(GraphEffectList effects, NodeBitMap usages, MetaAccessProvider metaAccess, Assumptions assumptions) { - this.effects = effects; + VirtualizerToolImpl(NodeBitMap usages, MetaAccessProvider metaAccess, Assumptions assumptions) { this.usages = usages; this.metaAccess = metaAccess; this.assumptions = assumptions; @@ -52,7 +51,6 @@ private boolean customAction; private BlockState state; private ValueNode current; - private int newVirtualObjectCount = 0; @Override public MetaAccessProvider getMetaAccessProvider() { @@ -64,6 +62,10 @@ return assumptions; } + public void setEffects(GraphEffectList effects) { + this.effects = effects; + } + public void reset(BlockState newState, ValueNode newCurrent) { deleted = false; customAction = false; @@ -79,10 +81,6 @@ return customAction; } - public int getNewVirtualObjectCount() { - return newVirtualObjectCount; - } - @Override public State getObjectState(ValueNode value) { return state.getObjectState(value); @@ -155,7 +153,7 @@ if (virtualObject.isAlive()) { state.addAndMarkAlias(virtualObject, virtualObject, usages); } else { - effects.addFloatingNode(virtualObject); + effects.addFloatingNode(virtualObject, "newVirtualObject"); } for (int i = 0; i < entryState.length; i++) { entryState[i] = state.getScalarAlias(entryState[i]); @@ -163,7 +161,6 @@ state.addObject(virtualObject, new ObjectState(virtualObject, entryState, EscapeState.Virtual, lockCount)); state.addAndMarkAlias(virtualObject, virtualObject, usages); PartialEscapeClosure.METRIC_ALLOCATION_REMOVED.increment(); - newVirtualObjectCount++; } @Override diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.extended.WriteNode.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; @@ -140,7 +141,7 @@ case READ: assert arguments.size() == 2 || arguments.size() == 3; Kind readKind = asKind(callTargetNode.returnType()); - Object readLocation = arguments.size() == 2 ? LocationNode.UNKNOWN_LOCATION : arguments.get(2).asConstant().asObject(); + Object readLocation = arguments.size() == 2 ? LocationNode.ANY_LOCATION : arguments.get(2).asConstant().asObject(); replace(invoke, readOp(graph, arguments.get(0), arguments.get(1), invoke, readKind, readLocation)); break; @@ -183,7 +184,7 @@ case TO_OBJECT: assert arguments.size() == 1; - replace(invoke, graph.unique(new UnsafeCastNode(arguments.get(0), invoke.node().stamp()))); + replace(invoke, graph.unique(new UnsafeCastNode(arguments.get(0), invoke.asNode().stamp()))); break; default: @@ -227,7 +228,7 @@ Constructor constructor = nodeClass.getConstructor(Kind.class, ValueNode.class, ValueNode.class); ValueNode result = graph.add(constructor.newInstance(wordKind, left, right)); if (result instanceof FixedWithNextNode) { - graph.addBeforeFixed(invoke.node(), (FixedWithNextNode) result); + graph.addBeforeFixed(invoke.asNode(), (FixedWithNextNode) result); } return result; } catch (Throwable ex) { @@ -267,28 +268,28 @@ private static ValueNode readOp(StructuredGraph graph, ValueNode base, ValueNode offset, Invoke invoke, Kind readKind, Object locationIdentity) { IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, readKind, 0, offset, graph, 1); - ReadNode read = graph.add(new ReadNode(base, location, invoke.node().stamp())); - graph.addBeforeFixed(invoke.node(), read); + ReadNode read = graph.add(new ReadNode(base, location, invoke.asNode().stamp())); + graph.addBeforeFixed(invoke.asNode(), read); // The read must not float outside its block otherwise it may float above an explicit zero // check on its base address - read.dependencies().add(BeginNode.prevBegin(invoke.node())); + read.dependencies().add(BeginNode.prevBegin(invoke.asNode())); return read; } private static ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode offset, ValueNode value, Invoke invoke, Kind writeKind, Object locationIdentity) { IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, writeKind, 0, offset, graph, 1); - WriteNode write = graph.add(new WriteNode(base, value, location)); + WriteNode write = graph.add(new WriteNode(base, value, location, WriteBarrierType.NONE)); write.setStateAfter(invoke.stateAfter()); - graph.addBeforeFixed(invoke.node(), write); + graph.addBeforeFixed(invoke.asNode(), write); return write; } private static void replace(Invoke invoke, ValueNode value) { FixedNode next = invoke.next(); invoke.setNext(null); - invoke.node().replaceAtPredecessor(next); - invoke.node().replaceAtUsages(value); - GraphUtil.killCFG(invoke.node()); + invoke.asNode().replaceAtPredecessor(next); + invoke.asNode().replaceAtUsages(value); + GraphUtil.killCFG(invoke.asNode()); } public boolean isWord(ValueNode node) { diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java Mon Apr 15 08:51:19 2013 +0200 @@ -80,9 +80,9 @@ ValueNode receiver = arguments.get(argc); if (receiver == node && isWord(node)) { ResolvedJavaMethod resolvedMethod = wordAccess.getWordImplType().resolveMethod(method); - verify(resolvedMethod != null, node, invoke.node(), "cannot resolve method on Word class: " + MetaUtil.format("%H.%n(%P) %r", method)); + verify(resolvedMethod != null, node, invoke.asNode(), "cannot resolve method on Word class: " + MetaUtil.format("%H.%n(%P) %r", method)); Operation operation = resolvedMethod.getAnnotation(Word.Operation.class); - verify(operation != null, node, invoke.node(), "cannot dispatch on word value to non @Operation annotated method " + resolvedMethod); + verify(operation != null, node, invoke.asNode(), "cannot dispatch on word value to non @Operation annotated method " + resolvedMethod); } argc++; } @@ -91,7 +91,7 @@ ValueNode argument = arguments.get(argc); if (argument == node) { ResolvedJavaType type = (ResolvedJavaType) signature.getParameterType(i, method.getDeclaringClass()); - verify(isWord(type) == isWord(argument), node, invoke.node(), "cannot pass word value to non-word parameter " + i + " or vice-versa"); + verify(isWord(type) == isWord(argument), node, invoke.asNode(), "cannot pass word value to non-word parameter " + i + " or vice-versa"); } argc++; } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java Mon Apr 15 08:51:19 2013 +0200 @@ -61,7 +61,7 @@ dom = db.newDocument(); } catch (ParserConfigurationException ex) { - System.out.println("Error while trying to instantiate DocumentBuilder " + ex); + throw new RuntimeException(ex); } graphDocument = dom.createElement("graphDocument"); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java Mon Apr 15 08:51:19 2013 +0200 @@ -799,4 +799,8 @@ return true; } + public static boolean isObject(TypeMirror actualType) { + return getQualifiedName(actualType).equals("java.lang.Object"); + } + } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeElement.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeElement.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeElement.java Mon Apr 15 08:51:19 2013 +0200 @@ -103,19 +103,29 @@ return annotations; } - /* Support JDK8 langtools. */ - @SuppressWarnings("unused") + /** + * Support JDK8 langtools. + * + * @param annotationType + */ public A[] getAnnotationsByType(Class annotationType) { throw new UnsupportedOperationException(); } - /* Support for some JDK8 builds. (remove after jdk8 is released) */ - @SuppressWarnings("unused") + /** + * Support for some JDK8 builds. (remove after jdk8 is released) + * + * @param annotationType + */ public A[] getAnnotations(Class annotationType) { throw new UnsupportedOperationException(); } - @Override + /** + * Support for some JDK8 builds. (remove after jdk8 is released) + * + * @param annotationType + */ public A getAnnotation(Class annotationType) { throw new UnsupportedOperationException(); } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java Mon Apr 15 08:51:19 2013 +0200 @@ -225,4 +225,7 @@ return copy; } + public TypeMirror getReceiverType() { + throw new UnsupportedOperationException(); + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTypeMirror.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTypeMirror.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTypeMirror.java Mon Apr 15 08:51:19 2013 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.truffle.codegen.processor.ast; +import java.lang.annotation.*; import java.util.*; import javax.lang.model.element.*; @@ -92,4 +93,21 @@ } + public List getAnnotationMirrors() { + throw new UnsupportedOperationException(); + } + + /** + * @param annotationType + */ + public A getAnnotation(Class annotationType) { + throw new UnsupportedOperationException(); + } + + /** + * @param annotationType + */ + public A[] getAnnotationsByType(Class annotationType) { + throw new UnsupportedOperationException(); + } } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Mon Apr 15 08:51:19 2013 +0200 @@ -117,7 +117,7 @@ } } - private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) { + private static CodeTree createTemplateMethodCall(CodeTreeBuilder parent, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) { CodeTreeBuilder builder = parent.create(); boolean castedValues = sourceMethod != targetMethod; @@ -153,6 +153,7 @@ break; } } + ActualParameter sourceParameter = sourceMethod.findParameter(parameter.getLocalName()); assert parameter != null; if (castedValues) { @@ -160,12 +161,10 @@ if (field == null) { builder.string(valueName(parameter)); } else { - NodeData fieldNode = field.getNodeData(); - ExecutableTypeData execType = fieldNode.findExecutableType(parameter.getActualTypeData(node.getTypeSystem())); - if (execType.hasUnexpectedValue(getContext())) { + if (Utils.typeEquals(sourceParameter.getActualType(), parameter.getActualType())) { + builder.string(valueName(parameter)); + } else { builder.string(castValueName(parameter)); - } else { - builder.string(valueName(parameter)); } } } else { @@ -326,7 +325,7 @@ return builder.getRoot(); } - private CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { + private static CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; if (guardedSpecialization.getGuards().size() > 0) { @@ -1476,7 +1475,12 @@ builder.end(); // call replace builder.end(); // statement - String generatedMethodName = generatedGenericMethodName(specialization.findNextSpecialization()); + String generatedMethodName; + if (specialization.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) { + generatedMethodName = generatedGenericMethodName(null); + } else { + generatedMethodName = generatedGenericMethodName(specialization.findNextSpecialization()); + } ExecutableElement generatedGeneric = clazz.getEnclosingClass().getMethod(generatedMethodName); CodeTreeBuilder genericExecute = CodeTreeBuilder.createBuilder(); diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java Mon Apr 15 08:51:19 2013 +0200 @@ -61,7 +61,7 @@ } protected ParameterSpec createReturnParameterSpec() { - return createValueParameterSpec("operation", getNode()); + return createValueParameterSpec("returnValue", getNode()); } @Override diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Mon Apr 15 08:51:19 2013 +0200 @@ -62,7 +62,9 @@ if (node != null) { String dump = parsed.dump(); log.message(Kind.ERROR, null, null, null, dump); + // CheckStyle: stop system..print check System.out.println(dump); + // CheckStyle: resume system..print check } } } finally { @@ -108,8 +110,7 @@ } NodeData rootNode = parseNode(rootType); - boolean hasErrors = rootNode != null ? rootNode.hasErrors() : false; - if ((rootNode == null || hasErrors) && children.size() > 0) { + if (rootNode == null && children.size() > 0) { rootNode = new NodeData(rootType, rootType.getSimpleName().toString()); } @@ -152,6 +153,10 @@ NodeData nodeData = parseNodeData(type, nodeType); + if (nodeData.hasErrors()) { + return nodeData; // error sync point + } + if (Utils.typeEquals(nodeType.asType(), type.asType())) { // filter fields if they were not split. (field are accessible anyway) for (ListIterator iterator = nodeData.getFields().listIterator(); iterator.hasNext();) { @@ -162,10 +167,6 @@ } } - if (nodeData.hasErrors()) { - return nodeData; // error sync point - } - List elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type)); nodeData.setExtensionElements(getExtensionParser().parseAll(nodeData, elements)); if (nodeData.getExtensionElements() != null) { @@ -328,6 +329,23 @@ } if (genericSpecialization != null) { + if (genericSpecialization.isUseSpecializationsForGeneric()) { + for (ActualParameter parameter : genericSpecialization.getReturnTypeAndParameters()) { + if (Utils.isObject(parameter.getActualType())) { + continue; + } + Set types = new HashSet<>(); + for (SpecializationData specialization : specializations) { + ActualParameter actualParameter = specialization.findParameter(parameter.getLocalName()); + if (actualParameter != null) { + types.add(Utils.getQualifiedName(actualParameter.getActualType())); + } + } + if (types.size() > 1) { + genericSpecialization.replaceParameter(parameter.getLocalName(), new ActualParameter(parameter, node.getTypeSystem().getGenericType())); + } + } + } TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", node, genericSpecialization.getSpecification(), null, null, genericSpecialization.getReturnType(), genericSpecialization.getParameters()); // should not use messages from generic specialization diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Mon Apr 15 08:51:19 2013 +0200 @@ -194,4 +194,5 @@ public String toString() { return String.format("%s [id = %s, method = %s, guards = %s]", getClass().getSimpleName(), getId(), getMethod(), getGuards()); } + } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java Mon Apr 15 08:51:19 2013 +0200 @@ -49,6 +49,10 @@ this.localName = valueName; } + public ActualParameter(ActualParameter parameter, TypeMirror otherType) { + this(parameter.specification, otherType, parameter.index, parameter.implicit); + } + public boolean isImplicit() { return implicit; } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Mon Apr 15 08:51:19 2013 +0200 @@ -40,7 +40,7 @@ private final MethodSpec specification; private final ExecutableElement method; private final AnnotationMirror markerAnnotation; - private final ActualParameter returnType; + private ActualParameter returnType; private List parameters; public TemplateMethod(String id, Template template, MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, ActualParameter returnType, @@ -104,6 +104,21 @@ return returnType; } + public void replaceParameter(String localName, ActualParameter newParameter) { + if (returnType.getLocalName().equals(localName)) { + returnType = newParameter; + returnType.setMethod(this); + } + + for (ListIterator iterator = parameters.listIterator(); iterator.hasNext();) { + ActualParameter parameter = iterator.next(); + if (parameter.getLocalName().equals(localName)) { + iterator.set(newParameter); + newParameter.setMethod(this); + } + } + } + public List getRequiredParameters() { List requiredParameters = new ArrayList<>(); for (ActualParameter parameter : getParameters()) { @@ -119,7 +134,7 @@ } public ActualParameter findParameter(String valueName) { - for (ActualParameter param : getParameters()) { + for (ActualParameter param : getReturnTypeAndParameters()) { if (param.getLocalName().equals(valueName)) { return param; } diff -r 0298d8a0caf5 -r 79b098d44d20 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SimpleLanguage.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SimpleLanguage.java Thu Apr 04 11:57:04 2013 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SimpleLanguage.java Mon Apr 15 08:51:19 2013 +0200 @@ -37,7 +37,9 @@ public static void run(InputStream input, PrintStream printOutput, int repeats, boolean log) { if (log) { + // CheckStyle: stop system..print check System.out.printf("== running on %s\n", Truffle.getRuntime().getName()); + // CheckStyle: resume system..print check } NodeFactory factory = new NodeFactory(printOutput); @@ -63,7 +65,9 @@ printOutput.println(result); } if (log) { + // CheckStyle: stop system..print check System.out.printf("== iteration %d: %.3f ms\n", (i + 1), (end - start) / 1000000.0); + // CheckStyle: resume system..print check } } diff -r 0298d8a0caf5 -r 79b098d44d20 make/Makefile --- a/make/Makefile Thu Apr 04 11:57:04 2013 +0200 +++ b/make/Makefile Mon Apr 15 08:51:19 2013 +0200 @@ -582,6 +582,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 0298d8a0caf5 -r 79b098d44d20 make/bsd/Makefile --- a/make/bsd/Makefile Thu Apr 04 11:57:04 2013 +0200 +++ b/make/bsd/Makefile Mon Apr 15 08:51:19 2013 +0200 @@ -306,63 +306,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 0298d8a0caf5 -r 79b098d44d20 make/bsd/build.sh --- a/make/bsd/build.sh Thu Apr 04 11:57:04 2013 +0200 +++ /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 0298d8a0caf5 -r 79b098d44d20 make/bsd/makefiles/buildtree.make --- a/make/bsd/makefiles/buildtree.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/bsd/makefiles/buildtree.make Mon Apr 15 08:51:19 2013 +0200 @@ -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:$(OUTPUTDIR)/shared/graal.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 0298d8a0caf5 -r 79b098d44d20 make/bsd/makefiles/compiler1.make --- a/make/bsd/makefiles/compiler1.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/bsd/makefiles/compiler1.make Mon Apr 15 08:51:19 2013 +0200 @@ -32,4 +32,6 @@ ifndef OMIT_GRAAL CFLAGS += -DGRAAL +else + VM_SUBDIR = client-nograal endif \ No newline at end of file diff -r 0298d8a0caf5 -r 79b098d44d20 make/bsd/makefiles/compiler2.make --- a/make/bsd/makefiles/compiler2.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/bsd/makefiles/compiler2.make Mon Apr 15 08:51:19 2013 +0200 @@ -32,4 +32,6 @@ ifndef OMIT_GRAAL CFLAGS += -DGRAAL +else + VM_SUBDIR = server-nograal endif \ No newline at end of file diff -r 0298d8a0caf5 -r 79b098d44d20 make/bsd/makefiles/gcc.make --- a/make/bsd/makefiles/gcc.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/bsd/makefiles/gcc.make Mon Apr 15 08:51:19 2013 +0200 @@ -168,12 +168,12 @@ # 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" -ACCEPTABLE_WARNINGS = -Wpointer-arith -Wsign-compare +WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef else -ACCEPTABLE_WARNINGS = -Wpointer-arith -Wconversion -Wsign-compare +WARNING_FLAGS = -Wpointer-arith -Wconversion -Wsign-compare -Wundef endif -CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(ACCEPTABLE_WARNINGS) +CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(WARNING_FLAGS) # Special cases CFLAGS_WARN/BYFILE = $(CFLAGS_WARN/$@)$(CFLAGS_WARN/DEFAULT$(CFLAGS_WARN/$@)) # XXXDARWIN: for _dyld_bind_fully_image_containing_address @@ -229,6 +229,20 @@ CFLAGS += -DDONT_USE_PRECOMPILED_HEADER endif +ifeq ($(OS_VENDOR), Darwin) + # Setting these parameters makes it an error to link to macosx APIs that are + # newer than the given OS version and makes the linked binaries compatible even + # if built on a newer version of the OS. + # The expected format is X.Y.Z + ifeq ($(MACOSX_VERSION_MIN),) + MACOSX_VERSION_MIN=10.7.0 + endif + # The macro takes the version with no dots, ex: 1070 + CFLAGS += -DMAC_OS_X_VERSION_MAX_ALLOWED=$(subst .,,$(MACOSX_VERSION_MIN)) \ + -mmacosx-version-min=$(MACOSX_VERSION_MIN) + LDFLAGS += -mmacosx-version-min=$(MACOSX_VERSION_MIN) +endif + #------------------------------------------------------------------------ # Linker flags diff -r 0298d8a0caf5 -r 79b098d44d20 make/bsd/makefiles/mapfile-vers-debug --- a/make/bsd/makefiles/mapfile-vers-debug Thu Apr 04 11:57:04 2013 +0200 +++ b/make/bsd/makefiles/mapfile-vers-debug Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 make/bsd/makefiles/mapfile-vers-product --- a/make/bsd/makefiles/mapfile-vers-product Thu Apr 04 11:57:04 2013 +0200 +++ b/make/bsd/makefiles/mapfile-vers-product Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 make/bsd/makefiles/saproc.make --- a/make/bsd/makefiles/saproc.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/bsd/makefiles/saproc.make Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 make/bsd/makefiles/tiered.make --- a/make/bsd/makefiles/tiered.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/bsd/makefiles/tiered.make Mon Apr 15 08:51:19 2013 +0200 @@ -32,4 +32,6 @@ ifndef OMIT_GRAAL CFLAGS += -DGRAAL +else + VM_SUBDIR = server-nograal endif diff -r 0298d8a0caf5 -r 79b098d44d20 make/build-graal.xml --- a/make/build-graal.xml Thu Apr 04 11:57:04 2013 +0200 +++ b/make/build-graal.xml Mon Apr 15 08:51:19 2013 +0200 @@ -29,16 +29,16 @@ - + + - @@ -76,8 +76,10 @@ - + - + + + diff -r 0298d8a0caf5 -r 79b098d44d20 make/build.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/build.sh Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 make/defs.make --- a/make/defs.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/defs.make Mon Apr 15 08:51:19 2013 +0200 @@ -329,7 +329,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) @@ -365,9 +365,6 @@ EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jmm.h EXPORT_LIST += $(EXPORT_JRE_LIB_DIR)/graal.jar -# By default, run Queens test after building -TEST_IN_BUILD ?= true - ifndef JAVASE_EMBEDDED EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jfr.h endif diff -r 0298d8a0caf5 -r 79b098d44d20 make/excludeSrc.make --- a/make/excludeSrc.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/excludeSrc.make Mon Apr 15 08:51:19 2013 +0200 @@ -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) @@ -69,7 +70,7 @@ CXXFLAGS += -DINCLUDE_CDS=0 CFLAGS += -DINCLUDE_CDS=0 - Src_Files_EXCLUDE += metaspaceShared.cpp + Src_Files_EXCLUDE += filemap.cpp metaspaceShared.cpp endif ifeq ($(INCLUDE_ALL_GCS), false) diff -r 0298d8a0caf5 -r 79b098d44d20 make/hotspot_version --- a/make/hotspot_version Thu Apr 04 11:57:04 2013 +0200 +++ b/make/hotspot_version Mon Apr 15 08:51:19 2013 +0200 @@ -35,7 +35,7 @@ HS_MAJOR_VER=25 HS_MINOR_VER=0 -HS_BUILD_NUMBER=21 +HS_BUILD_NUMBER=28 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 diff -r 0298d8a0caf5 -r 79b098d44d20 make/jprt.properties --- a/make/jprt.properties Thu Apr 04 11:57:04 2013 +0200 +++ b/make/jprt.properties Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 make/linux/Makefile --- a/make/linux/Makefile Thu Apr 04 11:57:04 2013 +0200 +++ b/make/linux/Makefile Mon Apr 15 08:51:19 2013 +0200 @@ -306,63 +306,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 0298d8a0caf5 -r 79b098d44d20 make/linux/build.sh --- a/make/linux/build.sh Thu Apr 04 11:57:04 2013 +0200 +++ /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 0298d8a0caf5 -r 79b098d44d20 make/linux/makefiles/buildtree.make --- a/make/linux/makefiles/buildtree.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/linux/makefiles/buildtree.make Mon Apr 15 08:51:19 2013 +0200 @@ -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:$(OUTPUTDIR)/shared/graal.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 0298d8a0caf5 -r 79b098d44d20 make/linux/makefiles/compiler1.make --- a/make/linux/makefiles/compiler1.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/linux/makefiles/compiler1.make Mon Apr 15 08:51:19 2013 +0200 @@ -32,4 +32,6 @@ ifndef OMIT_GRAAL CFLAGS += -DGRAAL +else + VM_SUBDIR = client-nograal endif \ No newline at end of file diff -r 0298d8a0caf5 -r 79b098d44d20 make/linux/makefiles/compiler2.make --- a/make/linux/makefiles/compiler2.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/linux/makefiles/compiler2.make Mon Apr 15 08:51:19 2013 +0200 @@ -32,4 +32,6 @@ ifndef OMIT_GRAAL CFLAGS += -DGRAAL +else + VM_SUBDIR = server-nograal endif \ No newline at end of file diff -r 0298d8a0caf5 -r 79b098d44d20 make/linux/makefiles/gcc.make --- a/make/linux/makefiles/gcc.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/linux/makefiles/gcc.make Mon Apr 15 08:51:19 2013 +0200 @@ -126,17 +126,15 @@ # 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" -ACCEPTABLE_WARNINGS = -Wpointer-arith -Wsign-compare -else -ACCEPTABLE_WARNINGS = -Wpointer-arith -Wconversion -Wsign-compare +# 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) $(ACCEPTABLE_WARNINGS) +CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(WARNING_FLAGS) # Special cases CFLAGS_WARN/BYFILE = $(CFLAGS_WARN/$@)$(CFLAGS_WARN/DEFAULT$(CFLAGS_WARN/$@)) diff -r 0298d8a0caf5 -r 79b098d44d20 make/linux/makefiles/mapfile-vers-debug --- a/make/linux/makefiles/mapfile-vers-debug Thu Apr 04 11:57:04 2013 +0200 +++ b/make/linux/makefiles/mapfile-vers-debug Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 make/linux/makefiles/mapfile-vers-product --- a/make/linux/makefiles/mapfile-vers-product Thu Apr 04 11:57:04 2013 +0200 +++ b/make/linux/makefiles/mapfile-vers-product Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 make/linux/makefiles/tiered.make --- a/make/linux/makefiles/tiered.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/linux/makefiles/tiered.make Mon Apr 15 08:51:19 2013 +0200 @@ -32,4 +32,6 @@ ifndef OMIT_GRAAL CFLAGS += -DGRAAL +else + VM_SUBDIR = server-nograal endif \ No newline at end of file diff -r 0298d8a0caf5 -r 79b098d44d20 make/solaris/Makefile --- a/make/solaris/Makefile Thu Apr 04 11:57:04 2013 +0200 +++ b/make/solaris/Makefile Mon Apr 15 08:51:19 2013 +0200 @@ -238,36 +238,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 0298d8a0caf5 -r 79b098d44d20 make/solaris/build.sh --- a/make/solaris/build.sh Thu Apr 04 11:57:04 2013 +0200 +++ /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 0298d8a0caf5 -r 79b098d44d20 make/solaris/makefiles/buildtree.make --- a/make/solaris/makefiles/buildtree.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/solaris/makefiles/buildtree.make Mon Apr 15 08:51:19 2013 +0200 @@ -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:$(OUTPUTDIR)/shared/graal.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 0298d8a0caf5 -r 79b098d44d20 make/solaris/makefiles/compiler1.make --- a/make/solaris/makefiles/compiler1.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/solaris/makefiles/compiler1.make Mon Apr 15 08:51:19 2013 +0200 @@ -32,4 +32,6 @@ ifndef OMIT_GRAAL CFLAGS += -DGRAAL +else + VM_SUBDIR = client-nograal endif diff -r 0298d8a0caf5 -r 79b098d44d20 make/solaris/makefiles/compiler2.make --- a/make/solaris/makefiles/compiler2.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/solaris/makefiles/compiler2.make Mon Apr 15 08:51:19 2013 +0200 @@ -32,4 +32,6 @@ ifndef OMIT_GRAAL CFLAGS += -DGRAAL +else + VM_SUBDIR = server-nograal endif diff -r 0298d8a0caf5 -r 79b098d44d20 make/solaris/makefiles/gcc.make --- a/make/solaris/makefiles/gcc.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/solaris/makefiles/gcc.make Mon Apr 15 08:51:19 2013 +0200 @@ -118,8 +118,8 @@ # Compiler warnings are treated as errors WARNINGS_ARE_ERRORS = -Werror # Enable these warnings. See 'info gcc' about details on these options -ADDITIONAL_WARNINGS = -Wpointer-arith -Wconversion -Wsign-compare -CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(ADDITIONAL_WARNINGS) +WARNING_FLAGS = -Wpointer-arith -Wconversion -Wsign-compare -Wundef +CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(WARNING_FLAGS) # Special cases CFLAGS_WARN/BYFILE = $(CFLAGS_WARN/$@)$(CFLAGS_WARN/DEFAULT$(CFLAGS_WARN/$@)) diff -r 0298d8a0caf5 -r 79b098d44d20 make/solaris/makefiles/mapfile-vers --- a/make/solaris/makefiles/mapfile-vers Thu Apr 04 11:57:04 2013 +0200 +++ b/make/solaris/makefiles/mapfile-vers Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 make/solaris/makefiles/tiered.make --- a/make/solaris/makefiles/tiered.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/solaris/makefiles/tiered.make Mon Apr 15 08:51:19 2013 +0200 @@ -32,4 +32,6 @@ ifndef OMIT_GRAAL CFLAGS += -DGRAAL +else + VM_SUBDIR = server-nograal endif diff -r 0298d8a0caf5 -r 79b098d44d20 make/test/Queens.java --- a/make/test/Queens.java Thu Apr 04 11:57:04 2013 +0200 +++ /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 0298d8a0caf5 -r 79b098d44d20 make/windows/build.make --- a/make/windows/build.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/windows/build.make Mon Apr 15 08:51:19 2013 +0200 @@ -110,8 +110,6 @@ !endif !elseif "$(Variant)" == "tiered" VARIANT_TEXT=Tiered -!elseif "$(Variant)" == "kernel" -VARIANT_TEXT=Kernel !elseif "$(Variant)" == "graal" VARIANT_TEXT=Graal !endif @@ -307,9 +305,9 @@ checks: checkVariant checkWorkSpace checkSA checkVariant: - @ if "$(Variant)"=="" echo Need to specify "Variant=[graal|tiered|compiler2|compiler1|kernel|core]" && false - @ if "$(Variant)" NEQ "graal" 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=[graal|tiered|compiler2|compiler1|kernel|core]" && false + @ if "$(Variant)"=="" echo Need to specify "Variant=[graal|tiered|compiler2|compiler1|core]" && false + @ if "$(Variant)" NEQ "graal" if "$(Variant)" NEQ "tiered" if "$(Variant)" NEQ "compiler2" if "$(Variant)" NEQ "compiler1" if "$(Variant)" NEQ "core" \ + echo Need to specify "Variant=[graal|tiered|compiler2|compiler1|core]" && false checkWorkSpace: @ if "$(WorkSpace)"=="" echo Need to specify "WorkSpace=..." && false diff -r 0298d8a0caf5 -r 79b098d44d20 make/windows/create.bat --- a/make/windows/create.bat Thu Apr 04 11:57:04 2013 +0200 +++ b/make/windows/create.bat Mon Apr 15 08:51:19 2013 +0200 @@ -37,10 +37,14 @@ REM that "grep" be accessible on the PATH. An MKS install does this. REM -rem cl 2>NUL >NUL -rem if %errorlevel% == 0 goto nexttest -rem echo Make sure cl.exe is in your PATH before running this script. -rem goto end + + +REM (cwirth) does not return a proper error code, so build fails all the time +REM +REM cl 2>NUL >NUL +REM if %errorlevel% == 0 goto nexttest +REM echo Make sure cl.exe is in your PATH before running this script. +REM goto end :nexttest grep -V 2>NUL >NUL @@ -52,8 +56,6 @@ :testit cl 2>&1 | grep "x64" >NUL if %errorlevel% == 0 goto amd64 -cl 2>&1 | grep "x64" >NUL -if %errorlevel% == 0 goto amd64 set ARCH=x86 set BUILDARCH=i486 set Platform_arch=x86 @@ -150,7 +152,7 @@ REM This is now safe to do. :copyfiles -for /D %%i in (graal, compiler1, compiler2, tiered, core, kernel) do ( +for /D %%i in (graal, 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 ) @@ -158,7 +160,7 @@ REM force regneration of ProjectFile if exist %ProjectFile% del %ProjectFile% -for /D %%i in (graal, compiler1, compiler2, tiered, core, kernel) do ( +for /D %%i in (graal, 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 0298d8a0caf5 -r 79b098d44d20 make/windows/makefiles/compile.make --- a/make/windows/makefiles/compile.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/windows/makefiles/compile.make Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 make/windows/makefiles/product.make --- a/make/windows/makefiles/product.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/windows/makefiles/product.make Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 make/windows/makefiles/vm.make --- a/make/windows/makefiles/vm.make Thu Apr 04 11:57:04 2013 +0200 +++ b/make/windows/makefiles/vm.make Mon Apr 15 08:51:19 2013 +0200 @@ -93,12 +93,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 0298d8a0caf5 -r 79b098d44d20 make/windows/projectfiles/kernel/Makefile --- a/make/windows/projectfiles/kernel/Makefile Thu Apr 04 11:57:04 2013 +0200 +++ /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 0298d8a0caf5 -r 79b098d44d20 make/windows/projectfiles/kernel/vm.def --- a/make/windows/projectfiles/kernel/vm.def Thu Apr 04 11:57:04 2013 +0200 +++ /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 0298d8a0caf5 -r 79b098d44d20 make/windows/projectfiles/kernel/vm.dsw --- a/make/windows/projectfiles/kernel/vm.dsw Thu Apr 04 11:57:04 2013 +0200 +++ /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 0298d8a0caf5 -r 79b098d44d20 mx/commands.py --- a/mx/commands.py Thu Apr 04 11:57:04 2013 +0200 +++ b/mx/commands.py Mon Apr 15 08:51:19 2013 +0200 @@ -38,13 +38,19 @@ """ Used to distinguish an exported GraalVM (see 'mx export'). """ _vmSourcesAvailable = exists(join(_graal_home, 'make')) and exists(join(_graal_home, 'src')) -""" The VM that will be run by the 'vm' command: graal(default), client or server. +""" The VMs that can be built and run - default is first in list """ +_vmChoices = ['graal', 'server', 'client', 'server-nograal', 'client-nograal', 'boot'] + +""" The VM that will be run by the 'vm' command and built by default by the 'build' command. This can be set via the global '--vm' option. """ -_vm = 'graal' +_vm = _vmChoices[0] -""" The VM build that will be run by the 'vm' command: product(default), fastdebug or debug. - This can be set via the global '--fastdebug' and '--debug' options. """ -_vmbuild = 'product' +""" The VM builds that will be run by the 'vm' command - default is first in list """ +_vmbuildChoices = ['product', 'fastdebug', 'debug'] + +""" The VM build that will be run by the 'vm' command. + This can be set via the global '--product', '--fastdebug' and '--debug' options. """ +_vmbuild = _vmbuildChoices[0] _jacoco = 'off' @@ -66,11 +72,16 @@ """clean the GraalVM source tree""" opts = mx.clean(args, parser=ArgumentParser(prog='mx clean')) if opts.native: - os.environ.update(ARCH_DATA_MODEL='64', LANG='C', HOTSPOT_BUILD_JOBS='16') - mx.run([mx.gmake_cmd(), 'clean'], cwd=join(_graal_home, 'make')) - jdks = join(_graal_home, 'jdk' + str(mx.java().version)) - if exists(jdks): - shutil.rmtree(jdks) + def rmIfExists(name): + if os.path.isdir(name): + shutil.rmtree(name) + elif os.path.isfile(name): + os.unlink(name) + + rmIfExists(join(_graal_home, 'build')) + rmIfExists(join(_graal_home, 'build-nograal')) + rmIfExists(join(_graal_home, 'jdk' + str(mx.java().version))) + rmIfExists(mx.distribution('GRAAL').path) def export(args): """create a GraalVM zip file for distribution""" @@ -296,14 +307,14 @@ Get the JDK into which Graal is installed, creating it first if necessary. """ jdk = join(_graal_home, 'jdk' + str(mx.java().version), build) + srcJdk = mx.java().jdk jdkContents = ['bin', 'include', 'jre', 'lib'] - if (exists(join(jdk, 'db'))): + if exists(join(srcJdk, 'db')): jdkContents.append('db') - if mx.get_os() != 'windows': + if mx.get_os() != 'windows' and exists(join(srcJdk, 'man')): jdkContents.append('man') if create: if not exists(jdk): - srcJdk = mx.java().jdk mx.log('Creating ' + jdk + ' from ' + srcJdk) os.makedirs(jdk) for d in jdkContents: @@ -320,6 +331,7 @@ mx.abort(jvmCfg + ' does not exist') defaultVM = None + jvmCfgLines = [] with open(jvmCfg) as f: for line in f: if line.startswith('-') and defaultVM is None: @@ -327,14 +339,20 @@ assert len(parts) == 2, parts assert parts[1] == 'KNOWN', parts[1] defaultVM = parts[0][1:] + jvmCfgLines += ['# boot VM is a copy of the unmodified ' + defaultVM + ' VM\n'] + jvmCfgLines += ['-boot KNOWN\n'] + else: + jvmCfgLines += [line] assert defaultVM is not None, 'Could not find default VM in ' + jvmCfg if mx.get_os() != 'windows': chmodRecursive(jdk, 0755) - shutil.copytree(join(_vmLibDirInJdk(jdk), defaultVM), join(_vmLibDirInJdk(jdk), defaultVM + '0')) + shutil.move(join(_vmLibDirInJdk(jdk), defaultVM), join(_vmLibDirInJdk(jdk), 'boot')) + with open(jvmCfg, 'w') as fp: - print >> fp, '-' + defaultVM + '0 KNOWN' + for line in jvmCfgLines: + fp.write(line) # Install a copy of the disassembler library try: @@ -479,7 +497,7 @@ out.element('target', {'name' : 'main', 'depends' : 'jar'}) - out.open('target', {'name' : 'compile'}) + out.open('target', {'name' : 'compile', 'depends' : 'cleanclasses'}) out.element('mkdir', {'dir' : '${classes.dir}'}) out.open('javac', {'destdir' : '${classes.dir}', 'debug' : 'on', 'includeantruntime' : 'false', }) for p in mx.sorted_deps(mx.distribution('GRAAL').deps): @@ -500,9 +518,12 @@ out.element('jar', {'destfile' : '${jar.file}', 'basedir' : '${classes.dir}'}) out.close('target') - out.open('target', {'name' : 'clean'}) + out.open('target', {'name' : 'cleanclasses'}) out.element('delete', {'dir' : '${classes.dir}'}) - out.element('delete', {'file' : '${jar.filr}'}) + out.close('target') + + out.open('target', {'name' : 'clean', 'depends' : 'cleanclasses'}) + out.element('delete', {'file' : '${jar.file}'}) out.close('target') out.close('project') @@ -530,9 +551,9 @@ if vm is None: vm = _vm - if vm == 'server': + if vm.startswith('server') or vm == 'boot': buildSuffix = '' - elif vm == 'client': + elif vm.startswith('client'): buildSuffix = '1' else: assert vm == 'graal', vm @@ -549,6 +570,11 @@ jdk = _jdk(build, create=True) + if vm == 'boot': + if build != 'product': + mx.log('only product build of boot VM exists') + continue + vmDir = join(_vmLibDirInJdk(jdk), vm) if not exists(vmDir): if mx.get_os() != 'windows': @@ -606,12 +632,16 @@ if build == 'debug': build = 'jvmg' runCmd.append(build + buildSuffix) - env = os.environ + env = os.environ.copy() env.setdefault('ARCH_DATA_MODEL', '64') env.setdefault('LANG', 'C') env.setdefault('HOTSPOT_BUILD_JOBS', str(cpus)) - env['ALT_BOOTDIR'] = jdk - if not env.has_key('OMIT_GRAAL'): + env['ALT_BOOTDIR'] = mx.java().jdk + env['JAVA_HOME'] = jdk + if vm.endswith('nograal'): + env['OMIT_GRAAL'] = 'true' + env.setdefault('ALT_OUTPUTDIR', join(_graal_home, 'build-nograal', mx.get_os())) + else: env['GRAAL'] = join(_graal_home, 'graal') # needed for TEST_IN_BUILD env.setdefault('INSTALL', 'y') if mx.get_os() == 'solaris' : @@ -636,26 +666,34 @@ env.pop('LD_LIBRARY_PATH', None) env.pop('CLASSPATH', None) - mx.run(runCmd, cwd=join(_graal_home, 'make'), err=filterXusage) + mx.run(runCmd, cwd=join(_graal_home, 'make'), err=filterXusage, env=env) jvmCfg = _vmCfgInJdk(jdk) - found = False if not exists(jvmCfg): mx.abort(jvmCfg + ' does not exist') - prefix = '-' + vm - vmKnown = prefix + ' KNOWN' + prefix = '-' + vm + ' ' + vmKnown = prefix + 'KNOWN\n' + lines = [] + found = False with open(jvmCfg) as f: for line in f: - if vmKnown == line.strip(): + if line.strip() == vmKnown.strip(): found = True - break + lines.append(line) + if not found: - mx.log('Appending "' + prefix + ' KNOWN" to ' + jvmCfg) + mx.log('Appending "' + prefix + 'KNOWN" to ' + jvmCfg) if mx.get_os() != 'windows': os.chmod(jvmCfg, 0755) - with open(jvmCfg, 'a') as f: - print >> f, vmKnown + with open(jvmCfg, 'w') as f: + for line in lines: + if line.startswith(prefix): + line = vmKnown + found = True + f.write(line) + if not found: + f.write(vmKnown) if exists(timestampFile): os.utime(timestampFile, None) @@ -753,12 +791,14 @@ name = 'JUnitWrapper' javaSource = join(mxdir, name + '.java') javaClass = join(mxdir, name + '.class') - (_, testfile) = tempfile.mkstemp(".testclasses", "graal") + testfile = os.environ.get('MX_TESTFILE', None) + if testfile is None: + (_, testfile) = tempfile.mkstemp(".testclasses", "graal") def harness(projectscp, vmArgs): if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource): subprocess.check_call([mx.java().javac, '-cp', projectscp, '-d', mxdir, javaSource]) - if _vm == 'server0': + if _vm == 'boot' or _vm.endswith('nograal'): prefixArgs = ['-esa', '-ea'] else: prefixArgs = ['-XX:-BootstrapGraal', '-esa', '-ea'] @@ -767,7 +807,8 @@ try: _run_tests(args, harness, annotations, testfile) finally: - os.remove(testfile) + if os.environ.get('MX_TESTFILE') is None: + os.remove(testfile) def unittest(args): """run the JUnit tests (all testcases) @@ -799,9 +840,14 @@ def buildvms(args): """build one or more VMs in various configurations""" + vmsDefault = ','.join(_vmChoices) + vmbuildsDefault = ','.join(_vmbuildChoices) + parser = ArgumentParser(prog='mx buildvms'); - parser.add_argument('--vms', help='a comma separated list of VMs to build (default: server,client,graal)', default='server,client,graal') - parser.add_argument('--builds', help='a comma separated list of build types (default: product,fastdebug,debug)', default='product,fastdebug,debug') + parser.add_argument('--vms', help='a comma separated list of VMs to build (default: ' + vmsDefault + ')', metavar='', default=vmsDefault) + parser.add_argument('--builds', help='a comma separated list of build types (default: ' + vmbuildsDefault + ')', metavar='', default=vmbuildsDefault) + parser.add_argument('-n', '--no-check', action='store_true', help='omit running "java -version" after each build') + parser.add_argument('-c', '--console', action='store_true', help='send build output to console instead of log file') args = parser.parse_args(args) vms = args.vms.split(',') @@ -810,14 +856,26 @@ allStart = time.time() for v in vms: for vmbuild in builds: - logFile = join(v + '-' + vmbuild + '.log') - log = open(join(_graal_home, logFile), 'wb') - start = time.time() - mx.log('BEGIN: ' + v + '-' + vmbuild + '\t(see: ' + logFile + ')') - # Run as subprocess so that output can be directed to a file - subprocess.check_call([sys.executable, '-u', join('mxtool', 'mx.py'), '--vm', v, 'build', vmbuild], cwd=_graal_home, stdout=log, stderr=subprocess.STDOUT) - duration = datetime.timedelta(seconds=time.time() - start) - mx.log('END: ' + v + '-' + vmbuild + '\t[' + str(duration) + ']') + if v == 'boot' and vmbuild != 'product': + continue + if not args.console: + logFile = join(v + '-' + vmbuild + '.log') + log = open(join(_graal_home, logFile), 'wb') + start = time.time() + mx.log('BEGIN: ' + v + '-' + vmbuild + '\t(see: ' + logFile + ')') + # Run as subprocess so that output can be directed to a file + subprocess.check_call([sys.executable, '-u', join('mxtool', 'mx.py'), '--vm', v, 'build', vmbuild], cwd=_graal_home, stdout=log, stderr=subprocess.STDOUT) + duration = datetime.timedelta(seconds=time.time() - start) + mx.log('END: ' + v + '-' + vmbuild + '\t[' + str(duration) + ']') + else: + global _vm + _vm = v + build([vmbuild]) + if not args.no_check: + vmargs = ['-version'] + if v == 'graal': + vmargs.insert(0, '-XX:-BootstrapGraal') + vm(vmargs, vm=v, vmbuild=vmbuild) allDuration = datetime.timedelta(seconds=time.time() - allStart) mx.log('TOTAL TIME: ' + '[' + str(allDuration) + ']') @@ -1042,7 +1100,9 @@ for dacapo in dacapos: if dacapo not in sanitycheck.dacapoSanityWarmup.keys(): mx.abort('Unknown DaCapo : ' + dacapo) - benchmarks += [sanitycheck.getDacapo(dacapo, sanitycheck.dacapoSanityWarmup[dacapo][sanitycheck.SanityCheckLevel.Benchmark])] + iterations = sanitycheck.dacapoSanityWarmup[dacapo][sanitycheck.SanityCheckLevel.Benchmark] + if (iterations > 0): + benchmarks += [sanitycheck.getDacapo(dacapo, iterations)] if ('scaladacapo' in args or 'all' in args): benchmarks += sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Benchmark) @@ -1051,7 +1111,9 @@ for scaladacapo in scaladacapos: if scaladacapo not in sanitycheck.dacapoScalaSanityWarmup.keys(): mx.abort('Unknown Scala DaCapo : ' + scaladacapo) - benchmarks += [sanitycheck.getScalaDacapo(scaladacapo, sanitycheck.dacapoScalaSanityWarmup[scaladacapo][sanitycheck.SanityCheckLevel.Benchmark])] + iterations = sanitycheck.dacapoScalaSanityWarmup[scaladacapo][sanitycheck.SanityCheckLevel.Benchmark] + if (iterations > 0): + benchmarks += [sanitycheck.getScalaDacapo(scaladacapo, iterations)] #Bootstrap if ('bootstrap' in args or 'all' in args): @@ -1261,18 +1323,16 @@ mx.add_argument('--jacoco', help='instruments com.oracle.* classes using JaCoCo', default='off', choices=['off', 'on', 'append']) if (_vmSourcesAvailable): - mx.add_argument('--vm', action='store', dest='vm', default='graal', choices=['graal', 'server', 'client', 'server0'], help='the VM to build/run (default: graal)') - mx.add_argument('--product', action='store_const', dest='vmbuild', const='product', help='select the product build of the VM') - mx.add_argument('--debug', action='store_const', dest='vmbuild', const='debug', help='select the debug build of the VM') - mx.add_argument('--fastdebug', action='store_const', dest='vmbuild', const='fastdebug', help='select the fast debug build of the VM') + mx.add_argument('--vm', action='store', dest='vm', default='graal', choices=_vmChoices, help='the VM to build/run (default: ' + _vmChoices[0] + ')') + for c in _vmbuildChoices: + mx.add_argument('--' + c, action='store_const', dest='vmbuild', const=c, help='select the ' + c + ' build of the VM') mx.add_argument('--ecl', action='store_true', dest='make_eclipse_launch', help='create launch configuration for running VM execution(s) in Eclipse') mx.add_argument('--native-dbg', action='store', dest='native_dbg', help='Start the vm inside a debugger', metavar='') mx.add_argument('--gdb', action='store_const', const='/usr/bin/gdb --args', dest='native_dbg', help='alias for --native-dbg /usr/bin/gdb -- args') - commands.update({ 'export': [export, '[-options] [zipfile]'], - 'build': [build, '[-options] [product|debug|fastdebug]...'] + 'build': [build, '[-options] [' + '|'.join(_vmbuildChoices) + ']...'] }) mx.commands.update(commands) diff -r 0298d8a0caf5 -r 79b098d44d20 mx/projects --- a/mx/projects Thu Apr 04 11:57:04 2013 +0200 +++ b/mx/projects Mon Apr 15 08:51:19 2013 +0200 @@ -125,7 +125,7 @@ # graal.hotspot.test project@com.oracle.graal.hotspot.test@subDir=graal project@com.oracle.graal.hotspot.test@sourceDirs=src -project@com.oracle.graal.hotspot.test@dependencies=com.oracle.graal.replacements.test,com.oracle.graal.hotspot +project@com.oracle.graal.hotspot.test@dependencies=com.oracle.graal.replacements.test project@com.oracle.graal.hotspot.test@checkstyle=com.oracle.graal.graph project@com.oracle.graal.hotspot.test@javaCompliance=1.7 @@ -155,6 +155,13 @@ project@com.oracle.graal.debug@checkstyle=com.oracle.graal.graph project@com.oracle.graal.debug@javaCompliance=1.7 +# graal.debug.test +project@com.oracle.graal.debug.test@subDir=graal +project@com.oracle.graal.debug.test@sourceDirs=src +project@com.oracle.graal.debug.test@dependencies=JUNIT,com.oracle.graal.debug +project@com.oracle.graal.debug.test@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.debug.test@javaCompliance=1.7 + # graal.lir project@com.oracle.graal.lir@subDir=graal project@com.oracle.graal.lir@sourceDirs=src @@ -215,7 +222,7 @@ # graal.replacements.test project@com.oracle.graal.replacements.test@subDir=graal project@com.oracle.graal.replacements.test@sourceDirs=src -project@com.oracle.graal.replacements.test@dependencies=com.oracle.graal.replacements,com.oracle.graal.compiler.test +project@com.oracle.graal.replacements.test@dependencies=com.oracle.graal.compiler.test project@com.oracle.graal.replacements.test@checkstyle=com.oracle.graal.graph project@com.oracle.graal.replacements.test@javaCompliance=1.7 @@ -229,7 +236,7 @@ # graal.nodes project@com.oracle.graal.nodes@subDir=graal project@com.oracle.graal.nodes@sourceDirs=src -project@com.oracle.graal.nodes@dependencies=com.oracle.graal.api.code,com.oracle.graal.graph,com.oracle.graal.debug +project@com.oracle.graal.nodes@dependencies=com.oracle.graal.api.code,com.oracle.graal.graph,com.oracle.graal.debug,com.oracle.graal.api.replacements project@com.oracle.graal.nodes@checkstyle=com.oracle.graal.graph project@com.oracle.graal.nodes@javaCompliance=1.7 @@ -243,7 +250,7 @@ # graal.phases.common project@com.oracle.graal.phases.common@subDir=graal project@com.oracle.graal.phases.common@sourceDirs=src -project@com.oracle.graal.phases.common@dependencies=com.oracle.graal.phases,com.oracle.graal.api.replacements +project@com.oracle.graal.phases.common@dependencies=com.oracle.graal.phases project@com.oracle.graal.phases.common@checkstyle=com.oracle.graal.graph project@com.oracle.graal.phases.common@javaCompliance=1.7 @@ -333,7 +340,7 @@ # graal.compiler.test project@com.oracle.graal.compiler.test@subDir=graal project@com.oracle.graal.compiler.test@sourceDirs=src -project@com.oracle.graal.compiler.test@dependencies=com.oracle.graal.api.runtime,com.oracle.graal.printer,com.oracle.graal.test +project@com.oracle.graal.compiler.test@dependencies=com.oracle.graal.test,com.oracle.graal.hotspot project@com.oracle.graal.compiler.test@checkstyle=com.oracle.graal.graph project@com.oracle.graal.compiler.test@javaCompliance=1.7 diff -r 0298d8a0caf5 -r 79b098d44d20 mxtool/mx.py --- a/mxtool/mx.py Thu Apr 04 11:57:04 2013 +0200 +++ b/mxtool/mx.py Mon Apr 15 08:51:19 2013 +0200 @@ -663,12 +663,14 @@ def element(self, tag, attributes={}, data=None): return self.open(tag, attributes, data).close(tag) - def xml(self, indent='', newl='', escape=False): + def xml(self, indent='', newl='', escape=False, standalone=None): assert self.current == self result = self.toprettyxml(indent, newl, encoding="UTF-8") if escape: entities = { '"': """, "'": "'", '\n': ' ' } result = xml.sax.saxutils.escape(result, entities) + if standalone is not None: + result = result.replace('encoding="UTF-8"?>', 'encoding="UTF-8" standalone="' + str(standalone) + '"?>') return result def get_os(): @@ -944,7 +946,7 @@ retcode = p.wait() return retcode -def run(args, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None): +def run(args, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, env=None): """ Run a command in a subprocess, wait for it to complete and return the exit status of the process. If the exit status is non-zero and `nonZeroIsFatal` is true, then mx is exited with @@ -981,7 +983,7 @@ if not callable(out) and not callable(err) and timeout is None: # The preexec_fn=os.setsid - p = subprocess.Popen(args, cwd=cwd, preexec_fn=preexec_fn, creationflags=creationflags) + p = subprocess.Popen(args, cwd=cwd, preexec_fn=preexec_fn, creationflags=creationflags, env=env) _currentSubprocess = (p, args) retcode = waitOn(p) else: @@ -991,7 +993,7 @@ stream.close() stdout=out if not callable(out) else subprocess.PIPE stderr=err if not callable(err) else subprocess.PIPE - p = subprocess.Popen(args, cwd=cwd, stdout=stdout, stderr=stderr, preexec_fn=preexec_fn, creationflags=creationflags) + p = subprocess.Popen(args, cwd=cwd, stdout=stdout, stderr=stderr, preexec_fn=preexec_fn, creationflags=creationflags, env=env) _currentSubprocess = (p, args) if callable(out): t = Thread(target=redirect, args=(p.stdout, out)) @@ -1342,7 +1344,7 @@ parser = parser if parser is not None else ArgumentParser(prog='mx build') parser.add_argument('-f', action='store_true', dest='force', help='force build (disables timestamp checking)') parser.add_argument('-c', action='store_true', dest='clean', help='removes existing build output') - parser.add_argument('--source', dest='compliance', help='Java compliance level', default=str(javaCompliance)) + parser.add_argument('--source', dest='compliance', help='Java compliance level for projects without an explicit one', default=str(javaCompliance)) parser.add_argument('--Wapi', action='store_true', dest='warnAPI', help='show warnings about using internal APIs') parser.add_argument('--projects', action='store', help='comma separated projects to build (omit to build all projects)') parser.add_argument('--only', action='store', help='comma separated projects to build, without checking their dependencies (omit to build all projects)') @@ -1500,16 +1502,17 @@ toBeDeleted = [argfileName] try: + compliance = str(p.javaCompliance) if p.javaCompliance is not None else args.compliance if jdtJar is None: log('Compiling Java sources for {0} with javac...'.format(p.name)) - javacCmd = [java().javac, '-g', '-J-Xmx1g', '-source', args.compliance, '-classpath', cp, '-d', outputDir] + javacArgs + ['@' + argfile.name] + javacCmd = [java().javac, '-g', '-J-Xmx1g', '-source', compliance, '-classpath', cp, '-d', outputDir] + javacArgs + ['@' + argfile.name] if not args.warnAPI: javacCmd.append('-XDignore.symbol.file') run(javacCmd) else: log('Compiling Java sources for {0} with JDT...'.format(p.name)) jdtArgs = [java().java, '-Xmx1g', '-jar', jdtJar, - '-' + args.compliance, + '-' + compliance, '-cp', cp, '-g', '-enableJavadoc', '-d', outputDir] + javacArgs jdtProperties = join(p.dir, '.settings', 'org.eclipse.jdt.core.prefs') @@ -1559,6 +1562,13 @@ args.eclipse_exe = os.environ.get('ECLIPSE_EXE') if args.eclipse_exe is None: abort('Could not find Eclipse executable. Use -e option or ensure ECLIPSE_EXE environment variable is set.') + + # Maybe an Eclipse installation dir was specified - look for the executable in it + if join(args.eclipse_exe, exe_suffix('eclipse')): + args.eclipse_exe = join(args.eclipse_exe, exe_suffix('eclipse')) + + if not os.path.isfile(args.eclipse_exe) or not os.access(args.eclipse_exe, os.X_OK): + abort('Not an executable file: ' + args.eclipse_exe) eclipseinit([], buildProcessorJars=False) @@ -1811,11 +1821,6 @@ log('[all Java sources in {0} already checked - skipping]'.format(sourceDir)) continue - if exists(timestampFile): - os.utime(timestampFile, None) - else: - file(timestampFile, 'a') - dotCheckstyleXML = xml.dom.minidom.parse(dotCheckstyle) localCheckConfig = dotCheckstyleXML.getElementsByTagName('local-check-config')[0] configLocation = localCheckConfig.getAttribute('location') @@ -1881,6 +1886,11 @@ if len(warnings) != 0: map(log, warnings) return 1 + else: + if exists(timestampFile): + os.utime(timestampFile, None) + else: + file(timestampFile, 'a') finally: if exists(auditfileName): os.unlink(auditfileName) @@ -1977,16 +1987,16 @@ slm.open('sourceContainers', {'duplicates' : 'false'}) # Every Java program depends on the JRE - memento = XMLDoc().element('classpathContainer', {'path' : 'org.eclipse.jdt.launching.JRE_CONTAINER'}).xml() + memento = XMLDoc().element('classpathContainer', {'path' : 'org.eclipse.jdt.launching.JRE_CONTAINER'}).xml(standalone='no') slm.element('classpathContainer', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.classpathContainer'}) for dep in deps: if dep.isLibrary(): if hasattr(dep, 'eclipse.container'): - memento = XMLDoc().element('classpathContainer', {'path' : getattr(dep, 'eclipse.container')}).xml() + memento = XMLDoc().element('classpathContainer', {'path' : getattr(dep, 'eclipse.container')}).xml(standalone='no') slm.element('classpathContainer', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.classpathContainer'}) else: - memento = XMLDoc().element('javaProject', {'name' : dep.name}).xml() + memento = XMLDoc().element('javaProject', {'name' : dep.name}).xml(standalone='no') slm.element('container', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.javaProject'}) slm.close('sourceContainers') @@ -2010,7 +2020,7 @@ launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.PROJECT_ATTR', 'value' : ''}) launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.VM_CONNECTOR_ID', 'value' : 'org.eclipse.jdt.launching.socketAttachConnector'}) launch.close('launchConfiguration') - launch = launch.xml(newl='\n') % slm.xml(escape=True) + launch = launch.xml(newl='\n', standalone='no') % slm.xml(escape=True, standalone='no') if name is None: name = 'attach-' + hostname + '-' + port @@ -2077,7 +2087,7 @@ launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.PROJECT_ATTR', 'value' : ''}) launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.VM_ARGUMENTS', 'value' : ' '.join(vmArgs)}) launch.close('launchConfiguration') - launch = launch.xml(newl='\n') % slm.xml(escape=True) + launch = launch.xml(newl='\n', standalone='no') % slm.xml(escape=True, standalone='no') eclipseLaunches = join('mx', 'eclipse-launches') if not exists(eclipseLaunches): @@ -2214,7 +2224,7 @@ out.close('buildCommand') if _isAnnotationProcessorDependency(p): - _genEclipseBuilder(out, p, 'Jar.launch', 'archive ' + p.name, refresh = False, async = False) + _genEclipseBuilder(out, p, 'Jar.launch', 'archive ' + p.name, refresh = False, async = False, xmlIndent='', xmlStandalone='no') _genEclipseBuilder(out, p, 'Refresh.launch', '', refresh = True, async = True) if projToDist.has_key(p.name): @@ -2296,10 +2306,11 @@ return False -def _genEclipseBuilder(dotProjectDoc, p, name, mxCommand, refresh=True, async=False, logToConsole=False): +def _genEclipseBuilder(dotProjectDoc, p, name, mxCommand, refresh=True, async=False, logToConsole=False, xmlIndent='\t', xmlStandalone=None): launchOut = XMLDoc(); consoleOn = 'true' if logToConsole else 'false' launchOut.open('launchConfiguration', {'type' : 'org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType'}) + launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.core.capture_output', 'value': consoleOn}) launchOut.open('mapAttribute', {'key' : 'org.eclipse.debug.core.environmentVariables'}) launchOut.element('mapEntry', {'key' : 'JAVA_HOME', 'value' : java().jdk}) launchOut.close('mapAttribute') @@ -2307,9 +2318,7 @@ if refresh: launchOut.element('stringAttribute', {'key' : 'org.eclipse.debug.core.ATTR_REFRESH_SCOPE', 'value': '${project}'}) launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.ui.ATTR_CONSOLE_OUTPUT_ON', 'value': consoleOn}) - launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.core.capture_output', 'value': consoleOn}) - if async: - launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND', 'value': 'true'}) + launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND', 'value': 'true' if async else 'false'}) baseDir = dirname(dirname(os.path.abspath(__file__))) @@ -2329,7 +2338,7 @@ if not exists(externalToolDir): os.makedirs(externalToolDir) - update_file(join(externalToolDir, name), launchOut.xml(indent='\t', newl='\n')) + update_file(join(externalToolDir, name), launchOut.xml(indent=xmlIndent, standalone=xmlStandalone, newl='\n')) dotProjectDoc.open('buildCommand') dotProjectDoc.element('name', data='org.eclipse.ui.externaltools.ExternalToolBuilder') @@ -3009,9 +3018,10 @@ if exists(tmpbase): shutil.rmtree(tmpbase) -def findclass(args): +def findclass(args, logToConsole=True): """find all classes matching a given substring""" + matches = [] for entry, filename in classpath_walk(includeBootClasspath=True): if filename.endswith('.class'): if isinstance(entry, zipfile.ZipFile): @@ -3021,20 +3031,19 @@ classname = classname[:-len('.class')] for a in args: if a in classname: - log(classname) + matches.append(classname) + if logToConsole: + log(classname) + return matches def javap(args): - """launch javap with a -classpath option denoting all available classes - - Run the JDK javap class file disassembler with the following prepended options: - - -private -verbose -classpath """ + """disassemble classes matching given pattern with javap""" javap = java().javap if not exists(javap): abort('The javap executable does not exists: ' + javap) else: - run([javap, '-private', '-verbose', '-classpath', classpath()] + args) + run([javap, '-private', '-verbose', '-classpath', classpath()] + findclass(args, logToConsole=False)) def show_projects(args): """show all loaded projects""" @@ -3072,7 +3081,7 @@ 'ideinit': [ideinit, ''], 'archive': [archive, '[options]'], 'projectgraph': [projectgraph, ''], - 'javap': [javap, ''], + 'javap': [javap, ''], 'javadoc': [javadoc, '[options]'], 'site': [site, '[options]'], 'netbeansinit': [netbeansinit, ''], diff -r 0298d8a0caf5 -r 79b098d44d20 src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp --- a/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp --- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp --- a/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/sparc/vm/c1_Runtime1_sparc.cpp --- a/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/sparc/vm/cppInterpreter_sparc.cpp --- a/src/cpu/sparc/vm/cppInterpreter_sparc.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/sparc/vm/cppInterpreter_sparc.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -2194,7 +2194,8 @@ int callee_locals_size, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { assert(popframe_extra_args == 0, "NEED TO FIX"); // NOTE this code must exactly mimic what InterpreterGenerator::generate_compute_interpreter_state() diff -r 0298d8a0caf5 -r 79b098d44d20 src/cpu/sparc/vm/interpreter_sparc.cpp --- a/src/cpu/sparc/vm/interpreter_sparc.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/sparc/vm/interpreter_sparc.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -381,6 +381,9 @@ case Interpreter::zerolocals_synchronized: synchronized = true; break; case Interpreter::native : entry_point = ((InterpreterGenerator*)this)->generate_native_entry(false); break; case Interpreter::native_synchronized : entry_point = ((InterpreterGenerator*)this)->generate_native_entry(true); break; +#ifdef GRAAL + case Interpreter::execute_compiled_method: entry_point = ((InterpreterGenerator*)this)->generate_execute_compiled_method_entry(); break; +#endif case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break; case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break; case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break; diff -r 0298d8a0caf5 -r 79b098d44d20 src/cpu/sparc/vm/macroAssembler_sparc.cpp --- a/src/cpu/sparc/vm/macroAssembler_sparc.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/sparc/vm/macroAssembler_sparc.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/sparc/vm/sharedRuntime_sparc.cpp diff -r 0298d8a0caf5 -r 79b098d44d20 src/cpu/sparc/vm/templateInterpreter_sparc.cpp --- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -1581,7 +1581,8 @@ int callee_local_count, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { // Note: This calculation must exactly parallel the frame setup // in InterpreterGenerator::generate_fixed_frame. // If f!=NULL, set up the following variables: @@ -1664,6 +1665,15 @@ int delta = local_words - parm_words; int computed_sp_adjustment = (delta > 0) ? round_to(delta, WordsPerLong) : 0; *interpreter_frame->register_addr(I5_savedSP) = (intptr_t) (fp + computed_sp_adjustment) - STACK_BIAS; + if (!is_bottom_frame) { + // Llast_SP is set below for the current frame to SP (with the + // extra space for the callee's locals). Here we adjust + // Llast_SP for the caller's frame, removing the extra space + // for the current method's locals. + *caller->register_addr(Llast_SP) = *interpreter_frame->register_addr(I5_savedSP); + } else { + assert(*caller->register_addr(Llast_SP) >= *interpreter_frame->register_addr(I5_savedSP), "strange Llast_SP"); + } } else { assert(caller->is_compiled_frame() || caller->is_entry_frame(), "only possible cases"); // Don't have Lesp available; lay out locals block in the caller diff -r 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/assembler_x86.cpp --- a/src/cpu/x86/vm/assembler_x86.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/assembler_x86.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/c1_CodeStubs_x86.cpp --- a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/c1_LIRAssembler_x86.cpp --- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/c1_LIRGenerator_x86.cpp --- a/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/c1_LinearScan_x86.cpp --- a/src/cpu/x86/vm/c1_LinearScan_x86.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/c1_LinearScan_x86.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/c1_Runtime1_x86.cpp --- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/cppInterpreter_x86.cpp --- a/src/cpu/x86/vm/cppInterpreter_x86.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/cppInterpreter_x86.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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); @@ -2361,7 +2344,8 @@ int callee_locals, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { assert(popframe_extra_args == 0, "FIX ME"); // NOTE this code must exactly mimic what InterpreterGenerator::generate_compute_interpreter_state() diff -r 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/frame_x86.cpp --- a/src/cpu/x86/vm/frame_x86.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/frame_x86.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -356,7 +356,7 @@ // Verifies the calculated original PC of a deoptimization PC for the // given unextended SP. The unextended SP might also be the saved SP // for MethodHandle call sites. -#if ASSERT +#ifdef ASSERT void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return) { frame fr; diff -r 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/frame_x86.hpp --- a/src/cpu/x86/vm/frame_x86.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/frame_x86.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -170,7 +170,7 @@ return (intptr_t*) addr_at(offset); } -#if ASSERT +#ifdef ASSERT // Used in frame::sender_for_{interpreter,compiled}_frame static void verify_deopt_original_pc( nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false); static void verify_deopt_mh_original_pc(nmethod* nm, intptr_t* unextended_sp) { diff -r 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/frame_x86.inline.hpp --- a/src/cpu/x86/vm/frame_x86.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/frame_x86.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/graalRuntime_x86.cpp --- a/src/cpu/x86/vm/graalRuntime_x86.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/graalRuntime_x86.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -879,30 +879,10 @@ // This is called via call_runtime so the arguments // will be place in C abi locations - -#ifdef _LP64 __ verify_oop(j_rarg0); - __ mov(rax, j_rarg0); -#else - // The object is passed on the stack and we haven't pushed a - // frame yet so it's one work away from top of stack. - __ movptr(rax, Address(rsp, 1 * BytesPerWord)); - __ verify_oop(rax); -#endif // _LP64 - - // load the klass and check the has finalizer flag - Label register_finalizer; - Register t = rsi; - __ load_klass(t, rax); - __ movl(t, Address(t, Klass::access_flags_offset())); - __ testl(t, JVM_ACC_HAS_FINALIZER); - __ jcc(Assembler::notZero, register_finalizer); - __ ret(0); - - __ bind(register_finalizer); __ enter(); OopMap* oop_map = save_live_registers(sasm, 2 /*num_rt_args */); - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, SharedRuntime::register_finalizer), rax); + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, SharedRuntime::register_finalizer), j_rarg0); oop_maps = new OopMapSet(); oop_maps->add_gc_map(call_offset, oop_map); @@ -950,6 +930,7 @@ OopMap* oop_map = save_live_registers(sasm, 0); int call_offset = __ call_RT(rax, noreg, (address)create_null_exception, 0); oop_maps->add_gc_map(call_offset, oop_map); + restore_live_registers_except_rax(sasm); __ leave(); __ ret(0); break; @@ -958,9 +939,10 @@ case create_out_of_bounds_exception_id: { __ enter(); oop_maps = new OopMapSet(); - OopMap* oop_map = save_live_registers(sasm, 0); + OopMap* oop_map = save_live_registers(sasm, 1); int call_offset = __ call_RT(rax, noreg, (address)create_out_of_bounds_exception, j_rarg0); oop_maps->add_gc_map(call_offset, oop_map); + restore_live_registers_except_rax(sasm); __ leave(); __ ret(0); break; @@ -969,7 +951,7 @@ case vm_error_id: { __ enter(); oop_maps = new OopMapSet(); - OopMap* oop_map = save_live_registers(sasm, 0); + OopMap* oop_map = save_live_registers(sasm, 3); int call_offset = __ call_RT(noreg, noreg, (address)vm_error, j_rarg0, j_rarg1, j_rarg2); oop_maps->add_gc_map(call_offset, oop_map); restore_live_registers(sasm); @@ -981,7 +963,7 @@ case log_printf_id: { __ enter(); oop_maps = new OopMapSet(); - OopMap* oop_map = save_live_registers(sasm, 0); + OopMap* oop_map = save_live_registers(sasm, 4); int call_offset = __ call_RT(noreg, noreg, (address)log_printf, j_rarg0, j_rarg1, j_rarg2, j_rarg3); oop_maps->add_gc_map(call_offset, oop_map); restore_live_registers(sasm); @@ -993,7 +975,7 @@ case log_primitive_id: { __ enter(); oop_maps = new OopMapSet(); - OopMap* oop_map = save_live_registers(sasm, 0); + OopMap* oop_map = save_live_registers(sasm, 3); int call_offset = __ call_RT(noreg, noreg, (address)log_primitive, j_rarg0, j_rarg1, j_rarg2); oop_maps->add_gc_map(call_offset, oop_map); restore_live_registers(sasm); @@ -1005,7 +987,7 @@ case log_object_id: { __ enter(); oop_maps = new OopMapSet(); - OopMap* oop_map = save_live_registers(sasm, 0); + OopMap* oop_map = save_live_registers(sasm, 2); int call_offset = __ call_RT(noreg, noreg, (address)log_object, j_rarg0, j_rarg1); oop_maps->add_gc_map(call_offset, oop_map); restore_live_registers(sasm); diff -r 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/interpreterGenerator_x86.hpp --- a/src/cpu/x86/vm/interpreterGenerator_x86.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/interpreterGenerator_x86.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -36,6 +36,9 @@ address generate_normal_entry(bool synchronized); address generate_native_entry(bool synchronized); +#ifdef GRAAL + address generate_execute_compiled_method_entry(); +#endif address generate_abstract_entry(void); address generate_math_entry(AbstractInterpreter::MethodKind kind); address generate_empty_entry(void); diff -r 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/macroAssembler_x86.cpp --- a/src/cpu/x86/vm/macroAssembler_x86.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/macroAssembler_x86.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/macroAssembler_x86.hpp --- a/src/cpu/x86/vm/macroAssembler_x86.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/macroAssembler_x86.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/methodHandles_x86.cpp --- a/src/cpu/x86/vm/methodHandles_x86.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/methodHandles_x86.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/relocInfo_x86.cpp --- a/src/cpu/x86/vm/relocInfo_x86.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/relocInfo_x86.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/sharedRuntime_x86_32.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -1670,6 +1670,17 @@ verify_oop_args(masm, method, sig_bt, regs); vmIntrinsics::ID iid = method->intrinsic_id(); +#ifdef GRAAL + if (iid == vmIntrinsics::_CompilerToVMImpl_executeCompiledMethod) { + // We are called from compiled code here. The three object arguments + // are already in the correct registers (j_rarg0, jrarg1, jrarg2). The + // fourth argument (j_rarg3) is a raw pointer to the nmethod. Make a tail + // call to its verified entry point. + __ jmp(Address(j_rarg3, nmethod::verified_entry_point_offset())); + return; + } +#endif + // Now write the args into the outgoing interpreter space bool has_receiver = false; Register receiver_reg = noreg; @@ -2326,16 +2337,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) { @@ -3338,6 +3341,10 @@ __ jmp(cont); int reexecute_offset = __ pc() - start; +#ifdef GRAALVM + // Graal does not use this kind of deoptimization + __ should_not_reach_here(); +#endif // Reexecute case // return address is the pc describes what bci to do re-execute at @@ -3348,6 +3355,32 @@ __ movl(r14, Deoptimization::Unpack_reexecute); // callee-saved __ jmp(cont); +#ifdef GRAAL + int implicit_exception_uncommon_trap_offset = __ pc() - start; + // pc where the exception happened is in ScratchA + __ pushptr(Address(r15_thread, in_bytes(JavaThread::ScratchA_offset()))); + + int uncommon_trap_offset = __ pc() - start; + + // Save everything in sight. + RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words); + // fetch_unroll_info needs to call last_java_frame() + __ set_last_Java_frame(noreg, noreg, NULL); + + __ movl(c_rarg1, Address(r15_thread, in_bytes(ThreadShadow::pending_deoptimization_offset()))); + __ movl(Address(r15_thread, in_bytes(ThreadShadow::pending_deoptimization_offset())), -1); + + __ movl(r14, (int32_t)Deoptimization::Unpack_reexecute); + __ mov(c_rarg0, r15_thread); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); + oop_maps->add_gc_map( __ pc()-start, map->deep_copy()); + + __ reset_last_Java_frame(false, false); + + Label after_fetch_unroll_info_call; + __ jmp(after_fetch_unroll_info_call); +#endif // GRAAL + int exception_offset = __ pc() - start; // Prolog for exception case @@ -3404,34 +3437,6 @@ __ bind(no_pending_exception); #endif -#ifdef GRAAL - __ jmp(cont); - - int implicit_exception_uncommon_trap_offset = __ pc() - start; - // pc where the exception happened is in ScratchA - __ pushptr(Address(r15_thread, in_bytes(JavaThread::ScratchA_offset()))); - - int uncommon_trap_offset = __ pc() - start; - - // Save everything in sight. - RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words); - // fetch_unroll_info needs to call last_java_frame() - __ set_last_Java_frame(noreg, noreg, NULL); - - __ movl(c_rarg1, Address(r15_thread, in_bytes(ThreadShadow::pending_deoptimization_offset()))); - __ movl(Address(r15_thread, in_bytes(ThreadShadow::pending_deoptimization_offset())), -1); - - __ movl(r14, (int32_t)Deoptimization::Unpack_reexecute); - __ mov(c_rarg0, r15_thread); - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); - oop_maps->add_gc_map( __ pc()-start, map->deep_copy()); - - __ reset_last_Java_frame(false, false); - - Label after_fetch_unroll_info_call; - __ jmp(after_fetch_unroll_info_call); -#endif // GRAAL - __ bind(cont); // Call C code. Need thread and this frame, but NOT official VM entry diff -r 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/stubGenerator_x86_32.cpp --- a/src/cpu/x86/vm/stubGenerator_x86_32.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/stubGenerator_x86_32.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/stubGenerator_x86_64.cpp --- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/templateInterpreter_x86.hpp --- a/src/cpu/x86/vm/templateInterpreter_x86.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/templateInterpreter_x86.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -34,7 +34,7 @@ // Run with +PrintInterpreter to get the VM to print out the size. // Max size with JVMTI #ifdef AMD64 - const static int InterpreterCodeSize = 224 * 1024; + const static int InterpreterCodeSize = 240 * 1024; #else const static int InterpreterCodeSize = 168 * 1024; #endif // AMD64 diff -r 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/templateInterpreter_x86_32.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 - @@ -1585,7 +1571,8 @@ int callee_locals, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { // Note: This calculation must exactly parallel the frame setup // in AbstractInterpreterGenerator::generate_method_entry. // If interpreter_frame!=NULL, set up the method, locals, and monitors. diff -r 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/templateInterpreter_x86_64.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -873,6 +873,46 @@ return generate_accessor_entry(); } +#ifdef GRAAL + +// Interpreter stub for calling a compiled method with 3 object arguments +address InterpreterGenerator::generate_execute_compiled_method_entry() { + address entry_point = __ pc(); + + // Pick up the return address + __ movptr(rax, Address(rsp, 0)); + + // Must preserve original SP for loading incoming arguments because + // we need to align the outgoing SP for compiled code. + __ movptr(r11, rsp); + + // Ensure compiled code always sees stack at proper alignment + __ andptr(rsp, -16); + + // push the return address and misalign the stack that youngest frame always sees + // as far as the placement of the call instruction + __ push(rax); + + // Move first object argument from interpreter calling convention to compiled + // code calling convention. + __ movq(j_rarg0, Address(r11, Interpreter::stackElementSize*5)); + + // Move second object argument. + __ movq(j_rarg1, Address(r11, Interpreter::stackElementSize*4)); + + // Move third object argument. + __ movq(j_rarg2, Address(r11, Interpreter::stackElementSize*3)); + + // Load the raw pointer to the nmethod. + __ movq(j_rarg3, Address(r11, Interpreter::stackElementSize)); + + // Perform a tail call to the verified entry point of the nmethod. + __ jmp(Address(j_rarg3, nmethod::verified_entry_point_offset())); + + return entry_point; +} + +#endif // Interpreter stub for calling a native method. (asm interpreter) // This sets up a somewhat different looking stack for calling the @@ -1123,15 +1163,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 @@ -1568,6 +1601,9 @@ switch (kind) { case Interpreter::zerolocals : break; case Interpreter::zerolocals_synchronized: synchronized = true; break; +#ifdef GRAAL + case Interpreter::execute_compiled_method: entry_point = ((InterpreterGenerator*)this)->generate_execute_compiled_method_entry(); break; +#endif case Interpreter::native : entry_point = ((InterpreterGenerator*)this)->generate_native_entry(false); break; case Interpreter::native_synchronized : entry_point = ((InterpreterGenerator*)this)->generate_native_entry(true); break; case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break; @@ -1643,7 +1679,8 @@ int callee_locals, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { // Note: This calculation must exactly parallel the frame setup // in AbstractInterpreterGenerator::generate_method_entry. // If interpreter_frame!=NULL, set up the method, locals, and monitors. diff -r 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/x86_32.ad --- a/src/cpu/x86/vm/x86_32.ad Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/x86_32.ad Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/x86/vm/x86_64.ad --- a/src/cpu/x86/vm/x86_64.ad Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/x86/vm/x86_64.ad Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/cpu/zero/vm/cppInterpreter_zero.cpp --- a/src/cpu/zero/vm/cppInterpreter_zero.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/cpu/zero/vm/cppInterpreter_zero.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -919,7 +919,8 @@ int callee_locals, frame* caller, frame* interpreter_frame, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { assert(popframe_extra_args == 0, "what to do?"); assert(!is_top_frame || (!callee_locals && !callee_param_count), "top frame should have no caller"); diff -r 0298d8a0caf5 -r 79b098d44d20 src/os/bsd/vm/os_bsd.cpp --- a/src/os/bsd/vm/os_bsd.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/bsd/vm/os_bsd.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -57,6 +57,7 @@ #include "runtime/threadCritical.hpp" #include "runtime/timer.hpp" #include "services/attachListener.hpp" +#include "services/memTracker.hpp" #include "services/runtimeService.hpp" #include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" @@ -151,7 +152,6 @@ // utility functions static int SR_initialize(); -static int SR_finalize(); julong os::available_memory() { return Bsd::available_memory(); @@ -166,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 @@ -1213,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) { @@ -2275,13 +2264,25 @@ return NULL; } + // The memory is committed + address pc = CALLER_PC; + MemTracker::record_virtual_memory_reserve((address)addr, bytes, pc); + MemTracker::record_virtual_memory_commit((address)addr, bytes, pc); + return addr; } bool os::release_memory_special(char* base, size_t bytes) { // detaching the SHM segment will also delete it, see reserve_memory_special() int rslt = shmdt(base); - return rslt == 0; + if (rslt == 0) { + MemTracker::record_virtual_memory_uncommit((address)base, bytes); + MemTracker::record_virtual_memory_release((address)base, bytes); + return true; + } else { + return false; + } + } size_t os::large_page_size() { @@ -2695,7 +2696,7 @@ assert(thread->is_VM_thread(), "Must be VMThread"); // read current suspend action int action = osthread->sr.suspend_action(); - if (action == SR_SUSPEND) { + if (action == os::Bsd::SuspendResume::SR_SUSPEND) { suspend_save_context(osthread, siginfo, context); // Notify the suspend action is about to be completed. do_suspend() @@ -2717,12 +2718,12 @@ do { sigsuspend(&suspend_set); // ignore all returns until we get a resume signal - } while (osthread->sr.suspend_action() != SR_CONTINUE); + } while (osthread->sr.suspend_action() != os::Bsd::SuspendResume::SR_CONTINUE); resume_clear_context(osthread); } else { - assert(action == SR_CONTINUE, "unexpected sr action"); + assert(action == os::Bsd::SuspendResume::SR_CONTINUE, "unexpected sr action"); // nothing special to do - just leave the handler } @@ -2767,16 +2768,12 @@ 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 static bool do_suspend(OSThread* osthread) { // mark as suspended and send signal - osthread->sr.set_suspend_action(SR_SUSPEND); + osthread->sr.set_suspend_action(os::Bsd::SuspendResume::SR_SUSPEND); int status = pthread_kill(osthread->pthread_id(), SR_signum); assert_status(status == 0, status, "pthread_kill"); @@ -2785,18 +2782,18 @@ for (int i = 0; !osthread->sr.is_suspended(); i++) { os::yield_all(i); } - osthread->sr.set_suspend_action(SR_NONE); + osthread->sr.set_suspend_action(os::Bsd::SuspendResume::SR_NONE); return true; } else { - osthread->sr.set_suspend_action(SR_NONE); + osthread->sr.set_suspend_action(os::Bsd::SuspendResume::SR_NONE); return false; } } static void do_resume(OSThread* osthread) { assert(osthread->sr.is_suspended(), "thread should be suspended"); - osthread->sr.set_suspend_action(SR_CONTINUE); + osthread->sr.set_suspend_action(os::Bsd::SuspendResume::SR_CONTINUE); int status = pthread_kill(osthread->pthread_id(), SR_signum); assert_status(status == 0, status, "pthread_kill"); @@ -2806,7 +2803,7 @@ os::yield_all(i); } } - osthread->sr.set_suspend_action(SR_NONE); + osthread->sr.set_suspend_action(os::Bsd::SuspendResume::SR_NONE); } //////////////////////////////////////////////////////////////////////////////// @@ -3579,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)); @@ -3612,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; @@ -3903,15 +3890,27 @@ jlong os::current_thread_cpu_time() { #ifdef __APPLE__ return os::thread_cpu_time(Thread::current(), true /* user + sys */); +#else + Unimplemented(); + return 0; #endif } jlong os::thread_cpu_time(Thread* thread) { +#ifdef __APPLE__ + return os::thread_cpu_time(thread, true /* user + sys */); +#else + Unimplemented(); + return 0; +#endif } jlong os::current_thread_cpu_time(bool user_sys_cpu_time) { #ifdef __APPLE__ return os::thread_cpu_time(Thread::current(), user_sys_cpu_time); +#else + Unimplemented(); + return 0; #endif } @@ -3935,6 +3934,9 @@ } else { return ((jlong)tinfo.user_time.seconds * 1000000000) + ((jlong)tinfo.user_time.microseconds * (jlong)1000); } +#else + Unimplemented(); + return 0; #endif } diff -r 0298d8a0caf5 -r 79b098d44d20 src/os/bsd/vm/os_bsd.hpp --- a/src/os/bsd/vm/os_bsd.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/bsd/vm/os_bsd.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -151,36 +151,25 @@ // for BsdThreads are no longer needed. class SuspendResume { private: - volatile int _suspend_action; + volatile int _suspend_action; + volatile jint _state; + public: // values for suspend_action: - #define SR_NONE (0x00) - #define SR_SUSPEND (0x01) // suspend request - #define SR_CONTINUE (0x02) // resume request + enum { + SR_NONE = 0x00, + SR_SUSPEND = 0x01, // suspend request + SR_CONTINUE = 0x02, // resume request + SR_SUSPENDED = 0x20 // values for _state: + SR_NONE + }; - volatile jint _state; - // values for _state: + SR_NONE - #define SR_SUSPENDED (0x20) - public: SuspendResume() { _suspend_action = SR_NONE; _state = SR_NONE; } int suspend_action() const { return _suspend_action; } void set_suspend_action(int x) { _suspend_action = x; } // atomic updates for _state - void set_suspended() { - jint temp, temp2; - do { - temp = _state; - temp2 = Atomic::cmpxchg(temp | SR_SUSPENDED, &_state, temp); - } while (temp2 != temp); - } - void clear_suspended() { - jint temp, temp2; - do { - temp = _state; - temp2 = Atomic::cmpxchg(temp & ~SR_SUSPENDED, &_state, temp); - } while (temp2 != temp); - } + inline void set_suspended(); + inline void clear_suspended(); bool is_suspended() { return _state & SR_SUSPENDED; } #undef SR_SUSPENDED diff -r 0298d8a0caf5 -r 79b098d44d20 src/os/bsd/vm/os_bsd.inline.hpp --- a/src/os/bsd/vm/os_bsd.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/bsd/vm/os_bsd.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -25,7 +25,6 @@ #ifndef OS_BSD_VM_OS_BSD_INLINE_HPP #define OS_BSD_VM_OS_BSD_INLINE_HPP -#include "runtime/atomic.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/os.hpp" @@ -286,4 +285,21 @@ const char* optval, socklen_t optlen) { return ::setsockopt(fd, level, optname, optval, optlen); } + +inline void os::Bsd::SuspendResume::set_suspended() { + jint temp, temp2; + do { + temp = _state; + temp2 = Atomic::cmpxchg(temp | SR_SUSPENDED, &_state, temp); + } while (temp2 != temp); +} + +inline void os::Bsd::SuspendResume::clear_suspended() { + jint temp, temp2; + do { + temp = _state; + temp2 = Atomic::cmpxchg(temp & ~SR_SUSPENDED, &_state, temp); + } while (temp2 != temp); +} + #endif // OS_BSD_VM_OS_BSD_INLINE_HPP diff -r 0298d8a0caf5 -r 79b098d44d20 src/os/bsd/vm/perfMemory_bsd.cpp --- a/src/os/bsd/vm/perfMemory_bsd.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/bsd/vm/perfMemory_bsd.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/os/linux/vm/globals_linux.hpp --- a/src/os/linux/vm/globals_linux.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/linux/vm/globals_linux.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, 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 @@ -40,6 +40,9 @@ product(bool, UseHugeTLBFS, false, \ "Use MAP_HUGETLB for large pages") \ \ + product(bool, LoadExecStackDllInVMThread, true, \ + "Load DLLs with executable-stack attribute in the VM Thread") \ + \ product(bool, UseSHM, false, \ "Use SYSV shared memory for large pages") diff -r 0298d8a0caf5 -r 79b098d44d20 src/os/linux/vm/os_linux.cpp --- a/src/os/linux/vm/os_linux.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/linux/vm/os_linux.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -44,6 +44,7 @@ #include "runtime/extendedPC.hpp" #include "runtime/globals.hpp" #include "runtime/interfaceSupport.hpp" +#include "runtime/init.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" #include "runtime/mutexLocker.hpp" @@ -57,10 +58,12 @@ #include "runtime/threadCritical.hpp" #include "runtime/timer.hpp" #include "services/attachListener.hpp" +#include "services/memTracker.hpp" #include "services/runtimeService.hpp" #include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" +#include "utilities/elfFile.hpp" #include "utilities/growableArray.hpp" #include "utilities/vmError.hpp" @@ -173,7 +176,6 @@ // utility functions static int SR_initialize(); -static int SR_finalize(); julong os::available_memory() { return Linux::available_memory(); @@ -191,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 @@ -1644,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) { @@ -1796,20 +1787,101 @@ // in case of error it checks if .dll/.so was built for the // same architecture as Hotspot is running on + +// Remember the stack's state. The Linux dynamic linker will change +// the stack to 'executable' at most once, so we must safepoint only once. +bool os::Linux::_stack_is_executable = false; + +// VM operation that loads a library. This is necessary if stack protection +// of the Java stacks can be lost during loading the library. If we +// do not stop the Java threads, they can stack overflow before the stacks +// are protected again. +class VM_LinuxDllLoad: public VM_Operation { + private: + const char *_filename; + char *_ebuf; + int _ebuflen; + void *_lib; + public: + 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_in_vmthread(_filename, _ebuf, _ebuflen); + os::Linux::_stack_is_executable = true; + } + void* loaded_library() { return _lib; } +}; + void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { - void * result= ::dlopen(filename, RTLD_LAZY); + void * result = NULL; + bool load_attempted = false; + + // Check whether the library to load might change execution rights + // of the stack. If they are changed, the protection of the stack + // guard pages will be lost. We need a safepoint to fix this. + // + // See Linux man page execstack(8) for more info. + if (os::uses_stack_guard_pages() && !os::Linux::_stack_is_executable) { + ElfFile ef(filename); + if (!ef.specifies_noexecstack()) { + if (!is_init_completed()) { + os::Linux::_stack_is_executable = true; + // This is OK - No Java threads have been created yet, and hence no + // stack guard pages to fix. + // + // This should happen only when you are building JDK7 using a very + // old version of JDK6 (e.g., with JPRT) and running test_gamma. + // + // Dynamic loader will make all stacks executable after + // this function returns, and will not do that again. + assert(Threads::first() == NULL, "no Java threads should exist yet."); + } else { + warning("You have loaded library %s which might have disabled stack guard. " + "The VM will try to fix the stack guard now.\n" + "It's highly recommended that you fix the library with " + "'execstack -c ', or link it with '-z noexecstack'.", + filename); + + assert(Thread::current()->is_Java_thread(), "must be Java thread"); + JavaThread *jt = JavaThread::current(); + if (jt->thread_state() != _thread_in_native) { + // This happens when a compiler thread tries to load a hsdis-.so file + // that requires ExecStack. Cannot enter safe point. Let's give up. + warning("Unable to fix stack guard. Giving up."); + } else { + if (!LoadExecStackDllInVMThread) { + // 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 = os::Linux::dlopen_helper(filename, ebuf, ebuflen); + } + + ThreadInVMfromNative tiv(jt); + debug_only(VMNativeEntryWrapper vew;) + + VM_LinuxDllLoad op(filename, ebuf, ebuflen); + VMThread::execute(&op); + if (LoadExecStackDllInVMThread) { + result = op.loaded_library(); + } + load_attempted = true; + } + } + } + } + + if (!load_attempted) { + result = os::Linux::dlopen_helper(filename, ebuf, ebuflen); + } + if (result != NULL) { // Successful loading return result; } 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); @@ -1952,6 +2024,47 @@ return NULL; } +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_helper(filename, ebuf, ebuflen); + } + + // Since 7019808, libjvm.so is linked with -noexecstack. If the VM loads a + // library that requires an executable stack, or which does not have this + // stack attribute set, dlopen changes the stack attribute to executable. The + // read protection of the guard pages gets lost. + // + // Need to check _stack_is_executable again as multiple VM_LinuxDllLoad + // may have been queued at the same time. + + if (!_stack_is_executable) { + JavaThread *jt = Threads::first(); + + while (jt) { + if (!jt->stack_guard_zone_unused() && // Stack not yet fully initialized + jt->stack_yellow_zone_enabled()) { // No pending stack overflow exceptions + if (!os::guard_memory((char *) jt->stack_red_zone_base() - jt->stack_red_zone_size(), + jt->stack_yellow_zone_size() + jt->stack_red_zone_size())) { + warning("Attempt to reguard stack yellow zone failed."); + } + } + jt = jt->next(); + } + } + + return result; +} + /* * glibc-2.0 libdl is not MT safe. If you are building with any glibc, * chances are you might want to run the generated bits against glibc-2.0 @@ -3094,13 +3207,24 @@ numa_make_global(addr, bytes); } + // The memory is committed + address pc = CALLER_PC; + MemTracker::record_virtual_memory_reserve((address)addr, bytes, pc); + MemTracker::record_virtual_memory_commit((address)addr, bytes, pc); + return addr; } bool os::release_memory_special(char* base, size_t bytes) { // detaching the SHM segment will also delete it, see reserve_memory_special() int rslt = shmdt(base); - return rslt == 0; + if (rslt == 0) { + MemTracker::record_virtual_memory_uncommit((address)base, bytes); + MemTracker::record_virtual_memory_release((address)base, bytes); + return true; + } else { + return false; + } } size_t os::large_page_size() { @@ -3461,7 +3585,7 @@ assert(thread->is_VM_thread(), "Must be VMThread"); // read current suspend action int action = osthread->sr.suspend_action(); - if (action == SR_SUSPEND) { + if (action == os::Linux::SuspendResume::SR_SUSPEND) { suspend_save_context(osthread, siginfo, context); // Notify the suspend action is about to be completed. do_suspend() @@ -3483,12 +3607,12 @@ do { sigsuspend(&suspend_set); // ignore all returns until we get a resume signal - } while (osthread->sr.suspend_action() != SR_CONTINUE); + } while (osthread->sr.suspend_action() != os::Linux::SuspendResume::SR_CONTINUE); resume_clear_context(osthread); } else { - assert(action == SR_CONTINUE, "unexpected sr action"); + assert(action == os::Linux::SuspendResume::SR_CONTINUE, "unexpected sr action"); // nothing special to do - just leave the handler } @@ -3533,16 +3657,12 @@ 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 static bool do_suspend(OSThread* osthread) { // mark as suspended and send signal - osthread->sr.set_suspend_action(SR_SUSPEND); + osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_SUSPEND); int status = pthread_kill(osthread->pthread_id(), SR_signum); assert_status(status == 0, status, "pthread_kill"); @@ -3551,18 +3671,18 @@ for (int i = 0; !osthread->sr.is_suspended(); i++) { os::yield_all(i); } - osthread->sr.set_suspend_action(SR_NONE); + osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_NONE); return true; } else { - osthread->sr.set_suspend_action(SR_NONE); + osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_NONE); return false; } } static void do_resume(OSThread* osthread) { assert(osthread->sr.is_suspended(), "thread should be suspended"); - osthread->sr.set_suspend_action(SR_CONTINUE); + osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_CONTINUE); int status = pthread_kill(osthread->pthread_id(), SR_signum); assert_status(status == 0, status, "pthread_kill"); @@ -3572,7 +3692,7 @@ os::yield_all(i); } } - osthread->sr.set_suspend_action(SR_NONE); + osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_NONE); } //////////////////////////////////////////////////////////////////////////////// @@ -4378,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)); @@ -4411,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 0298d8a0caf5 -r 79b098d44d20 src/os/linux/vm/os_linux.hpp --- a/src/os/linux/vm/os_linux.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/linux/vm/os_linux.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -94,6 +94,10 @@ static void print_libversion_info(outputStream* st); public: + static bool _stack_is_executable; + 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(); static void set_fpu_control_word(int fpu_control); @@ -209,39 +213,27 @@ // for LinuxThreads are no longer needed. class SuspendResume { private: - volatile int _suspend_action; + volatile int _suspend_action; + volatile jint _state; + public: // values for suspend_action: - #define SR_NONE (0x00) - #define SR_SUSPEND (0x01) // suspend request - #define SR_CONTINUE (0x02) // resume request + enum { + SR_NONE = 0x00, + SR_SUSPEND = 0x01, // suspend request + SR_CONTINUE = 0x02, // resume request + SR_SUSPENDED = 0x20 // values for _state: + SR_NONE + }; - volatile jint _state; - // values for _state: + SR_NONE - #define SR_SUSPENDED (0x20) - public: SuspendResume() { _suspend_action = SR_NONE; _state = SR_NONE; } int suspend_action() const { return _suspend_action; } void set_suspend_action(int x) { _suspend_action = x; } // atomic updates for _state - void set_suspended() { - jint temp, temp2; - do { - temp = _state; - temp2 = Atomic::cmpxchg(temp | SR_SUSPENDED, &_state, temp); - } while (temp2 != temp); - } - void clear_suspended() { - jint temp, temp2; - do { - temp = _state; - temp2 = Atomic::cmpxchg(temp & ~SR_SUSPENDED, &_state, temp); - } while (temp2 != temp); - } + inline void set_suspended(); + inline void clear_suspended(); bool is_suspended() { return _state & SR_SUSPENDED; } - #undef SR_SUSPENDED }; private: diff -r 0298d8a0caf5 -r 79b098d44d20 src/os/linux/vm/os_linux.inline.hpp --- a/src/os/linux/vm/os_linux.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/linux/vm/os_linux.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -25,7 +25,6 @@ #ifndef OS_LINUX_VM_OS_LINUX_INLINE_HPP #define OS_LINUX_VM_OS_LINUX_INLINE_HPP -#include "runtime/atomic.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/os.hpp" @@ -288,4 +287,21 @@ const char* optval, socklen_t optlen) { return ::setsockopt(fd, level, optname, optval, optlen); } + +inline void os::Linux::SuspendResume::set_suspended() { + jint temp, temp2; + do { + temp = _state; + temp2 = Atomic::cmpxchg(temp | SR_SUSPENDED, &_state, temp); + } while (temp2 != temp); +} + +inline void os::Linux::SuspendResume::clear_suspended() { + jint temp, temp2; + do { + temp = _state; + temp2 = Atomic::cmpxchg(temp & ~SR_SUSPENDED, &_state, temp); + } while (temp2 != temp); +} + #endif // OS_LINUX_VM_OS_LINUX_INLINE_HPP diff -r 0298d8a0caf5 -r 79b098d44d20 src/os/linux/vm/perfMemory_linux.cpp --- a/src/os/linux/vm/perfMemory_linux.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/linux/vm/perfMemory_linux.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/os/posix/launcher/launcher.script --- a/src/os/posix/launcher/launcher.script Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/posix/launcher/launcher.script Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/os/posix/vm/os_posix.cpp --- a/src/os/posix/vm/os_posix.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/posix/vm/os_posix.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/os/solaris/vm/os_solaris.cpp --- a/src/os/solaris/vm/os_solaris.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/solaris/vm/os_solaris.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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) { @@ -2945,7 +2930,7 @@ while (p < (uint64_t)end) { addrs[0] = p; size_t addrs_count = 1; - while (addrs_count < MAX_MEMINFO_CNT && addrs[addrs_count - 1] < (uint64_t)end) { + while (addrs_count < MAX_MEMINFO_CNT && addrs[addrs_count - 1] + page_size < (uint64_t)end) { addrs[addrs_count] = addrs[addrs_count - 1] + page_size; addrs_count++; } @@ -3420,13 +3405,25 @@ if ((retAddr != NULL) && UseNUMAInterleaving) { numa_make_global(retAddr, size); } + + // The memory is committed + address pc = CALLER_PC; + MemTracker::record_virtual_memory_reserve((address)retAddr, size, pc); + MemTracker::record_virtual_memory_commit((address)retAddr, size, pc); + return retAddr; } bool os::release_memory_special(char* base, size_t bytes) { // detaching the SHM segment will also delete it, see reserve_memory_special() int rslt = shmdt(base); - return rslt == 0; + if (rslt == 0) { + MemTracker::record_virtual_memory_uncommit((address)base, bytes); + MemTracker::record_virtual_memory_release((address)base, bytes); + return true; + } else { + return false; + } } size_t os::large_page_size() { @@ -5793,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)); @@ -5828,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 0298d8a0caf5 -r 79b098d44d20 src/os/solaris/vm/os_solaris.inline.hpp --- a/src/os/solaris/vm/os_solaris.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/solaris/vm/os_solaris.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -25,7 +25,6 @@ #ifndef OS_SOLARIS_VM_OS_SOLARIS_INLINE_HPP #define OS_SOLARIS_VM_OS_SOLARIS_INLINE_HPP -#include "runtime/atomic.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/os.hpp" diff -r 0298d8a0caf5 -r 79b098d44d20 src/os/solaris/vm/perfMemory_solaris.cpp --- a/src/os/solaris/vm/perfMemory_solaris.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/solaris/vm/perfMemory_solaris.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/os/windows/vm/decoder_windows.cpp --- a/src/os/windows/vm/decoder_windows.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/windows/vm/decoder_windows.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "prims/jvm.h" +#include "runtime/arguments.hpp" #include "decoder_windows.hpp" WindowsDecoder::WindowsDecoder() { diff -r 0298d8a0caf5 -r 79b098d44d20 src/os/windows/vm/os_windows.cpp --- a/src/os/windows/vm/os_windows.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/windows/vm/os_windows.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -60,6 +60,7 @@ #include "runtime/threadCritical.hpp" #include "runtime/timer.hpp" #include "services/attachListener.hpp" +#include "services/memTracker.hpp" #include "services/runtimeService.hpp" #include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" @@ -685,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 } @@ -1176,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 @@ -2852,7 +2861,7 @@ PAGE_READWRITE); // If reservation failed, return NULL if (p_buf == NULL) return NULL; - + MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, CALLER_PC); os::release_memory(p_buf, bytes + chunk_size); // we still need to round up to a page boundary (in case we are using large pages) @@ -2914,6 +2923,11 @@ if (next_alloc_addr > p_buf) { // Some memory was committed so release it. size_t bytes_to_release = bytes - bytes_remaining; + // NMT has yet to record any individual blocks, so it + // need to create a dummy 'reserve' record to match + // the release. + MemTracker::record_virtual_memory_reserve((address)p_buf, + bytes_to_release, CALLER_PC); os::release_memory(p_buf, bytes_to_release); } #ifdef ASSERT @@ -2925,10 +2939,19 @@ #endif return NULL; } + bytes_remaining -= bytes_to_rq; next_alloc_addr += bytes_to_rq; count++; } + // Although the memory is allocated individually, it is returned as one. + // NMT records it as one block. + address pc = CALLER_PC; + MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, pc); + if ((flags & MEM_COMMIT) != 0) { + MemTracker::record_virtual_memory_commit((address)p_buf, bytes, pc); + } + // made it this far, success return p_buf; } @@ -3115,11 +3138,20 @@ // normal policy just allocate it all at once DWORD flag = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES; char * res = (char *)VirtualAlloc(NULL, bytes, flag, prot); + if (res != NULL) { + address pc = CALLER_PC; + MemTracker::record_virtual_memory_reserve((address)res, bytes, pc); + MemTracker::record_virtual_memory_commit((address)res, bytes, pc); + } + return res; } } bool os::release_memory_special(char* base, size_t bytes) { + assert(base != NULL, "Sanity check"); + // Memory allocated via reserve_memory_special() is committed + MemTracker::record_virtual_memory_uncommit((address)base, bytes); return release_memory(base, bytes); } @@ -3760,6 +3792,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 @@ -3890,6 +3924,10 @@ if (!success) UseNUMAInterleaving = false; } + if (initSock() != JNI_OK) { + return JNI_ERR; + } + return JNI_OK; } @@ -4886,42 +4924,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 0298d8a0caf5 -r 79b098d44d20 src/os/windows/vm/os_windows.inline.hpp --- a/src/os/windows/vm/os_windows.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/windows/vm/os_windows.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -25,7 +25,6 @@ #ifndef OS_WINDOWS_VM_OS_WINDOWS_INLINE_HPP #define OS_WINDOWS_VM_OS_WINDOWS_INLINE_HPP -#include "runtime/atomic.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/os.hpp" diff -r 0298d8a0caf5 -r 79b098d44d20 src/os/windows/vm/perfMemory_windows.cpp --- a/src/os/windows/vm/perfMemory_windows.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os/windows/vm/perfMemory_windows.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/bsd_x86/vm/atomic_bsd_x86.inline.hpp --- a/src/os_cpu/bsd_x86/vm/atomic_bsd_x86.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/bsd_x86/vm/atomic_bsd_x86.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -25,7 +25,6 @@ #ifndef OS_CPU_BSD_X86_VM_ATOMIC_BSD_X86_INLINE_HPP #define OS_CPU_BSD_X86_VM_ATOMIC_BSD_X86_INLINE_HPP -#include "orderAccess_bsd_x86.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "vm_version_x86.hpp" diff -r 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/bsd_x86/vm/bsd_x86_64.ad --- a/src/os_cpu/bsd_x86/vm/bsd_x86_64.ad Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/bsd_x86/vm/bsd_x86_64.ad Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp --- a/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/bsd_x86/vm/orderAccess_bsd_x86.inline.hpp --- a/src/os_cpu/bsd_x86/vm/orderAccess_bsd_x86.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/bsd_x86/vm/orderAccess_bsd_x86.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, 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 @@ -25,8 +25,9 @@ #ifndef OS_CPU_BSD_X86_VM_ORDERACCESS_BSD_X86_INLINE_HPP #define OS_CPU_BSD_X86_VM_ORDERACCESS_BSD_X86_INLINE_HPP -#include "runtime/atomic.hpp" +#include "runtime/atomic.inline.hpp" #include "runtime/orderAccess.hpp" +#include "runtime/os.hpp" #include "vm_version_x86.hpp" // Implementation of class OrderAccess. diff -r 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp --- a/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -516,7 +516,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 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/bsd_zero/vm/atomic_bsd_zero.inline.hpp --- a/src/os_cpu/bsd_zero/vm/atomic_bsd_zero.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/bsd_zero/vm/atomic_bsd_zero.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,7 +26,6 @@ #ifndef OS_CPU_BSD_ZERO_VM_ATOMIC_BSD_ZERO_INLINE_HPP #define OS_CPU_BSD_ZERO_VM_ATOMIC_BSD_ZERO_INLINE_HPP -#include "orderAccess_bsd_zero.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "vm_version_zero.hpp" diff -r 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/bsd_zero/vm/globals_bsd_zero.hpp --- a/src/os_cpu/bsd_zero/vm/globals_bsd_zero.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/bsd_zero/vm/globals_bsd_zero.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/linux_sparc/vm/atomic_linux_sparc.inline.hpp --- a/src/os_cpu/linux_sparc/vm/atomic_linux_sparc.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/linux_sparc/vm/atomic_linux_sparc.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -25,7 +25,6 @@ #ifndef OS_CPU_LINUX_SPARC_VM_ATOMIC_LINUX_SPARC_INLINE_HPP #define OS_CPU_LINUX_SPARC_VM_ATOMIC_LINUX_SPARC_INLINE_HPP -#include "orderAccess_linux_sparc.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "vm_version_sparc.hpp" diff -r 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp --- a/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp --- a/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -410,6 +410,11 @@ // to handle_unexpected_exception way down below. thread->disable_stack_red_zone(); tty->print_raw_cr("An irrecoverable stack overflow has occurred."); + + // This is a likely cause, but hard to verify. Let's just print + // it as a hint. + tty->print_raw_cr("Please check if any of your loaded .so files has " + "enabled executable stack (see man page execstack(8))"); } else { // Accessing stack address below sp may cause SEGV if current // thread has MAP_GROWSDOWN stack. This should only happen when diff -r 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp --- a/src/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -25,7 +25,6 @@ #ifndef OS_CPU_LINUX_X86_VM_ATOMIC_LINUX_X86_INLINE_HPP #define OS_CPU_LINUX_X86_VM_ATOMIC_LINUX_X86_INLINE_HPP -#include "orderAccess_linux_x86.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "vm_version_x86.hpp" diff -r 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/linux_x86/vm/globals_linux_x86.hpp --- a/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/linux_x86/vm/linux_x86_64.ad --- a/src/os_cpu/linux_x86/vm/linux_x86_64.ad Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/linux_x86/vm/linux_x86_64.ad Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp --- a/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, 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 @@ -25,8 +25,9 @@ #ifndef OS_CPU_LINUX_X86_VM_ORDERACCESS_LINUX_X86_INLINE_HPP #define OS_CPU_LINUX_X86_VM_ORDERACCESS_LINUX_X86_INLINE_HPP -#include "runtime/atomic.hpp" +#include "runtime/atomic.inline.hpp" #include "runtime/orderAccess.hpp" +#include "runtime/os.hpp" #include "vm_version_x86.hpp" // Implementation of class OrderAccess. diff -r 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/linux_x86/vm/os_linux_x86.cpp --- a/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -305,6 +305,11 @@ // to handle_unexpected_exception way down below. thread->disable_stack_red_zone(); tty->print_raw_cr("An irrecoverable stack overflow has occurred."); + + // This is a likely cause, but hard to verify. Let's just print + // it as a hint. + tty->print_raw_cr("Please check if any of your loaded .so files has " + "enabled executable stack (see man page execstack(8))"); } else { // Accessing stack address below sp may cause SEGV if current // thread has MAP_GROWSDOWN stack. This should only happen when @@ -335,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 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/linux_zero/vm/atomic_linux_zero.inline.hpp --- a/src/os_cpu/linux_zero/vm/atomic_linux_zero.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/linux_zero/vm/atomic_linux_zero.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,7 +26,6 @@ #ifndef OS_CPU_LINUX_ZERO_VM_ATOMIC_LINUX_ZERO_INLINE_HPP #define OS_CPU_LINUX_ZERO_VM_ATOMIC_LINUX_ZERO_INLINE_HPP -#include "orderAccess_linux_zero.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "vm_version_zero.hpp" diff -r 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/linux_zero/vm/globals_linux_zero.hpp --- a/src/os_cpu/linux_zero/vm/globals_linux_zero.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/linux_zero/vm/globals_linux_zero.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.inline.hpp --- a/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -25,7 +25,6 @@ #ifndef OS_CPU_SOLARIS_SPARC_VM_ATOMIC_SOLARIS_SPARC_INLINE_HPP #define OS_CPU_SOLARIS_SPARC_VM_ATOMIC_SOLARIS_SPARC_INLINE_HPP -#include "orderAccess_solaris_sparc.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "vm_version_sparc.hpp" diff -r 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp --- a/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp --- a/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/solaris_sparc/vm/orderAccess_solaris_sparc.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, 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 @@ -25,6 +25,7 @@ #ifndef OS_CPU_SOLARIS_SPARC_VM_ORDERACCESS_SOLARIS_SPARC_INLINE_HPP #define OS_CPU_SOLARIS_SPARC_VM_ORDERACCESS_SOLARIS_SPARC_INLINE_HPP +#include "runtime/atomic.inline.hpp" #include "runtime/orderAccess.hpp" #include "vm_version_sparc.hpp" diff -r 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/solaris_x86/vm/atomic_solaris_x86.inline.hpp --- a/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -25,7 +25,6 @@ #ifndef OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_INLINE_HPP #define OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_INLINE_HPP -#include "orderAccess_solaris_x86.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "vm_version_x86.hpp" diff -r 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp --- a/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp --- a/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, 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 @@ -25,7 +25,7 @@ #ifndef OS_CPU_SOLARIS_X86_VM_ORDERACCESS_SOLARIS_X86_INLINE_HPP #define OS_CPU_SOLARIS_X86_VM_ORDERACCESS_SOLARIS_X86_INLINE_HPP -#include "runtime/atomic.hpp" +#include "runtime/atomic.inline.hpp" #include "runtime/orderAccess.hpp" #include "runtime/os.hpp" #include "vm_version_x86.hpp" diff -r 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/solaris_x86/vm/solaris_x86_64.ad --- a/src/os_cpu/solaris_x86/vm/solaris_x86_64.ad Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/solaris_x86/vm/solaris_x86_64.ad Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/windows_x86/vm/atomic_windows_x86.inline.hpp --- a/src/os_cpu/windows_x86/vm/atomic_windows_x86.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/windows_x86/vm/atomic_windows_x86.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -25,7 +25,6 @@ #ifndef OS_CPU_WINDOWS_X86_VM_ATOMIC_WINDOWS_X86_INLINE_HPP #define OS_CPU_WINDOWS_X86_VM_ATOMIC_WINDOWS_X86_INLINE_HPP -#include "orderAccess_windows_x86.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "vm_version_x86.hpp" diff -r 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/windows_x86/vm/globals_windows_x86.hpp --- a/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp --- a/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/windows_x86/vm/orderAccess_windows_x86.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, 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 @@ -25,12 +25,11 @@ #ifndef OS_CPU_WINDOWS_X86_VM_ORDERACCESS_WINDOWS_X86_INLINE_HPP #define OS_CPU_WINDOWS_X86_VM_ORDERACCESS_WINDOWS_X86_INLINE_HPP -#include "runtime/atomic.hpp" +#include "runtime/atomic.inline.hpp" #include "runtime/orderAccess.hpp" +#include "runtime/os.hpp" #include "vm_version_x86.hpp" -#pragma warning(disable: 4035) // Disables warnings reporting missing return statement - // Implementation of class OrderAccess. inline void OrderAccess::loadload() { acquire(); } @@ -214,6 +213,4 @@ #endif // AMD64 } -#pragma warning(default: 4035) // Enables warnings reporting missing return statement - #endif // OS_CPU_WINDOWS_X86_VM_ORDERACCESS_WINDOWS_X86_INLINE_HPP diff -r 0298d8a0caf5 -r 79b098d44d20 src/os_cpu/windows_x86/vm/windows_x86_64.ad --- a/src/os_cpu/windows_x86/vm/windows_x86_64.ad Thu Apr 04 11:57:04 2013 +0200 +++ b/src/os_cpu/windows_x86/vm/windows_x86_64.ad Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/tools/ProjectCreator/BuildConfig.java --- a/src/share/tools/ProjectCreator/BuildConfig.java Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/tools/ProjectCreator/BuildConfig.java Mon Apr 15 08:51:19 2013 +0200 @@ -635,36 +635,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 0298d8a0caf5 -r 79b098d44d20 src/share/tools/ProjectCreator/WinGammaPlatform.java --- a/src/share/tools/ProjectCreator/WinGammaPlatform.java Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/tools/ProjectCreator/WinGammaPlatform.java Mon Apr 15 08:51:19 2013 +0200 @@ -568,12 +568,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 0298d8a0caf5 -r 79b098d44d20 src/share/tools/launcher/wildcard.c --- a/src/share/tools/launcher/wildcard.c Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/tools/launcher/wildcard.c Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/adlc/archDesc.cpp --- a/src/share/vm/adlc/archDesc.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/adlc/archDesc.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/adlc/dfa.cpp --- a/src/share/vm/adlc/dfa.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/adlc/dfa.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/adlc/output_c.cpp --- a/src/share/vm/adlc/output_c.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/adlc/output_c.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -63,11 +63,10 @@ RegDef *reg_def = NULL; RegDef *next = NULL; registers->reset_RegDefs(); - for( reg_def = registers->iter_RegDefs(); reg_def != NULL; reg_def = next ) { + for (reg_def = registers->iter_RegDefs(); reg_def != NULL; reg_def = next) { next = registers->iter_RegDefs(); const char *comma = (next != NULL) ? "," : " // no trailing comma"; - fprintf(fp," \"%s\"%s\n", - reg_def->_regname, comma ); + fprintf(fp," \"%s\"%s\n", reg_def->_regname, comma); } // Finish defining enumeration @@ -79,10 +78,10 @@ reg_def = NULL; next = NULL; registers->reset_RegDefs(); - for( reg_def = registers->iter_RegDefs(); reg_def != NULL; reg_def = next ) { + for (reg_def = registers->iter_RegDefs(); reg_def != NULL; reg_def = next) { next = registers->iter_RegDefs(); const char *comma = (next != NULL) ? "," : " // no trailing comma"; - fprintf(fp,"\t%s%s\n", reg_def->_concrete, comma ); + fprintf(fp,"\t%s%s\n", reg_def->_concrete, comma); } // Finish defining array fprintf(fp,"\t};\n"); @@ -104,19 +103,17 @@ RegDef *reg_def = NULL; RegDef *next = NULL; registers->reset_RegDefs(); - for( reg_def = registers->iter_RegDefs(); reg_def != NULL; reg_def = next ) { + for (reg_def = registers->iter_RegDefs(); reg_def != NULL; reg_def = next) { next = registers->iter_RegDefs(); const char* register_encode = reg_def->register_encode(); const char *comma = (next != NULL) ? "," : " // no trailing comma"; int encval; if (!ADLParser::is_int_token(register_encode, encval)) { - fprintf(fp," %s%s // %s\n", - register_encode, comma, reg_def->_regname ); + fprintf(fp," %s%s // %s\n", register_encode, comma, reg_def->_regname); } else { // Output known constants in hex char format (backward compatibility). assert(encval < 256, "Exceeded supported width for register encoding"); - fprintf(fp," (unsigned char)'\\x%X'%s // %s\n", - encval, comma, reg_def->_regname ); + fprintf(fp," (unsigned char)'\\x%X'%s // %s\n", encval, comma, reg_def->_regname); } } // Finish defining enumeration @@ -133,9 +130,10 @@ fprintf(fp,"// Enumeration of register class names\n"); fprintf(fp, "enum machRegisterClass {\n"); registers->_rclasses.reset(); - for( const char *class_name = NULL; - (class_name = registers->_rclasses.iter()) != NULL; ) { - fprintf(fp," %s,\n", toUpper( class_name )); + for (const char *class_name = NULL; (class_name = registers->_rclasses.iter()) != NULL;) { + const char * class_name_to_upper = toUpper(class_name); + fprintf(fp," %s,\n", class_name_to_upper); + delete[] class_name_to_upper; } // Finish defining enumeration fprintf(fp, " _last_Mach_Reg_Class\n"); @@ -148,7 +146,7 @@ void ArchDesc::declare_register_masks(FILE *fp_hpp) { const char *rc_name; - if( _register ) { + if (_register) { // Build enumeration of user-defined register classes. defineRegClassEnum(fp_hpp, _register); @@ -156,24 +154,27 @@ fprintf(fp_hpp,"\n"); fprintf(fp_hpp,"// Register masks, one for each register class.\n"); _register->_rclasses.reset(); - for( rc_name = NULL; - (rc_name = _register->_rclasses.iter()) != NULL; ) { - const char *prefix = ""; - RegClass *reg_class = _register->getRegClass(rc_name); - assert( reg_class, "Using an undefined register class"); + for (rc_name = NULL; (rc_name = _register->_rclasses.iter()) != NULL;) { + const char *prefix = ""; + RegClass *reg_class = _register->getRegClass(rc_name); + assert(reg_class, "Using an undefined register class"); + + const char* rc_name_to_upper = toUpper(rc_name); if (reg_class->_user_defined == NULL) { - fprintf(fp_hpp, "extern const RegMask _%s%s_mask;\n", prefix, toUpper( rc_name ) ); - fprintf(fp_hpp, "inline const RegMask &%s%s_mask() { return _%s%s_mask; }\n", prefix, toUpper( rc_name ), prefix, toUpper( rc_name )); + fprintf(fp_hpp, "extern const RegMask _%s%s_mask;\n", prefix, rc_name_to_upper); + fprintf(fp_hpp, "inline const RegMask &%s%s_mask() { return _%s%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); } else { - fprintf(fp_hpp, "inline const RegMask &%s%s_mask() { %s }\n", prefix, toUpper( rc_name ), reg_class->_user_defined); + fprintf(fp_hpp, "inline const RegMask &%s%s_mask() { %s }\n", prefix, rc_name_to_upper, reg_class->_user_defined); } - if( reg_class->_stack_or_reg ) { + if (reg_class->_stack_or_reg) { assert(reg_class->_user_defined == NULL, "no user defined reg class here"); - fprintf(fp_hpp, "extern const RegMask _%sSTACK_OR_%s_mask;\n", prefix, toUpper( rc_name ) ); - fprintf(fp_hpp, "inline const RegMask &%sSTACK_OR_%s_mask() { return _%sSTACK_OR_%s_mask; }\n", prefix, toUpper( rc_name ), prefix, toUpper( rc_name ) ); + fprintf(fp_hpp, "extern const RegMask _%sSTACK_OR_%s_mask;\n", prefix, rc_name_to_upper); + fprintf(fp_hpp, "inline const RegMask &%sSTACK_OR_%s_mask() { return _%sSTACK_OR_%s_mask; }\n", prefix, rc_name_to_upper, prefix, rc_name_to_upper); } + delete[] rc_name_to_upper; + } } } @@ -183,34 +184,41 @@ void ArchDesc::build_register_masks(FILE *fp_cpp) { const char *rc_name; - if( _register ) { + if (_register) { // Generate a list of register masks, one for each class. fprintf(fp_cpp,"\n"); fprintf(fp_cpp,"// Register masks, one for each register class.\n"); _register->_rclasses.reset(); - for( rc_name = NULL; - (rc_name = _register->_rclasses.iter()) != NULL; ) { - const char *prefix = ""; - RegClass *reg_class = _register->getRegClass(rc_name); - assert( reg_class, "Using an undefined register class"); - - if (reg_class->_user_defined != NULL) continue; + for (rc_name = NULL; (rc_name = _register->_rclasses.iter()) != NULL;) { + const char *prefix = ""; + RegClass *reg_class = _register->getRegClass(rc_name); + assert(reg_class, "Using an undefined register class"); + + if (reg_class->_user_defined != NULL) { + continue; + } int len = RegisterForm::RegMask_Size(); - fprintf(fp_cpp, "const RegMask _%s%s_mask(", prefix, toUpper( rc_name ) ); - { int i; - for( i = 0; i < len-1; i++ ) - fprintf(fp_cpp," 0x%x,",reg_class->regs_in_word(i,false)); - fprintf(fp_cpp," 0x%x );\n",reg_class->regs_in_word(i,false)); + const char* rc_name_to_upper = toUpper(rc_name); + fprintf(fp_cpp, "const RegMask _%s%s_mask(", prefix, rc_name_to_upper); + + { + int i; + for(i = 0; i < len - 1; i++) { + fprintf(fp_cpp," 0x%x,", reg_class->regs_in_word(i, false)); + } + fprintf(fp_cpp," 0x%x );\n", reg_class->regs_in_word(i, false)); } - if( reg_class->_stack_or_reg ) { + if (reg_class->_stack_or_reg) { int i; - fprintf(fp_cpp, "const RegMask _%sSTACK_OR_%s_mask(", prefix, toUpper( rc_name ) ); - for( i = 0; i < len-1; i++ ) - fprintf(fp_cpp," 0x%x,",reg_class->regs_in_word(i,true)); - fprintf(fp_cpp," 0x%x );\n",reg_class->regs_in_word(i,true)); + fprintf(fp_cpp, "const RegMask _%sSTACK_OR_%s_mask(", prefix, rc_name_to_upper); + for(i = 0; i < len - 1; i++) { + fprintf(fp_cpp," 0x%x,",reg_class->regs_in_word(i, true)); + } + fprintf(fp_cpp," 0x%x );\n",reg_class->regs_in_word(i, true)); } + delete[] rc_name_to_upper; } } } @@ -2676,7 +2684,9 @@ if (strcmp(first_reg_class, "stack_slots") == 0) { fprintf(fp," return &(Compile::current()->FIRST_STACK_mask());\n"); } else { - fprintf(fp," return &%s_mask();\n", toUpper(first_reg_class)); + const char* first_reg_class_to_upper = toUpper(first_reg_class); + fprintf(fp," return &%s_mask();\n", first_reg_class_to_upper); + delete[] first_reg_class_to_upper; } } else { // Build a switch statement to return the desired mask. @@ -2688,7 +2698,9 @@ if( !strcmp(reg_class, "stack_slots") ) { fprintf(fp, " case %d: return &(Compile::current()->FIRST_STACK_mask());\n", index); } else { - fprintf(fp, " case %d: return &%s_mask();\n", index, toUpper(reg_class)); + const char* reg_class_to_upper = toUpper(reg_class); + fprintf(fp, " case %d: return &%s_mask();\n", index, reg_class_to_upper); + delete[] reg_class_to_upper; } } fprintf(fp," }\n"); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/adlc/output_h.cpp --- a/src/share/vm/adlc/output_h.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/adlc/output_h.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -2069,9 +2069,21 @@ void closing() { fprintf(_cpp, " _LAST_MACH_OPER\n"); OutputMap::closing(); } - void map(OpClassForm &opc) { fprintf(_cpp, " %s", _AD.machOperEnum(opc._ident) ); } - void map(OperandForm &oper) { fprintf(_cpp, " %s", _AD.machOperEnum(oper._ident) ); } - void map(char *name) { fprintf(_cpp, " %s", _AD.machOperEnum(name)); } + void map(OpClassForm &opc) { + const char* opc_ident_to_upper = _AD.machOperEnum(opc._ident); + fprintf(_cpp, " %s", opc_ident_to_upper); + delete[] opc_ident_to_upper; + } + void map(OperandForm &oper) { + const char* oper_ident_to_upper = _AD.machOperEnum(oper._ident); + fprintf(_cpp, " %s", oper_ident_to_upper); + delete[] oper_ident_to_upper; + } + void map(char *name) { + const char* name_to_upper = _AD.machOperEnum(name); + fprintf(_cpp, " %s", name_to_upper); + delete[] name_to_upper; + } bool do_instructions() { return false; } void map(InstructForm &inst){ assert( false, "ShouldNotCallThis()"); } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/asm/assembler.cpp --- a/src/share/vm/asm/assembler.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/asm/assembler.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/asm/assembler.hpp --- a/src/share/vm/asm/assembler.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/asm/assembler.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/asm/codeBuffer.cpp --- a/src/share/vm/asm/codeBuffer.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/asm/codeBuffer.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/asm/codeBuffer.hpp --- a/src/share/vm/asm/codeBuffer.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/asm/codeBuffer.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_Canonicalizer.cpp --- a/src/share/vm/c1/c1_Canonicalizer.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_Canonicalizer.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_Canonicalizer.hpp --- a/src/share/vm/c1/c1_Canonicalizer.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_Canonicalizer.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_CodeStubs.hpp --- a/src/share/vm/c1/c1_CodeStubs.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_CodeStubs.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_Compilation.cpp --- a/src/share/vm/c1/c1_Compilation.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_Compilation.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_Compilation.hpp --- a/src/share/vm/c1/c1_Compilation.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_Compilation.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_FrameMap.cpp --- a/src/share/vm/c1/c1_FrameMap.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_FrameMap.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -308,27 +308,6 @@ return sp_offset_for_monitor_base(index) + in_ByteSize(BasicObjectLock::obj_offset_in_bytes()); } -void FrameMap::print_frame_layout() const { - int svar; - tty->print_cr("#####################################"); - tty->print_cr("Frame size in words %d", framesize()); - - if( _num_monitors > 0) { - tty->print_cr("monitor [0]:%d | [%2d]:%d", - in_bytes(sp_offset_for_monitor_base(0)), - in_bytes(sp_offset_for_monitor_base(_num_monitors))); - } - if( _num_spills > 0) { - svar = _num_spills - 1; - if(svar == 0) - tty->print_cr("spill [0]:%d", in_bytes(sp_offset_for_spill(0))); - else - tty->print_cr("spill [0]:%d | [%2d]:%d", in_bytes(sp_offset_for_spill(0)), - svar, - in_bytes(sp_offset_for_spill(svar))); - } -} - // For OopMaps, map a local variable or spill index to an VMReg. // This is the offset from sp() in the frame of the slot for the index, diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_FrameMap.hpp --- a/src/share/vm/c1/c1_FrameMap.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_FrameMap.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -226,8 +226,6 @@ return make_new_address(sp_offset_for_monitor_object(monitor_index)); } - void print_frame_layout() const; - // Creates Location describing desired slot and returns it via pointer // to Location object. Returns true if the stack frame offset was legal // (as defined by Location::legal_offset_in_bytes()), false otherwise. diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_GraphBuilder.hpp --- a/src/share/vm/c1/c1_GraphBuilder.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_GraphBuilder.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_IR.cpp --- a/src/share/vm/c1/c1_IR.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_IR.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_IR.hpp --- a/src/share/vm/c1/c1_IR.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_IR.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -255,6 +255,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(); } @@ -262,7 +263,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); @@ -273,6 +274,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); @@ -310,7 +312,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_Instruction.cpp --- a/src/share/vm/c1/c1_Instruction.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_Instruction.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_Instruction.hpp --- a/src/share/vm/c1/c1_Instruction.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_Instruction.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_InstructionPrinter.cpp --- a/src/share/vm/c1/c1_InstructionPrinter.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_InstructionPrinter.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_InstructionPrinter.hpp --- a/src/share/vm/c1/c1_InstructionPrinter.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_InstructionPrinter.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_LIR.cpp --- a/src/share/vm/c1/c1_LIR.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_LIR.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_LIR.hpp --- a/src/share/vm/c1/c1_LIR.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_LIR.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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); @@ -2375,7 +2407,7 @@ // collects all register operands of the instruction void visit(LIR_Op* op); -#if ASSERT +#ifdef ASSERT // check that an operation has no operands bool no_operands(LIR_Op* op); #endif diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_LIRAssembler.hpp --- a/src/share/vm/c1/c1_LIRAssembler.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_LIRAssembler.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_LIRGenerator.cpp --- a/src/share/vm/c1/c1_LIRGenerator.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_LIRGenerator.hpp --- a/src/share/vm/c1/c1_LIRGenerator.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_LIRGenerator.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_LinearScan.cpp --- a/src/share/vm/c1/c1_LinearScan.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_LinearScan.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_Optimizer.cpp --- a/src/share/vm/c1/c1_Optimizer.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_Optimizer.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 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 Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 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 Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_Runtime1.cpp --- a/src/share/vm/c1/c1_Runtime1.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_Runtime1.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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(), Deoptimization::Reason_none); + +JRT_END #ifndef PRODUCT void Runtime1::print_statistics() { diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_Runtime1.hpp --- a/src/share/vm/c1/c1_Runtime1.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_Runtime1.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_ValueMap.cpp --- a/src/share/vm/c1/c1_ValueMap.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_ValueMap.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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,143 @@ , _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; + bool _insert_is_pred; + + 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(); + _insert_is_pred = loop_header->is_predecessor(insertion_block); + + 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()) && _insert_is_pred; + } 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()) && _insert_is_pred; + } + + 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 +449,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 +473,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 +487,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 +500,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 +523,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 +552,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_ValueMap.hpp --- a/src/share/vm/c1/c1_ValueMap.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_ValueMap.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/c1/c1_globals.hpp --- a/src/share/vm/c1/c1_globals.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/c1/c1_globals.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/ci/ciEnv.cpp --- a/src/share/vm/ci/ciEnv.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/ci/ciEnv.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/ci/ciMethod.cpp --- a/src/share/vm/ci/ciMethod.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/ci/ciMethod.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/ci/ciMethod.hpp --- a/src/share/vm/ci/ciMethod.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/ci/ciMethod.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/ci/ciTypeFlow.cpp --- a/src/share/vm/ci/ciTypeFlow.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/ci/ciTypeFlow.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -2540,7 +2540,7 @@ } else if (innermost->head() == blk) { // If loop header, complete the tree pointers if (blk->loop() != innermost) { -#if ASSERT +#ifdef ASSERT assert(blk->loop()->head() == innermost->head(), "same head"); Loop* dl; for (dl = innermost; dl != NULL && dl != blk->loop(); dl = dl->parent()); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/classfile/classFileParser.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -90,8 +90,7 @@ // Extension method support. #define JAVA_8_VERSION 52 - -void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, constantPoolHandle cp, int length, TRAPS) { +void ClassFileParser::parse_constant_pool_entries(int length, TRAPS) { // Use a local copy of ClassFileStream. It helps the C++ compiler to optimize // this function (_current can be allocated in a register, with scalar // replacement of aggregates). The _current pointer is copied back to @@ -104,7 +103,7 @@ assert(cfs->allocated_on_stack(),"should be local"); u1* old_current = cfs0->current(); #endif - Handle class_loader(THREAD, loader_data->class_loader()); + Handle class_loader(THREAD, _loader_data->class_loader()); // Used for batching symbol allocations. const char* names[SymbolTable::symbol_alloc_batch_size]; @@ -124,7 +123,7 @@ { cfs->guarantee_more(3, CHECK); // name_index, tag/access_flags u2 name_index = cfs->get_u2_fast(); - cp->klass_index_at_put(index, name_index); + _cp->klass_index_at_put(index, name_index); } break; case JVM_CONSTANT_Fieldref : @@ -132,7 +131,7 @@ cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags u2 class_index = cfs->get_u2_fast(); u2 name_and_type_index = cfs->get_u2_fast(); - cp->field_at_put(index, class_index, name_and_type_index); + _cp->field_at_put(index, class_index, name_and_type_index); } break; case JVM_CONSTANT_Methodref : @@ -140,7 +139,7 @@ cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags u2 class_index = cfs->get_u2_fast(); u2 name_and_type_index = cfs->get_u2_fast(); - cp->method_at_put(index, class_index, name_and_type_index); + _cp->method_at_put(index, class_index, name_and_type_index); } break; case JVM_CONSTANT_InterfaceMethodref : @@ -148,14 +147,14 @@ cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags u2 class_index = cfs->get_u2_fast(); u2 name_and_type_index = cfs->get_u2_fast(); - cp->interface_method_at_put(index, class_index, name_and_type_index); + _cp->interface_method_at_put(index, class_index, name_and_type_index); } break; case JVM_CONSTANT_String : { cfs->guarantee_more(3, CHECK); // string_index, tag/access_flags u2 string_index = cfs->get_u2_fast(); - cp->string_index_at_put(index, string_index); + _cp->string_index_at_put(index, string_index); } break; case JVM_CONSTANT_MethodHandle : @@ -174,11 +173,11 @@ cfs->guarantee_more(4, CHECK); // ref_kind, method_index, tag/access_flags u1 ref_kind = cfs->get_u1_fast(); u2 method_index = cfs->get_u2_fast(); - cp->method_handle_index_at_put(index, ref_kind, method_index); + _cp->method_handle_index_at_put(index, ref_kind, method_index); } else if (tag == JVM_CONSTANT_MethodType) { cfs->guarantee_more(3, CHECK); // signature_index, tag/access_flags u2 signature_index = cfs->get_u2_fast(); - cp->method_type_index_at_put(index, signature_index); + _cp->method_type_index_at_put(index, signature_index); } else { ShouldNotReachHere(); } @@ -200,21 +199,21 @@ u2 name_and_type_index = cfs->get_u2_fast(); if (_max_bootstrap_specifier_index < (int) bootstrap_specifier_index) _max_bootstrap_specifier_index = (int) bootstrap_specifier_index; // collect for later - cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index); + _cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index); } break; case JVM_CONSTANT_Integer : { cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags u4 bytes = cfs->get_u4_fast(); - cp->int_at_put(index, (jint) bytes); + _cp->int_at_put(index, (jint) bytes); } break; case JVM_CONSTANT_Float : { cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags u4 bytes = cfs->get_u4_fast(); - cp->float_at_put(index, *(jfloat*)&bytes); + _cp->float_at_put(index, *(jfloat*)&bytes); } break; case JVM_CONSTANT_Long : @@ -225,7 +224,7 @@ { cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags u8 bytes = cfs->get_u8_fast(); - cp->long_at_put(index, bytes); + _cp->long_at_put(index, bytes); } index++; // Skip entry following eigth-byte constant, see JVM book p. 98 break; @@ -237,7 +236,7 @@ { cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags u8 bytes = cfs->get_u8_fast(); - cp->double_at_put(index, *(jdouble*)&bytes); + _cp->double_at_put(index, *(jdouble*)&bytes); } index++; // Skip entry following eigth-byte constant, see JVM book p. 98 break; @@ -246,7 +245,7 @@ cfs->guarantee_more(5, CHECK); // name_index, signature_index, tag/access_flags u2 name_index = cfs->get_u2_fast(); u2 signature_index = cfs->get_u2_fast(); - cp->name_and_type_at_put(index, name_index, signature_index); + _cp->name_and_type_at_put(index, name_index, signature_index); } break; case JVM_CONSTANT_Utf8 : @@ -283,11 +282,11 @@ indices[names_count] = index; hashValues[names_count++] = hash; if (names_count == SymbolTable::symbol_alloc_batch_size) { - SymbolTable::new_symbols(loader_data, cp, names_count, names, lengths, indices, hashValues, CHECK); + SymbolTable::new_symbols(_loader_data, _cp, names_count, names, lengths, indices, hashValues, CHECK); names_count = 0; } } else { - cp->symbol_at_put(index, result); + _cp->symbol_at_put(index, result); } } break; @@ -300,7 +299,7 @@ // Allocate the remaining symbols if (names_count > 0) { - SymbolTable::new_symbols(loader_data, cp, names_count, names, lengths, indices, hashValues, CHECK); + SymbolTable::new_symbols(_loader_data, _cp, names_count, names, lengths, indices, hashValues, CHECK); } // Copy _current pointer of local copy back to stream(). @@ -310,23 +309,6 @@ cfs0->set_current(cfs1.current()); } -// This class unreferences constant pool symbols if an error has occurred -// while parsing the class before it is assigned into the class. -// If it gets an error after that it is unloaded and the constant pool will -// be cleaned up then. -class ConstantPoolCleaner : public StackObj { - constantPoolHandle _cphandle; - bool _in_error; - public: - ConstantPoolCleaner(constantPoolHandle cp) : _cphandle(cp), _in_error(true) {} - ~ConstantPoolCleaner() { - if (_in_error && _cphandle.not_null()) { - _cphandle->unreference_symbols(); - } - } - void set_in_error(bool clean) { _in_error = clean; } -}; - bool inline valid_cp_range(int index, int length) { return (index > 0 && index < length); } inline Symbol* check_symbol_at(constantPoolHandle cp, int index) { @@ -336,7 +318,7 @@ return NULL; } -constantPoolHandle ClassFileParser::parse_constant_pool(ClassLoaderData* loader_data, TRAPS) { +constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) { ClassFileStream* cfs = stream(); constantPoolHandle nullHandle; @@ -345,16 +327,13 @@ guarantee_property( length >= 1, "Illegal constant pool size %u in class file %s", length, CHECK_(nullHandle)); - ConstantPool* constant_pool = - ConstantPool::allocate(loader_data, - length, - CHECK_(nullHandle)); + ConstantPool* constant_pool = ConstantPool::allocate(_loader_data, length, + CHECK_(nullHandle)); + _cp = constant_pool; // save in case of errors constantPoolHandle cp (THREAD, constant_pool); - ConstantPoolCleaner cp_in_error(cp); // set constant pool to be cleaned up. - // parsing constant pool entries - parse_constant_pool_entries(loader_data, cp, length, CHECK_(nullHandle)); + parse_constant_pool_entries(length, CHECK_(nullHandle)); int index = 1; // declared outside of loops for portability @@ -373,8 +352,7 @@ if (!_need_verify) break; int klass_ref_index = cp->klass_ref_index_at(index); int name_and_type_ref_index = cp->name_and_type_ref_index_at(index); - check_property(valid_cp_range(klass_ref_index, length) && - is_klass_reference(cp, klass_ref_index), + check_property(valid_klass_reference_at(klass_ref_index), "Invalid constant pool index %u in class file %s", klass_ref_index, CHECK_(nullHandle)); @@ -404,16 +382,12 @@ if (!_need_verify) break; int name_ref_index = cp->name_ref_index_at(index); int signature_ref_index = cp->signature_ref_index_at(index); - check_property( - valid_cp_range(name_ref_index, length) && - cp->tag_at(name_ref_index).is_utf8(), - "Invalid constant pool index %u in class file %s", - name_ref_index, CHECK_(nullHandle)); - check_property( - valid_cp_range(signature_ref_index, length) && - cp->tag_at(signature_ref_index).is_utf8(), - "Invalid constant pool index %u in class file %s", - signature_ref_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(name_ref_index), + "Invalid constant pool index %u in class file %s", + name_ref_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(signature_ref_index), + "Invalid constant pool index %u in class file %s", + signature_ref_index, CHECK_(nullHandle)); break; } case JVM_CONSTANT_Utf8 : @@ -425,22 +399,18 @@ case JVM_CONSTANT_ClassIndex : { int class_index = cp->klass_index_at(index); - check_property( - valid_cp_range(class_index, length) && - cp->tag_at(class_index).is_utf8(), - "Invalid constant pool index %u in class file %s", - class_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(class_index), + "Invalid constant pool index %u in class file %s", + class_index, CHECK_(nullHandle)); cp->unresolved_klass_at_put(index, cp->symbol_at(class_index)); } break; case JVM_CONSTANT_StringIndex : { int string_index = cp->string_index_at(index); - check_property( - valid_cp_range(string_index, length) && - cp->tag_at(string_index).is_utf8(), - "Invalid constant pool index %u in class file %s", - string_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(string_index), + "Invalid constant pool index %u in class file %s", + string_index, CHECK_(nullHandle)); Symbol* sym = cp->symbol_at(string_index); cp->unresolved_string_at_put(index, sym); } @@ -491,12 +461,9 @@ case JVM_CONSTANT_MethodType : { int ref_index = cp->method_type_index_at(index); - check_property( - valid_cp_range(ref_index, length) && - cp->tag_at(ref_index).is_utf8() && - EnableInvokeDynamic, - "Invalid constant pool index %u in class file %s", - ref_index, CHECK_(nullHandle)); + check_property(valid_symbol_at(ref_index) && EnableInvokeDynamic, + "Invalid constant pool index %u in class file %s", + ref_index, CHECK_(nullHandle)); } break; case JVM_CONSTANT_InvokeDynamic : @@ -541,7 +508,6 @@ } if (!_need_verify) { - cp_in_error.set_in_error(false); return cp; } @@ -664,7 +630,6 @@ } // end of switch } // end of for - cp_in_error.set_in_error(false); return cp; } @@ -786,93 +751,92 @@ } -Array* ClassFileParser::parse_interfaces(constantPoolHandle cp, - int length, - ClassLoaderData* loader_data, +Array* ClassFileParser::parse_interfaces(int length, Handle protection_domain, Symbol* class_name, bool* has_default_methods, TRAPS) { - ClassFileStream* cfs = stream(); - assert(length > 0, "only called for length>0"); - // FIXME: Leak at later OOM. - Array* interfaces = MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); - - int index; - for (index = 0; index < length; index++) { - u2 interface_index = cfs->get_u2(CHECK_NULL); - KlassHandle interf; - check_property( - valid_cp_range(interface_index, cp->length()) && - is_klass_reference(cp, interface_index), - "Interface name has bad constant pool index %u in class file %s", - interface_index, CHECK_NULL); - if (cp->tag_at(interface_index).is_klass()) { - interf = KlassHandle(THREAD, cp->resolved_klass_at(interface_index)); - } else { - Symbol* unresolved_klass = cp->klass_name_at(interface_index); - - // Don't need to check legal name because it's checked when parsing constant pool. - // But need to make sure it's not an array type. - guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY, - "Bad interface name in class file %s", CHECK_NULL); - Handle class_loader(THREAD, loader_data->class_loader()); - - // Call resolve_super so classcircularity is checked - Klass* k = SystemDictionary::resolve_super_or_fail(class_name, - unresolved_klass, class_loader, protection_domain, - false, CHECK_NULL); - interf = KlassHandle(THREAD, k); + if (length == 0) { + _local_interfaces = Universe::the_empty_klass_array(); + } else { + ClassFileStream* cfs = stream(); + assert(length > 0, "only called for length>0"); + _local_interfaces = MetadataFactory::new_array(_loader_data, length, NULL, CHECK_NULL); + + int index; + for (index = 0; index < length; index++) { + u2 interface_index = cfs->get_u2(CHECK_NULL); + KlassHandle interf; + check_property( + valid_klass_reference_at(interface_index), + "Interface name has bad constant pool index %u in class file %s", + interface_index, CHECK_NULL); + if (_cp->tag_at(interface_index).is_klass()) { + interf = KlassHandle(THREAD, _cp->resolved_klass_at(interface_index)); + } else { + Symbol* unresolved_klass = _cp->klass_name_at(interface_index); + + // Don't need to check legal name because it's checked when parsing constant pool. + // But need to make sure it's not an array type. + guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY, + "Bad interface name in class file %s", CHECK_NULL); + Handle class_loader(THREAD, _loader_data->class_loader()); + + // Call resolve_super so classcircularity is checked + Klass* k = SystemDictionary::resolve_super_or_fail(class_name, + unresolved_klass, class_loader, protection_domain, + false, CHECK_NULL); + interf = KlassHandle(THREAD, k); + } + + if (!interf()->is_interface()) { + THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", NULL); + } + if (InstanceKlass::cast(interf())->has_default_methods()) { + *has_default_methods = true; + } + _local_interfaces->at_put(index, interf()); } - if (!interf()->is_interface()) { - THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", NULL); - } - if (InstanceKlass::cast(interf())->has_default_methods()) { - *has_default_methods = true; + if (!_need_verify || length <= 1) { + return _local_interfaces; } - interfaces->at_put(index, interf()); - } - - if (!_need_verify || length <= 1) { - return interfaces; - } - - // Check if there's any duplicates in interfaces - ResourceMark rm(THREAD); - NameSigHash** interface_names = NEW_RESOURCE_ARRAY_IN_THREAD( - THREAD, NameSigHash*, HASH_ROW_SIZE); - initialize_hashtable(interface_names); - bool dup = false; - { - debug_only(No_Safepoint_Verifier nsv;) - for (index = 0; index < length; index++) { - Klass* k = interfaces->at(index); - Symbol* name = InstanceKlass::cast(k)->name(); - // If no duplicates, add (name, NULL) in hashtable interface_names. - if (!put_after_lookup(name, NULL, interface_names)) { - dup = true; - break; + + // Check if there's any duplicates in interfaces + ResourceMark rm(THREAD); + NameSigHash** interface_names = NEW_RESOURCE_ARRAY_IN_THREAD( + THREAD, NameSigHash*, HASH_ROW_SIZE); + initialize_hashtable(interface_names); + bool dup = false; + { + debug_only(No_Safepoint_Verifier nsv;) + for (index = 0; index < length; index++) { + Klass* k = _local_interfaces->at(index); + Symbol* name = InstanceKlass::cast(k)->name(); + // If no duplicates, add (name, NULL) in hashtable interface_names. + if (!put_after_lookup(name, NULL, interface_names)) { + dup = true; + break; + } } } - } - if (dup) { - classfile_parse_error("Duplicate interface name in class file %s", CHECK_NULL); + if (dup) { + classfile_parse_error("Duplicate interface name in class file %s", CHECK_NULL); + } } - - return interfaces; + return _local_interfaces; } -void ClassFileParser::verify_constantvalue(int constantvalue_index, int signature_index, constantPoolHandle cp, TRAPS) { +void ClassFileParser::verify_constantvalue(int constantvalue_index, int signature_index, TRAPS) { // Make sure the constant pool entry is of a type appropriate to this field guarantee_property( (constantvalue_index > 0 && - constantvalue_index < cp->length()), + constantvalue_index < _cp->length()), "Bad initial value index %u in ConstantValue attribute in class file %s", constantvalue_index, CHECK); - constantTag value_type = cp->tag_at(constantvalue_index); - switch ( cp->basic_type_for_signature_at(signature_index) ) { + constantTag value_type = _cp->tag_at(constantvalue_index); + switch ( _cp->basic_type_for_signature_at(signature_index) ) { case T_LONG: guarantee_property(value_type.is_long(), "Inconsistent constant value type in class file %s", CHECK); break; @@ -886,7 +850,7 @@ guarantee_property(value_type.is_int(), "Inconsistent constant value type in class file %s", CHECK); break; case T_OBJECT: - guarantee_property((cp->symbol_at(signature_index)->equals("Ljava/lang/String;") + guarantee_property((_cp->symbol_at(signature_index)->equals("Ljava/lang/String;") && value_type.is_string()), "Bad string initial value in class file %s", CHECK); break; @@ -899,15 +863,11 @@ // Parse attributes for a field. -void ClassFileParser::parse_field_attributes(ClassLoaderData* loader_data, - constantPoolHandle cp, - u2 attributes_count, +void ClassFileParser::parse_field_attributes(u2 attributes_count, bool is_static, u2 signature_index, u2* constantvalue_index_addr, bool* is_synthetic_addr, u2* generic_signature_index_addr, - AnnotationArray** field_annotations, - AnnotationArray** field_type_annotations, ClassFileParser::FieldAnnotationCollector* parsed_annotations, TRAPS) { ClassFileStream* cfs = stream(); @@ -927,12 +887,11 @@ cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length u2 attribute_name_index = cfs->get_u2_fast(); u4 attribute_length = cfs->get_u4_fast(); - check_property(valid_cp_range(attribute_name_index, cp->length()) && - cp->tag_at(attribute_name_index).is_utf8(), + check_property(valid_symbol_at(attribute_name_index), "Invalid field attribute index %u in class file %s", attribute_name_index, CHECK); - Symbol* attribute_name = cp->symbol_at(attribute_name_index); + Symbol* attribute_name = _cp->symbol_at(attribute_name_index); if (is_static && attribute_name == vmSymbols::tag_constant_value()) { // ignore if non-static if (constantvalue_index != 0) { @@ -944,7 +903,7 @@ attribute_length, CHECK); constantvalue_index = cfs->get_u2(CHECK); if (_need_verify) { - verify_constantvalue(constantvalue_index, signature_index, cp, CHECK); + verify_constantvalue(constantvalue_index, signature_index, CHECK); } } else if (attribute_name == vmSymbols::tag_synthetic()) { if (attribute_length != 0) { @@ -971,10 +930,8 @@ runtime_visible_annotations_length = attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); - parse_annotations(loader_data, - runtime_visible_annotations, + parse_annotations(runtime_visible_annotations, runtime_visible_annotations_length, - cp, parsed_annotations, CHECK); cfs->skip_u1(runtime_visible_annotations_length, CHECK); @@ -1004,18 +961,18 @@ *constantvalue_index_addr = constantvalue_index; *is_synthetic_addr = is_synthetic; *generic_signature_index_addr = generic_signature_index; - *field_annotations = assemble_annotations(loader_data, - runtime_visible_annotations, + AnnotationArray* a = assemble_annotations(runtime_visible_annotations, runtime_visible_annotations_length, runtime_invisible_annotations, runtime_invisible_annotations_length, CHECK); - *field_type_annotations = assemble_annotations(loader_data, - runtime_visible_type_annotations, - runtime_visible_type_annotations_length, - runtime_invisible_type_annotations, - runtime_invisible_type_annotations_length, - CHECK); + parsed_annotations->set_field_annotations(a); + a = assemble_annotations(runtime_visible_type_annotations, + runtime_visible_type_annotations_length, + runtime_invisible_type_annotations, + runtime_invisible_type_annotations_length, + CHECK); + parsed_annotations->set_field_type_annotations(a); return; } @@ -1106,13 +1063,9 @@ } }; -Array* ClassFileParser::parse_fields(ClassLoaderData* loader_data, - Symbol* class_name, - constantPoolHandle cp, +Array* ClassFileParser::parse_fields(Symbol* class_name, bool is_interface, FieldAllocationCount *fac, - Array** fields_annotations, - Array** fields_type_annotations, u2* java_fields_count_ptr, TRAPS) { ClassFileStream* cfs = stream(); cfs->guarantee_more(2, CHECK_NULL); // length @@ -1147,8 +1100,6 @@ u2* fa = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, u2, total_fields * (FieldInfo::field_slots + 1)); - AnnotationArray* field_annotations = NULL; - AnnotationArray* field_type_annotations = NULL; // The generic signature slots start after all other fields' data. int generic_signature_slot = total_fields * FieldInfo::field_slots; int num_generic_signature = 0; @@ -1161,53 +1112,52 @@ access_flags.set_flags(flags); u2 name_index = cfs->get_u2_fast(); - int cp_size = cp->length(); - check_property( - valid_cp_range(name_index, cp_size) && cp->tag_at(name_index).is_utf8(), + int cp_size = _cp->length(); + check_property(valid_symbol_at(name_index), "Invalid constant pool index %u for field name in class file %s", - name_index, CHECK_NULL); - Symbol* name = cp->symbol_at(name_index); + name_index, + CHECK_NULL); + Symbol* name = _cp->symbol_at(name_index); verify_legal_field_name(name, CHECK_NULL); u2 signature_index = cfs->get_u2_fast(); - check_property( - valid_cp_range(signature_index, cp_size) && - cp->tag_at(signature_index).is_utf8(), + check_property(valid_symbol_at(signature_index), "Invalid constant pool index %u for field signature in class file %s", signature_index, CHECK_NULL); - Symbol* sig = cp->symbol_at(signature_index); + Symbol* sig = _cp->symbol_at(signature_index); verify_legal_field_signature(name, sig, CHECK_NULL); u2 constantvalue_index = 0; bool is_synthetic = false; u2 generic_signature_index = 0; bool is_static = access_flags.is_static(); - FieldAnnotationCollector parsed_annotations; + FieldAnnotationCollector parsed_annotations(_loader_data); u2 attributes_count = cfs->get_u2_fast(); if (attributes_count > 0) { - parse_field_attributes(loader_data, - cp, attributes_count, is_static, signature_index, + parse_field_attributes(attributes_count, is_static, signature_index, &constantvalue_index, &is_synthetic, - &generic_signature_index, &field_annotations, - &field_type_annotations, &parsed_annotations, + &generic_signature_index, &parsed_annotations, CHECK_NULL); - if (field_annotations != NULL) { - if (*fields_annotations == NULL) { - *fields_annotations = MetadataFactory::new_array( - loader_data, length, NULL, + if (parsed_annotations.field_annotations() != NULL) { + if (_fields_annotations == NULL) { + _fields_annotations = MetadataFactory::new_array( + _loader_data, length, NULL, CHECK_NULL); } - (*fields_annotations)->at_put(n, field_annotations); + _fields_annotations->at_put(n, parsed_annotations.field_annotations()); + parsed_annotations.set_field_annotations(NULL); } - if (field_type_annotations != NULL) { - if (*fields_type_annotations == NULL) { - *fields_type_annotations = MetadataFactory::new_array( - loader_data, length, NULL, + if (parsed_annotations.field_type_annotations() != NULL) { + if (_fields_type_annotations == NULL) { + _fields_type_annotations = MetadataFactory::new_array( + _loader_data, length, NULL, CHECK_NULL); } - (*fields_type_annotations)->at_put(n, field_type_annotations); + _fields_type_annotations->at_put(n, parsed_annotations.field_type_annotations()); + parsed_annotations.set_field_type_annotations(NULL); } + if (is_synthetic) { access_flags.set_is_synthetic(); } @@ -1224,7 +1174,7 @@ name_index, signature_index, constantvalue_index); - BasicType type = cp->basic_type_for_signature_at(signature_index); + BasicType type = _cp->basic_type_for_signature_at(signature_index); // Remember how many oops we encountered and compute allocation type FieldAllocationType atype = fac->update(is_static, type); @@ -1245,8 +1195,8 @@ bool duplicate = false; for (int i = 0; i < length; i++) { FieldInfo* f = FieldInfo::from_field_array(fa, i); - if (name == cp->symbol_at(f->name_index()) && - signature == cp->symbol_at(f->signature_index())) { + if (name == _cp->symbol_at(f->name_index()) && + signature == _cp->symbol_at(f->signature_index())) { // Symbol is desclared in Java so skip this one duplicate = true; break; @@ -1280,8 +1230,9 @@ // fields array is trimed. Also unused slots that were reserved // for generic signature indexes are discarded. Array* fields = MetadataFactory::new_array( - loader_data, index * FieldInfo::field_slots + num_generic_signature, + _loader_data, index * FieldInfo::field_slots + num_generic_signature, CHECK_NULL); + _fields = fields; // save in case of error { int i = 0; for (; i < index * FieldInfo::field_slots; i++) { @@ -1303,7 +1254,7 @@ bool dup = false; { debug_only(No_Safepoint_Verifier nsv;) - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { + for (AllFieldStream fs(fields, _cp); !fs.done(); fs.next()) { Symbol* name = fs.name(); Symbol* sig = fs.signature(); // If no duplicates, add name/signature in hashtable names_and_sigs. @@ -1330,10 +1281,8 @@ } -u2* ClassFileParser::parse_exception_table(ClassLoaderData* loader_data, - u4 code_length, +u2* ClassFileParser::parse_exception_table(u4 code_length, u4 exception_table_length, - constantPoolHandle cp, TRAPS) { ClassFileStream* cfs = stream(); @@ -1354,8 +1303,7 @@ "Illegal exception table handler in class file %s", CHECK_NULL); if (catch_type_index != 0) { - guarantee_property(valid_cp_range(catch_type_index, cp->length()) && - is_klass_reference(cp, catch_type_index), + guarantee_property(valid_klass_reference_at(catch_type_index), "Catch type in exception table has bad constant type in class file %s", CHECK_NULL); } } @@ -1506,7 +1454,6 @@ u2* ClassFileParser::parse_localvariable_table(u4 code_length, u2 max_locals, u4 code_attribute_length, - constantPoolHandle cp, u2* localvariable_table_length, bool isLVTT, TRAPS) { @@ -1544,20 +1491,16 @@ "Invalid length %u in %s in class file %s", length, tbl_name, CHECK_NULL); } - int cp_size = cp->length(); - guarantee_property( - valid_cp_range(name_index, cp_size) && - cp->tag_at(name_index).is_utf8(), + int cp_size = _cp->length(); + guarantee_property(valid_symbol_at(name_index), "Name index %u in %s has bad constant type in class file %s", name_index, tbl_name, CHECK_NULL); - guarantee_property( - valid_cp_range(descriptor_index, cp_size) && - cp->tag_at(descriptor_index).is_utf8(), + guarantee_property(valid_symbol_at(descriptor_index), "Signature index %u in %s has bad constant type in class file %s", descriptor_index, tbl_name, CHECK_NULL); - Symbol* name = cp->symbol_at(name_index); - Symbol* sig = cp->symbol_at(descriptor_index); + Symbol* name = _cp->symbol_at(name_index); + Symbol* sig = _cp->symbol_at(descriptor_index); verify_legal_field_name(name, CHECK_NULL); u2 extra_slot = 0; if (!isLVTT) { @@ -1579,7 +1522,7 @@ void ClassFileParser::parse_type_array(u2 array_length, u4 code_length, u4* u1_index, u4* u2_index, - u1* u1_array, u2* u2_array, constantPoolHandle cp, TRAPS) { + u1* u1_array, u2* u2_array, TRAPS) { ClassFileStream* cfs = stream(); u2 index = 0; // index in the array with long/double occupying two slots u4 i1 = *u1_index; @@ -1591,8 +1534,7 @@ index++; } else if (tag == ITEM_Object) { u2 class_index = u2_array[i2++] = cfs->get_u2(CHECK); - guarantee_property(valid_cp_range(class_index, cp->length()) && - is_klass_reference(cp, class_index), + guarantee_property(valid_klass_reference_at(class_index), "Bad class index %u in StackMap in class file %s", class_index, CHECK); } else if (tag == ITEM_Uninitialized) { @@ -1613,8 +1555,7 @@ *u2_index = i2; } -Array* ClassFileParser::parse_stackmap_table( - ClassLoaderData* loader_data, +u1* ClassFileParser::parse_stackmap_table( u4 code_attribute_length, TRAPS) { if (code_attribute_length == 0) return NULL; @@ -1629,18 +1570,12 @@ if (!_need_verify && !DumpSharedSpaces) { return NULL; } - - Array* stackmap_data = - MetadataFactory::new_array(loader_data, code_attribute_length, 0, CHECK_NULL); - - memcpy((void*)stackmap_data->adr_at(0), - (void*)stackmap_table_start, code_attribute_length); - return stackmap_data; + return stackmap_table_start; } u2* ClassFileParser::parse_checked_exceptions(u2* checked_exceptions_length, u4 method_attribute_length, - constantPoolHandle cp, TRAPS) { + TRAPS) { ClassFileStream* cfs = stream(); cfs->guarantee_more(2, CHECK_NULL); // checked_exceptions_length *checked_exceptions_length = cfs->get_u2_fast(); @@ -1657,8 +1592,7 @@ for (int i = 0; i < len; i++) { checked_exception = cfs->get_u2_fast(); check_property( - valid_cp_range(checked_exception, cp->length()) && - is_klass_reference(cp, checked_exception), + valid_klass_reference_at(checked_exception), "Exception name has bad type at constant pool %u in class file %s", checked_exception, CHECK_NULL); } @@ -1735,9 +1669,7 @@ } // Sift through annotations, looking for those significant to the VM: -void ClassFileParser::parse_annotations(ClassLoaderData* loader_data, - u1* buffer, int limit, - constantPoolHandle cp, +void ClassFileParser::parse_annotations(u1* buffer, int limit, ClassFileParser::AnnotationCollector* coll, TRAPS) { // annotations := do(nann:u2) {annotation} @@ -1767,17 +1699,17 @@ u1* abase = buffer + index0; int atype = Bytes::get_Java_u2(abase + atype_off); int count = Bytes::get_Java_u2(abase + count_off); - Symbol* aname = check_symbol_at(cp, atype); + Symbol* aname = check_symbol_at(_cp, atype); if (aname == NULL) break; // invalid annotation name Symbol* member = NULL; if (count >= 1) { int member_index = Bytes::get_Java_u2(abase + member_off); - member = check_symbol_at(cp, member_index); + member = check_symbol_at(_cp, member_index); if (member == NULL) break; // invalid member name } // Here is where parsing particular annotations will take place. - AnnotationCollector::ID id = coll->annotation_index(loader_data, aname); + AnnotationCollector::ID id = coll->annotation_index(_loader_data, aname); if (id == AnnotationCollector::_unknown) continue; coll->set_annotation(id); @@ -1791,9 +1723,6 @@ } else { coll->set_contended_group(0); // default contended group } - coll->set_contended(true); - } else { - coll->set_contended(false); } } } @@ -1803,9 +1732,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 @@ -1836,7 +1770,15 @@ f->set_contended_group(contended_group()); } +ClassFileParser::FieldAnnotationCollector::~FieldAnnotationCollector() { + // If there's an error deallocate metadata for field annotations + MetadataFactory::free_array(_loader_data, _field_annotations); + MetadataFactory::free_array(_loader_data, _field_type_annotations); +} + 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)) @@ -1894,10 +1836,9 @@ && _need_verify && _major_version >= JAVA_1_5_VERSION) { clear_hashtable(lvt_Hash); - ConstantPool* cp = cm->constants(); classfile_parse_error("Duplicated LocalVariableTable attribute " "entry for '%s' in class file %s", - cp->symbol_at(lvt->name_cp_index)->as_utf8(), + _cp->symbol_at(lvt->name_cp_index)->as_utf8(), CHECK); } } @@ -1916,18 +1857,16 @@ if (entry == NULL) { if (_need_verify) { clear_hashtable(lvt_Hash); - ConstantPool* cp = cm->constants(); classfile_parse_error("LVTT entry for '%s' in class file %s " "does not match any LVT entry", - cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), + _cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), CHECK); } } else if (entry->_elem->signature_cp_index != 0 && _need_verify) { clear_hashtable(lvt_Hash); - ConstantPool* cp = cm->constants(); classfile_parse_error("Duplicated LocalVariableTypeTable attribute " "entry for '%s' in class file %s", - cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), + _cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), CHECK); } else { // to add generic signatures into LocalVariableTable @@ -1939,8 +1878,7 @@ } -void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, - ConstMethod* cm, +void ClassFileParser::copy_method_annotations(ConstMethod* cm, u1* runtime_visible_annotations, int runtime_visible_annotations_length, u1* runtime_invisible_annotations, @@ -1961,8 +1899,7 @@ if (runtime_visible_annotations_length + runtime_invisible_annotations_length > 0) { - a = assemble_annotations(loader_data, - runtime_visible_annotations, + a = assemble_annotations(runtime_visible_annotations, runtime_visible_annotations_length, runtime_invisible_annotations, runtime_invisible_annotations_length, @@ -1972,8 +1909,7 @@ if (runtime_visible_parameter_annotations_length + runtime_invisible_parameter_annotations_length > 0) { - a = assemble_annotations(loader_data, - runtime_visible_parameter_annotations, + a = assemble_annotations(runtime_visible_parameter_annotations, runtime_visible_parameter_annotations_length, runtime_invisible_parameter_annotations, runtime_invisible_parameter_annotations_length, @@ -1982,8 +1918,7 @@ } if (annotation_default_length > 0) { - a = assemble_annotations(loader_data, - annotation_default, + a = assemble_annotations(annotation_default, annotation_default_length, NULL, 0, @@ -1993,8 +1928,7 @@ if (runtime_visible_type_annotations_length + runtime_invisible_type_annotations_length > 0) { - a = assemble_annotations(loader_data, - runtime_visible_type_annotations, + a = assemble_annotations(runtime_visible_type_annotations, runtime_visible_type_annotations_length, runtime_invisible_type_annotations, runtime_invisible_type_annotations_length, @@ -2013,9 +1947,7 @@ // from the method back up to the containing klass. These flag values // are added to klass's access_flags. -methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, - constantPoolHandle cp, - bool is_interface, +methodHandle ClassFileParser::parse_method(bool is_interface, AccessFlags *promoted_flags, TRAPS) { ClassFileStream* cfs = stream(); @@ -2026,22 +1958,20 @@ int flags = cfs->get_u2_fast(); u2 name_index = cfs->get_u2_fast(); - int cp_size = cp->length(); + int cp_size = _cp->length(); check_property( - valid_cp_range(name_index, cp_size) && - cp->tag_at(name_index).is_utf8(), + valid_symbol_at(name_index), "Illegal constant pool index %u for method name in class file %s", name_index, CHECK_(nullHandle)); - Symbol* name = cp->symbol_at(name_index); + Symbol* name = _cp->symbol_at(name_index); verify_legal_method_name(name, CHECK_(nullHandle)); u2 signature_index = cfs->get_u2_fast(); guarantee_property( - valid_cp_range(signature_index, cp_size) && - cp->tag_at(signature_index).is_utf8(), + valid_symbol_at(signature_index), "Illegal constant pool index %u for method signature in class file %s", signature_index, CHECK_(nullHandle)); - Symbol* signature = cp->symbol_at(signature_index); + Symbol* signature = _cp->symbol_at(signature_index); AccessFlags access_flags; if (name == vmSymbols::class_initializer_name()) { @@ -2097,7 +2027,8 @@ bool parsed_checked_exceptions_attribute = false; bool parsed_stackmap_attribute = false; // stackmap attribute - JDK1.5 - Array* stackmap_data = NULL; + u1* stackmap_data = NULL; + int stackmap_data_length = 0; u2 generic_signature_index = 0; MethodAnnotationCollector parsed_annotations; u1* runtime_visible_annotations = NULL; @@ -2122,12 +2053,11 @@ u2 method_attribute_name_index = cfs->get_u2_fast(); u4 method_attribute_length = cfs->get_u4_fast(); check_property( - valid_cp_range(method_attribute_name_index, cp_size) && - cp->tag_at(method_attribute_name_index).is_utf8(), + valid_symbol_at(method_attribute_name_index), "Invalid method attribute name index %u in class file %s", method_attribute_name_index, CHECK_(nullHandle)); - Symbol* method_attribute_name = cp->symbol_at(method_attribute_name_index); + Symbol* method_attribute_name = _cp->symbol_at(method_attribute_name_index); if (method_attribute_name == vmSymbols::tag_code()) { // Parse Code attribute if (_need_verify) { @@ -2171,7 +2101,7 @@ exception_table_length = cfs->get_u2_fast(); if (exception_table_length > 0) { exception_table_start = - parse_exception_table(loader_data, code_length, exception_table_length, cp, CHECK_(nullHandle)); + parse_exception_table(code_length, exception_table_length, CHECK_(nullHandle)); } // Parse additional attributes in code attribute @@ -2204,19 +2134,18 @@ calculated_attribute_length += code_attribute_length + sizeof(code_attribute_name_index) + sizeof(code_attribute_length); - check_property(valid_cp_range(code_attribute_name_index, cp_size) && - cp->tag_at(code_attribute_name_index).is_utf8(), + check_property(valid_symbol_at(code_attribute_name_index), "Invalid code attribute name index %u in class file %s", code_attribute_name_index, CHECK_(nullHandle)); if (LoadLineNumberTables && - cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_line_number_table()) { + _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_line_number_table()) { // Parse and compress line number table parse_linenumber_table(code_attribute_length, code_length, &linenumber_table, CHECK_(nullHandle)); } else if (LoadLocalVariableTables && - cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_table()) { + _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_table()) { // Parse local variable table if (!lvt_allocated) { localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD( @@ -2238,7 +2167,6 @@ parse_localvariable_table(code_length, max_locals, code_attribute_length, - cp, &localvariable_table_length[lvt_cnt], false, // is not LVTT CHECK_(nullHandle)); @@ -2246,7 +2174,7 @@ lvt_cnt++; } else if (LoadLocalVariableTypeTables && _major_version >= JAVA_1_5_VERSION && - cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_type_table()) { + _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_type_table()) { if (!lvt_allocated) { localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD( THREAD, u2, INITIAL_MAX_LVT_NUMBER); @@ -2268,19 +2196,18 @@ parse_localvariable_table(code_length, max_locals, code_attribute_length, - cp, &localvariable_type_table_length[lvtt_cnt], true, // is LVTT CHECK_(nullHandle)); lvtt_cnt++; - } else if (UseSplitVerifier && - _major_version >= Verifier::STACKMAP_ATTRIBUTE_MAJOR_VERSION && - cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_stack_map_table()) { + } 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) { classfile_parse_error("Multiple StackMapTable attributes in class file %s", CHECK_(nullHandle)); } - stackmap_data = parse_stackmap_table(loader_data, code_attribute_length, CHECK_(nullHandle)); + stackmap_data = parse_stackmap_table(code_attribute_length, CHECK_(nullHandle)); + stackmap_data_length = code_attribute_length; parsed_stackmap_attribute = true; } else { // Skip unknown attributes @@ -2301,7 +2228,7 @@ checked_exceptions_start = parse_checked_exceptions(&checked_exceptions_length, method_attribute_length, - cp, CHECK_(nullHandle)); + CHECK_(nullHandle)); } else if (method_attribute_name == vmSymbols::tag_method_parameters()) { // reject multiple method parameters if (method_parameters_seen) { @@ -2359,9 +2286,8 @@ runtime_visible_annotations_length = method_attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); - parse_annotations(loader_data, - runtime_visible_annotations, - runtime_visible_annotations_length, cp, &parsed_annotations, + parse_annotations(runtime_visible_annotations, + runtime_visible_annotations_length, &parsed_annotations, CHECK_(nullHandle)); cfs->skip_u1(runtime_visible_annotations_length, CHECK_(nullHandle)); } else if (PreserveAllAnnotations && method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) { @@ -2434,18 +2360,18 @@ 0); Method* m = Method::allocate( - loader_data, code_length, access_flags, &sizes, + _loader_data, code_length, access_flags, &sizes, ConstMethod::NORMAL, CHECK_(nullHandle)); ClassLoadingService::add_class_method_size(m->size()*HeapWordSize); // Fill in information from fixed part (access_flags already set) - m->set_constants(cp()); + m->set_constants(_cp); m->set_name_index(name_index); m->set_signature_index(signature_index); #ifdef CC_INTERP // hmm is there a gc issue here?? - ResultTypeFinder rtf(cp->symbol_at(signature_index)); + ResultTypeFinder rtf(_cp->symbol_at(signature_index)); m->set_result_index(rtf.type()); #endif @@ -2464,7 +2390,10 @@ // Fill in code attribute information m->set_max_stack(max_stack); m->set_max_locals(max_locals); - m->constMethod()->set_stackmap_data(stackmap_data); + if (stackmap_data != NULL) { + m->constMethod()->copy_stackmap_data(_loader_data, stackmap_data, + stackmap_data_length, CHECK_NULL); + } // Copy byte codes m->set_code(code_start); @@ -2520,7 +2449,7 @@ parsed_annotations.apply_to(m); // Copy annotations - copy_method_annotations(loader_data, m->constMethod(), + copy_method_annotations(m->constMethod(), runtime_visible_annotations, runtime_visible_annotations_length, runtime_invisible_annotations, @@ -2560,9 +2489,7 @@ // from the methods back up to the containing klass. These flag values // are added to klass's access_flags. -Array* ClassFileParser::parse_methods(ClassLoaderData* loader_data, - constantPoolHandle cp, - bool is_interface, +Array* ClassFileParser::parse_methods(bool is_interface, AccessFlags* promoted_flags, bool* has_final_method, bool* has_default_methods, @@ -2571,15 +2498,13 @@ cfs->guarantee_more(2, CHECK_NULL); // length u2 length = cfs->get_u2_fast(); if (length == 0) { - return Universe::the_empty_method_array(); + _methods = Universe::the_empty_method_array(); } else { - // FIXME: Handle leaks at later failures. - Array* methods = MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); + _methods = MetadataFactory::new_array(_loader_data, length, NULL, CHECK_NULL); HandleMark hm(THREAD); for (int index = 0; index < length; index++) { - methodHandle method = parse_method(loader_data, - cp, is_interface, + methodHandle method = parse_method(is_interface, promoted_flags, CHECK_NULL); @@ -2590,7 +2515,7 @@ // default method *has_default_methods = true; } - methods->at_put(index, method()); + _methods->at_put(index, method()); } if (_need_verify && length > 1) { @@ -2603,7 +2528,7 @@ { debug_only(No_Safepoint_Verifier nsv;) for (int i = 0; i < length; i++) { - Method* m = methods->at(i); + Method* m = _methods->at(i); // If no duplicates, add name/signature in hashtable names_and_sigs. if (!put_after_lookup(m->name(), m->signature(), names_and_sigs)) { dup = true; @@ -2616,14 +2541,12 @@ CHECK_NULL); } } - return methods; } + return _methods; } -Array* ClassFileParser::sort_methods(ClassLoaderData* loader_data, - Array* methods, - TRAPS) { +intArray* ClassFileParser::sort_methods(Array* methods) { int length = methods->length(); // If JVMTI original method ordering or sharing is enabled we have to // remember the original class file ordering. @@ -2641,10 +2564,11 @@ // Note that the ordering is not alphabetical, see Symbol::fast_compare Method::sort_methods(methods); + intArray* method_ordering = NULL; // If JVMTI original method ordering or sharing is enabled construct int // array remembering the original ordering if (JvmtiExport::can_maintain_original_method_order() || DumpSharedSpaces) { - Array* method_ordering = MetadataFactory::new_array(loader_data, length, CHECK_NULL); + method_ordering = new intArray(length); for (int index = 0; index < length; index++) { Method* m = methods->at(index); int old_index = m->vtable_index(); @@ -2652,29 +2576,25 @@ method_ordering->at_put(index, old_index); m->set_vtable_index(Method::invalid_vtable_index); } - return method_ordering; - } else { - return Universe::the_empty_int_array(); } + return method_ordering; } -void ClassFileParser::parse_classfile_sourcefile_attribute(constantPoolHandle cp, TRAPS) { +void ClassFileParser::parse_classfile_sourcefile_attribute(TRAPS) { ClassFileStream* cfs = stream(); cfs->guarantee_more(2, CHECK); // sourcefile_index u2 sourcefile_index = cfs->get_u2_fast(); check_property( - valid_cp_range(sourcefile_index, cp->length()) && - cp->tag_at(sourcefile_index).is_utf8(), + valid_symbol_at(sourcefile_index), "Invalid SourceFile attribute at constant pool index %u in class file %s", sourcefile_index, CHECK); - set_class_sourcefile(cp->symbol_at(sourcefile_index)); + set_class_sourcefile(_cp->symbol_at(sourcefile_index)); } -void ClassFileParser::parse_classfile_source_debug_extension_attribute(constantPoolHandle cp, - int length, TRAPS) { +void ClassFileParser::parse_classfile_source_debug_extension_attribute(int length, TRAPS) { ClassFileStream* cfs = stream(); u1* sde_buffer = cfs->get_u1_buffer(); assert(sde_buffer != NULL, "null sde buffer"); @@ -2698,12 +2618,10 @@ #define RECOGNIZED_INNER_CLASS_MODIFIERS (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_PRIVATE | JVM_ACC_PROTECTED | JVM_ACC_STATIC) // Return number of classes in the inner classes attribute table -u2 ClassFileParser::parse_classfile_inner_classes_attribute(ClassLoaderData* loader_data, - u1* inner_classes_attribute_start, +u2 ClassFileParser::parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start, bool parsed_enclosingmethod_attribute, u2 enclosing_method_class_index, u2 enclosing_method_method_index, - constantPoolHandle cp, TRAPS) { ClassFileStream* cfs = stream(); u1* current_mark = cfs->current(); @@ -2724,33 +2642,31 @@ // enclosing_method_class_index, // enclosing_method_method_index] int size = length * 4 + (parsed_enclosingmethod_attribute ? 2 : 0); - // FIXME: Will leak on exceptions. - Array* inner_classes = MetadataFactory::new_array(loader_data, size, CHECK_0); + Array* inner_classes = MetadataFactory::new_array(_loader_data, size, CHECK_0); + _inner_classes = inner_classes; + int index = 0; - int cp_size = cp->length(); + int cp_size = _cp->length(); cfs->guarantee_more(8 * length, CHECK_0); // 4-tuples of u2 for (int n = 0; n < length; n++) { // Inner class index u2 inner_class_info_index = cfs->get_u2_fast(); check_property( inner_class_info_index == 0 || - (valid_cp_range(inner_class_info_index, cp_size) && - is_klass_reference(cp, inner_class_info_index)), + valid_klass_reference_at(inner_class_info_index), "inner_class_info_index %u has bad constant type in class file %s", inner_class_info_index, CHECK_0); // Outer class index u2 outer_class_info_index = cfs->get_u2_fast(); check_property( outer_class_info_index == 0 || - (valid_cp_range(outer_class_info_index, cp_size) && - is_klass_reference(cp, outer_class_info_index)), + valid_klass_reference_at(outer_class_info_index), "outer_class_info_index %u has bad constant type in class file %s", outer_class_info_index, CHECK_0); // Inner class name u2 inner_name_index = cfs->get_u2_fast(); check_property( - inner_name_index == 0 || (valid_cp_range(inner_name_index, cp_size) && - cp->tag_at(inner_name_index).is_utf8()), + inner_name_index == 0 || valid_symbol_at(inner_name_index), "inner_name_index %u has bad constant type in class file %s", inner_name_index, CHECK_0); if (_need_verify) { @@ -2794,33 +2710,27 @@ } assert(index == size, "wrong size"); - // Update InstanceKlass with inner class info. - set_class_inner_classes(inner_classes); - // Restore buffer's current position. cfs->set_current(current_mark); return length; } -void ClassFileParser::parse_classfile_synthetic_attribute(constantPoolHandle cp, TRAPS) { +void ClassFileParser::parse_classfile_synthetic_attribute(TRAPS) { set_class_synthetic_flag(true); } -void ClassFileParser::parse_classfile_signature_attribute(constantPoolHandle cp, TRAPS) { +void ClassFileParser::parse_classfile_signature_attribute(TRAPS) { ClassFileStream* cfs = stream(); u2 signature_index = cfs->get_u2(CHECK); check_property( - valid_cp_range(signature_index, cp->length()) && - cp->tag_at(signature_index).is_utf8(), + valid_symbol_at(signature_index), "Invalid constant pool index %u in Signature attribute in class file %s", signature_index, CHECK); - set_class_generic_signature(cp->symbol_at(signature_index)); + set_class_generic_signature(_cp->symbol_at(signature_index)); } -void ClassFileParser::parse_classfile_bootstrap_methods_attribute(ClassLoaderData* loader_data, - constantPoolHandle cp, - u4 attribute_byte_length, TRAPS) { +void ClassFileParser::parse_classfile_bootstrap_methods_attribute(u4 attribute_byte_length, TRAPS) { ClassFileStream* cfs = stream(); u1* current_start = cfs->current(); @@ -2841,10 +2751,14 @@ // The array begins with a series of short[2] pairs, one for each tuple. int index_size = (attribute_array_length * 2); - Array* operands = MetadataFactory::new_array(loader_data, index_size + operand_count, CHECK); + Array* operands = MetadataFactory::new_array(_loader_data, index_size + operand_count, CHECK); + + // Eagerly assign operands so they will be deallocated with the constant + // pool if there is an error. + _cp->set_operands(operands); int operand_fill_index = index_size; - int cp_size = cp->length(); + int cp_size = _cp->length(); for (int n = 0; n < attribute_array_length; n++) { // Store a 32-bit offset into the header of the operand array. @@ -2856,7 +2770,7 @@ u2 argument_count = cfs->get_u2_fast(); check_property( valid_cp_range(bootstrap_method_index, cp_size) && - cp->tag_at(bootstrap_method_index).is_method_handle(), + _cp->tag_at(bootstrap_method_index).is_method_handle(), "bootstrap_method_index %u has bad constant type in class file %s", bootstrap_method_index, CHECK); @@ -2868,7 +2782,7 @@ u2 argument_index = cfs->get_u2_fast(); check_property( valid_cp_range(argument_index, cp_size) && - cp->tag_at(argument_index).is_loadable_constant(), + _cp->tag_at(argument_index).is_loadable_constant(), "argument_index %u has bad constant type in class file %s", argument_index, CHECK); @@ -2883,17 +2797,13 @@ guarantee_property(current_end == current_start + attribute_byte_length, "Bad length on BootstrapMethods in class file %s", CHECK); - - cp->set_operands(operands); } -void ClassFileParser::parse_classfile_attributes(ClassLoaderData* loader_data, - constantPoolHandle cp, - ClassFileParser::ClassAnnotationCollector* parsed_annotations, +void ClassFileParser::parse_classfile_attributes(ClassFileParser::ClassAnnotationCollector* parsed_annotations, TRAPS) { ClassFileStream* cfs = stream(); // Set inner classes attribute to default sentinel - set_class_inner_classes(Universe::the_empty_short_array()); + _inner_classes = Universe::the_empty_short_array(); cfs->guarantee_more(2, CHECK); // attributes_count u2 attributes_count = cfs->get_u2_fast(); bool parsed_sourcefile_attribute = false; @@ -2918,11 +2828,10 @@ u2 attribute_name_index = cfs->get_u2_fast(); u4 attribute_length = cfs->get_u4_fast(); check_property( - valid_cp_range(attribute_name_index, cp->length()) && - cp->tag_at(attribute_name_index).is_utf8(), + valid_symbol_at(attribute_name_index), "Attribute name has bad constant pool index %u in class file %s", attribute_name_index, CHECK); - Symbol* tag = cp->symbol_at(attribute_name_index); + Symbol* tag = _cp->symbol_at(attribute_name_index); if (tag == vmSymbols::tag_source_file()) { // Check for SourceFile tag if (_need_verify) { @@ -2933,10 +2842,10 @@ } else { parsed_sourcefile_attribute = true; } - parse_classfile_sourcefile_attribute(cp, CHECK); + parse_classfile_sourcefile_attribute(CHECK); } else if (tag == vmSymbols::tag_source_debug_extension()) { // Check for SourceDebugExtension tag - parse_classfile_source_debug_extension_attribute(cp, (int)attribute_length, CHECK); + parse_classfile_source_debug_extension_attribute((int)attribute_length, CHECK); } else if (tag == vmSymbols::tag_inner_classes()) { // Check for InnerClasses tag if (parsed_innerclasses_attribute) { @@ -2955,7 +2864,7 @@ "Invalid Synthetic classfile attribute length %u in class file %s", attribute_length, CHECK); } - parse_classfile_synthetic_attribute(cp, CHECK); + parse_classfile_synthetic_attribute(CHECK); } else if (tag == vmSymbols::tag_deprecated()) { // Check for Deprecatd tag - 4276120 if (attribute_length != 0) { @@ -2970,15 +2879,13 @@ "Wrong Signature attribute length %u in class file %s", attribute_length, CHECK); } - parse_classfile_signature_attribute(cp, CHECK); + parse_classfile_signature_attribute(CHECK); } else if (tag == vmSymbols::tag_runtime_visible_annotations()) { runtime_visible_annotations_length = attribute_length; runtime_visible_annotations = cfs->get_u1_buffer(); assert(runtime_visible_annotations != NULL, "null visible annotations"); - parse_annotations(loader_data, - runtime_visible_annotations, + parse_annotations(runtime_visible_annotations, runtime_visible_annotations_length, - cp, parsed_annotations, CHECK); cfs->skip_u1(runtime_visible_annotations_length, CHECK); @@ -3000,13 +2907,11 @@ classfile_parse_error("Invalid class index in EnclosingMethod attribute in class file %s", CHECK); } // Validate the constant pool indices and types - if (!cp->is_within_bounds(enclosing_method_class_index) || - !is_klass_reference(cp, enclosing_method_class_index)) { - classfile_parse_error("Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK); - } + check_property(valid_klass_reference_at(enclosing_method_class_index), + "Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK); if (enclosing_method_method_index != 0 && - (!cp->is_within_bounds(enclosing_method_method_index) || - !cp->tag_at(enclosing_method_method_index).is_name_and_type())) { + (!_cp->is_within_bounds(enclosing_method_method_index) || + !_cp->tag_at(enclosing_method_method_index).is_name_and_type())) { classfile_parse_error("Invalid or out-of-bounds method index in EnclosingMethod attribute in class file %s", CHECK); } } else if (tag == vmSymbols::tag_bootstrap_methods() && @@ -3014,7 +2919,7 @@ if (parsed_bootstrap_methods_attribute) classfile_parse_error("Multiple BootstrapMethods attributes in class file %s", CHECK); parsed_bootstrap_methods_attribute = true; - parse_classfile_bootstrap_methods_attribute(loader_data, cp, attribute_length, CHECK); + parse_classfile_bootstrap_methods_attribute(attribute_length, CHECK); } else if (tag == vmSymbols::tag_runtime_visible_type_annotations()) { runtime_visible_type_annotations_length = attribute_length; runtime_visible_type_annotations = cfs->get_u1_buffer(); @@ -3035,29 +2940,24 @@ cfs->skip_u1(attribute_length, CHECK); } } - AnnotationArray* annotations = assemble_annotations(loader_data, - runtime_visible_annotations, - runtime_visible_annotations_length, - runtime_invisible_annotations, - runtime_invisible_annotations_length, - CHECK); - set_class_annotations(annotations); - AnnotationArray* type_annotations = assemble_annotations(loader_data, - runtime_visible_type_annotations, - runtime_visible_type_annotations_length, - runtime_invisible_type_annotations, - runtime_invisible_type_annotations_length, - CHECK); - set_class_type_annotations(type_annotations); + _annotations = assemble_annotations(runtime_visible_annotations, + runtime_visible_annotations_length, + runtime_invisible_annotations, + runtime_invisible_annotations_length, + CHECK); + _type_annotations = assemble_annotations(runtime_visible_type_annotations, + runtime_visible_type_annotations_length, + runtime_invisible_type_annotations, + runtime_invisible_type_annotations_length, + CHECK); if (parsed_innerclasses_attribute || parsed_enclosingmethod_attribute) { u2 num_of_classes = parse_classfile_inner_classes_attribute( - loader_data, inner_classes_attribute_start, parsed_innerclasses_attribute, enclosing_method_class_index, enclosing_method_method_index, - cp, CHECK); + CHECK); if (parsed_innerclasses_attribute &&_need_verify && _major_version >= JAVA_1_5_VERSION) { guarantee_property( inner_classes_attribute_length == sizeof(num_of_classes) + 4 * sizeof(u2) * num_of_classes, @@ -3085,18 +2985,43 @@ if (_sde_buffer != NULL) { k->set_source_debug_extension(_sde_buffer, _sde_length); } - k->set_inner_classes(_inner_classes); } -AnnotationArray* ClassFileParser::assemble_annotations(ClassLoaderData* loader_data, - u1* runtime_visible_annotations, +// Transfer ownership of metadata allocated to the InstanceKlass. +void ClassFileParser::apply_parsed_class_metadata( + instanceKlassHandle this_klass, + int java_fields_count, TRAPS) { + // Assign annotations if needed + if (_annotations != NULL || _type_annotations != NULL || + _fields_annotations != NULL || _fields_type_annotations != NULL) { + Annotations* annotations = Annotations::allocate(_loader_data, CHECK); + annotations->set_class_annotations(_annotations); + annotations->set_class_type_annotations(_type_annotations); + annotations->set_fields_annotations(_fields_annotations); + annotations->set_fields_type_annotations(_fields_type_annotations); + this_klass->set_annotations(annotations); + } + + _cp->set_pool_holder(this_klass()); + this_klass->set_constants(_cp); + this_klass->set_fields(_fields, java_fields_count); + this_klass->set_methods(_methods); + this_klass->set_inner_classes(_inner_classes); + this_klass->set_local_interfaces(_local_interfaces); + this_klass->set_transitive_interfaces(_transitive_interfaces); + + // Clear out these fields so they don't get deallocated by the destructor + clear_class_metadata(); +} + +AnnotationArray* ClassFileParser::assemble_annotations(u1* runtime_visible_annotations, int runtime_visible_annotations_length, u1* runtime_invisible_annotations, int runtime_invisible_annotations_length, TRAPS) { AnnotationArray* annotations = NULL; if (runtime_visible_annotations != NULL || runtime_invisible_annotations != NULL) { - annotations = MetadataFactory::new_array(loader_data, + annotations = MetadataFactory::new_array(_loader_data, runtime_visible_annotations_length + runtime_invisible_annotations_length, CHECK_(annotations)); @@ -3144,6 +3069,581 @@ #endif // ndef PRODUCT +instanceKlassHandle ClassFileParser::parse_super_class(int super_class_index, + TRAPS) { + instanceKlassHandle super_klass; + if (super_class_index == 0) { + check_property(_class_name == vmSymbols::java_lang_Object(), + "Invalid superclass index %u in class file %s", + super_class_index, + CHECK_NULL); + } else { + check_property(valid_klass_reference_at(super_class_index), + "Invalid superclass index %u in class file %s", + super_class_index, + CHECK_NULL); + // The class name should be legal because it is checked when parsing constant pool. + // However, make sure it is not an array type. + bool is_array = false; + if (_cp->tag_at(super_class_index).is_klass()) { + super_klass = instanceKlassHandle(THREAD, _cp->resolved_klass_at(super_class_index)); + if (_need_verify) + is_array = super_klass->oop_is_array(); + } else if (_need_verify) { + is_array = (_cp->unresolved_klass_at(super_class_index)->byte_at(0) == JVM_SIGNATURE_ARRAY); + } + if (_need_verify) { + guarantee_property(!is_array, + "Bad superclass name in class file %s", CHECK_NULL); + } + } + return super_klass; +} + + +// Values needed for oopmap and InstanceKlass creation +class FieldLayoutInfo : public StackObj { + public: + int* nonstatic_oop_offsets; + unsigned int* nonstatic_oop_counts; + unsigned int nonstatic_oop_map_count; + unsigned int total_oop_map_count; + int instance_size; + int nonstatic_field_size; + int static_field_size; + bool has_nonstatic_fields; +}; + +// Layout fields and fill in FieldLayoutInfo. Could use more refactoring! +void ClassFileParser::layout_fields(Handle class_loader, + FieldAllocationCount* fac, + ClassAnnotationCollector* parsed_annotations, + FieldLayoutInfo* info, + TRAPS) { + + // get the padding width from the option + // TODO: Ask VM about specific CPU we are running on + int pad_size = ContendedPaddingWidth; + + // Field size and offset computation + int nonstatic_field_size = _super_klass() == NULL ? 0 : _super_klass()->nonstatic_field_size(); +#ifndef PRODUCT + int orig_nonstatic_field_size = 0; +#endif + int next_static_oop_offset; + int next_static_double_offset; + int next_static_word_offset; + int next_static_short_offset; + int next_static_byte_offset; + int next_nonstatic_oop_offset; + int next_nonstatic_double_offset; + int next_nonstatic_word_offset; + int next_nonstatic_short_offset; + int next_nonstatic_byte_offset; + int next_nonstatic_type_offset; + int first_nonstatic_oop_offset; + int first_nonstatic_field_offset; + int next_nonstatic_field_offset; + int next_nonstatic_padded_offset; + + // Count the contended fields by type. + int nonstatic_contended_count = 0; + FieldAllocationCount fac_contended; + for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) { + FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); + if (fs.is_contended()) { + fac_contended.count[atype]++; + if (!fs.access_flags().is_static()) { + nonstatic_contended_count++; + } + } + } + int contended_count = nonstatic_contended_count; + + + // Calculate the starting byte offsets + next_static_oop_offset = InstanceMirrorKlass::offset_of_static_fields(); + next_static_double_offset = next_static_oop_offset + + ((fac->count[STATIC_OOP]) * heapOopSize); + if ( fac->count[STATIC_DOUBLE] && + (Universe::field_type_should_be_aligned(T_DOUBLE) || + Universe::field_type_should_be_aligned(T_LONG)) ) { + next_static_double_offset = align_size_up(next_static_double_offset, BytesPerLong); + } + + next_static_word_offset = next_static_double_offset + + ((fac->count[STATIC_DOUBLE]) * BytesPerLong); + next_static_short_offset = next_static_word_offset + + ((fac->count[STATIC_WORD]) * BytesPerInt); + next_static_byte_offset = next_static_short_offset + + ((fac->count[STATIC_SHORT]) * BytesPerShort); + + first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() + + nonstatic_field_size * heapOopSize; + + // class is contended, pad before all the fields + if (parsed_annotations->is_contended()) { + first_nonstatic_field_offset += pad_size; + } + + next_nonstatic_field_offset = first_nonstatic_field_offset; + + unsigned int nonstatic_double_count = fac->count[NONSTATIC_DOUBLE] - fac_contended.count[NONSTATIC_DOUBLE]; + unsigned int nonstatic_word_count = fac->count[NONSTATIC_WORD] - fac_contended.count[NONSTATIC_WORD]; + unsigned int nonstatic_short_count = fac->count[NONSTATIC_SHORT] - fac_contended.count[NONSTATIC_SHORT]; + unsigned int nonstatic_byte_count = fac->count[NONSTATIC_BYTE] - fac_contended.count[NONSTATIC_BYTE]; + unsigned int nonstatic_oop_count = fac->count[NONSTATIC_OOP] - fac_contended.count[NONSTATIC_OOP]; + + bool super_has_nonstatic_fields = + (_super_klass() != NULL && _super_klass->has_nonstatic_fields()); + bool has_nonstatic_fields = super_has_nonstatic_fields || + ((nonstatic_double_count + nonstatic_word_count + + nonstatic_short_count + nonstatic_byte_count + + nonstatic_oop_count) != 0); + + + // Prepare list of oops for oop map generation. + int* nonstatic_oop_offsets; + unsigned int* nonstatic_oop_counts; + unsigned int nonstatic_oop_map_count = 0; + + nonstatic_oop_offsets = NEW_RESOURCE_ARRAY_IN_THREAD( + THREAD, int, nonstatic_oop_count + 1); + nonstatic_oop_counts = NEW_RESOURCE_ARRAY_IN_THREAD( + THREAD, unsigned int, nonstatic_oop_count + 1); + + first_nonstatic_oop_offset = 0; // will be set for first oop field + +#ifndef PRODUCT + if( PrintCompactFieldsSavings ) { + next_nonstatic_double_offset = next_nonstatic_field_offset + + (nonstatic_oop_count * heapOopSize); + if ( nonstatic_double_count > 0 ) { + next_nonstatic_double_offset = align_size_up(next_nonstatic_double_offset, BytesPerLong); + } + next_nonstatic_word_offset = next_nonstatic_double_offset + + (nonstatic_double_count * BytesPerLong); + next_nonstatic_short_offset = next_nonstatic_word_offset + + (nonstatic_word_count * BytesPerInt); + next_nonstatic_byte_offset = next_nonstatic_short_offset + + (nonstatic_short_count * BytesPerShort); + next_nonstatic_type_offset = align_size_up((next_nonstatic_byte_offset + + nonstatic_byte_count ), heapOopSize ); + orig_nonstatic_field_size = nonstatic_field_size + + ((next_nonstatic_type_offset - first_nonstatic_field_offset)/heapOopSize); + } +#endif + bool compact_fields = CompactFields; + int allocation_style = FieldsAllocationStyle; + if( allocation_style < 0 || allocation_style > 2 ) { // Out of range? + assert(false, "0 <= FieldsAllocationStyle <= 2"); + allocation_style = 1; // Optimistic + } + + // The next classes have predefined hard-coded fields offsets + // (see in JavaClasses::compute_hard_coded_offsets()). + // Use default fields allocation order for them. + if( (allocation_style != 0 || compact_fields ) && class_loader.is_null() && + (_class_name == vmSymbols::java_lang_AssertionStatusDirectives() || + _class_name == vmSymbols::java_lang_Class() || + _class_name == vmSymbols::java_lang_ClassLoader() || + _class_name == vmSymbols::java_lang_ref_Reference() || + _class_name == vmSymbols::java_lang_ref_SoftReference() || + _class_name == vmSymbols::java_lang_StackTraceElement() || + _class_name == vmSymbols::java_lang_String() || + _class_name == vmSymbols::java_lang_Throwable() || + _class_name == vmSymbols::java_lang_Boolean() || + _class_name == vmSymbols::java_lang_Character() || + _class_name == vmSymbols::java_lang_Float() || + _class_name == vmSymbols::java_lang_Double() || + _class_name == vmSymbols::java_lang_Byte() || + _class_name == vmSymbols::java_lang_Short() || + _class_name == vmSymbols::java_lang_Integer() || + _class_name == vmSymbols::java_lang_Long())) { + allocation_style = 0; // Allocate oops first + compact_fields = false; // Don't compact fields + } + + if( allocation_style == 0 ) { + // Fields order: oops, longs/doubles, ints, shorts/chars, bytes, padded fields + next_nonstatic_oop_offset = next_nonstatic_field_offset; + next_nonstatic_double_offset = next_nonstatic_oop_offset + + (nonstatic_oop_count * heapOopSize); + } else if( allocation_style == 1 ) { + // Fields order: longs/doubles, ints, shorts/chars, bytes, oops, padded fields + next_nonstatic_double_offset = next_nonstatic_field_offset; + } else if( allocation_style == 2 ) { + // Fields allocation: oops fields in super and sub classes are together. + if( nonstatic_field_size > 0 && _super_klass() != NULL && + _super_klass->nonstatic_oop_map_size() > 0 ) { + unsigned int map_count = _super_klass->nonstatic_oop_map_count(); + OopMapBlock* first_map = _super_klass->start_of_nonstatic_oop_maps(); + OopMapBlock* last_map = first_map + map_count - 1; + int next_offset = last_map->offset() + (last_map->count() * heapOopSize); + if (next_offset == next_nonstatic_field_offset) { + allocation_style = 0; // allocate oops first + next_nonstatic_oop_offset = next_nonstatic_field_offset; + next_nonstatic_double_offset = next_nonstatic_oop_offset + + (nonstatic_oop_count * heapOopSize); + } + } + if( allocation_style == 2 ) { + allocation_style = 1; // allocate oops last + next_nonstatic_double_offset = next_nonstatic_field_offset; + } + } else { + ShouldNotReachHere(); + } + + int nonstatic_oop_space_count = 0; + int nonstatic_word_space_count = 0; + int nonstatic_short_space_count = 0; + int nonstatic_byte_space_count = 0; + int nonstatic_oop_space_offset; + int nonstatic_word_space_offset; + int nonstatic_short_space_offset; + int nonstatic_byte_space_offset; + + if( nonstatic_double_count > 0 ) { + int offset = next_nonstatic_double_offset; + next_nonstatic_double_offset = align_size_up(offset, BytesPerLong); + if( compact_fields && offset != next_nonstatic_double_offset ) { + // Allocate available fields into the gap before double field. + int length = next_nonstatic_double_offset - offset; + assert(length == BytesPerInt, ""); + nonstatic_word_space_offset = offset; + if( nonstatic_word_count > 0 ) { + nonstatic_word_count -= 1; + nonstatic_word_space_count = 1; // Only one will fit + length -= BytesPerInt; + offset += BytesPerInt; + } + nonstatic_short_space_offset = offset; + while( length >= BytesPerShort && nonstatic_short_count > 0 ) { + nonstatic_short_count -= 1; + nonstatic_short_space_count += 1; + length -= BytesPerShort; + offset += BytesPerShort; + } + nonstatic_byte_space_offset = offset; + while( length > 0 && nonstatic_byte_count > 0 ) { + nonstatic_byte_count -= 1; + nonstatic_byte_space_count += 1; + length -= 1; + } + // Allocate oop field in the gap if there are no other fields for that. + nonstatic_oop_space_offset = offset; + if( length >= heapOopSize && nonstatic_oop_count > 0 && + allocation_style != 0 ) { // when oop fields not first + nonstatic_oop_count -= 1; + nonstatic_oop_space_count = 1; // Only one will fit + length -= heapOopSize; + offset += heapOopSize; + } + } + } + + next_nonstatic_word_offset = next_nonstatic_double_offset + + (nonstatic_double_count * BytesPerLong); + next_nonstatic_short_offset = next_nonstatic_word_offset + + (nonstatic_word_count * BytesPerInt); + next_nonstatic_byte_offset = next_nonstatic_short_offset + + (nonstatic_short_count * BytesPerShort); + next_nonstatic_padded_offset = next_nonstatic_byte_offset + + nonstatic_byte_count; + + // let oops jump before padding with this allocation style + if( allocation_style == 1 ) { + next_nonstatic_oop_offset = next_nonstatic_padded_offset; + if( nonstatic_oop_count > 0 ) { + next_nonstatic_oop_offset = align_size_up(next_nonstatic_oop_offset, heapOopSize); + } + next_nonstatic_padded_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize); + } + + // Iterate over fields again and compute correct offsets. + // The field allocation type was temporarily stored in the offset slot. + // oop fields are located before non-oop fields (static and non-static). + for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) { + + // skip already laid out fields + if (fs.is_offset_set()) continue; + + // contended instance fields are handled below + if (fs.is_contended() && !fs.access_flags().is_static()) continue; + + int real_offset; + FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); + + // pack the rest of the fields + switch (atype) { + case STATIC_OOP: + real_offset = next_static_oop_offset; + next_static_oop_offset += heapOopSize; + break; + case STATIC_BYTE: + real_offset = next_static_byte_offset; + next_static_byte_offset += 1; + break; + case STATIC_SHORT: + real_offset = next_static_short_offset; + next_static_short_offset += BytesPerShort; + break; + case STATIC_WORD: + real_offset = next_static_word_offset; + next_static_word_offset += BytesPerInt; + break; + case STATIC_DOUBLE: + real_offset = next_static_double_offset; + next_static_double_offset += BytesPerLong; + break; + case NONSTATIC_OOP: + if( nonstatic_oop_space_count > 0 ) { + real_offset = nonstatic_oop_space_offset; + nonstatic_oop_space_offset += heapOopSize; + nonstatic_oop_space_count -= 1; + } else { + real_offset = next_nonstatic_oop_offset; + next_nonstatic_oop_offset += heapOopSize; + } + // Update oop maps + if( nonstatic_oop_map_count > 0 && + nonstatic_oop_offsets[nonstatic_oop_map_count - 1] == + real_offset - + int(nonstatic_oop_counts[nonstatic_oop_map_count - 1]) * + heapOopSize ) { + // Extend current oop map + nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1; + } else { + // Create new oop map + nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; + nonstatic_oop_counts [nonstatic_oop_map_count] = 1; + nonstatic_oop_map_count += 1; + if( first_nonstatic_oop_offset == 0 ) { // Undefined + first_nonstatic_oop_offset = real_offset; + } + } + break; + case NONSTATIC_BYTE: + if( nonstatic_byte_space_count > 0 ) { + real_offset = nonstatic_byte_space_offset; + nonstatic_byte_space_offset += 1; + nonstatic_byte_space_count -= 1; + } else { + real_offset = next_nonstatic_byte_offset; + next_nonstatic_byte_offset += 1; + } + break; + case NONSTATIC_SHORT: + if( nonstatic_short_space_count > 0 ) { + real_offset = nonstatic_short_space_offset; + nonstatic_short_space_offset += BytesPerShort; + nonstatic_short_space_count -= 1; + } else { + real_offset = next_nonstatic_short_offset; + next_nonstatic_short_offset += BytesPerShort; + } + break; + case NONSTATIC_WORD: + if( nonstatic_word_space_count > 0 ) { + real_offset = nonstatic_word_space_offset; + nonstatic_word_space_offset += BytesPerInt; + nonstatic_word_space_count -= 1; + } else { + real_offset = next_nonstatic_word_offset; + next_nonstatic_word_offset += BytesPerInt; + } + break; + case NONSTATIC_DOUBLE: + real_offset = next_nonstatic_double_offset; + next_nonstatic_double_offset += BytesPerLong; + break; + default: + ShouldNotReachHere(); + } + fs.set_offset(real_offset); + } + + + // Handle the contended cases. + // + // Each contended field should not intersect the cache line with another contended field. + // In the absence of alignment information, we end up with pessimistically separating + // the fields with full-width padding. + // + // Additionally, this should not break alignment for the fields, so we round the alignment up + // for each field. + if (contended_count > 0) { + + // if there is at least one contended field, we need to have pre-padding for them + if (nonstatic_contended_count > 0) { + next_nonstatic_padded_offset += pad_size; + } + + // collect all contended groups + BitMap bm(_cp->size()); + for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) { + // skip already laid out fields + if (fs.is_offset_set()) continue; + + if (fs.is_contended()) { + bm.set_bit(fs.contended_group()); + } + } + + int current_group = -1; + while ((current_group = (int)bm.get_next_one_offset(current_group + 1)) != (int)bm.size()) { + + for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) { + + // skip already laid out fields + if (fs.is_offset_set()) continue; + + // skip non-contended fields and fields from different group + if (!fs.is_contended() || (fs.contended_group() != current_group)) continue; + + // handle statics below + if (fs.access_flags().is_static()) continue; + + int real_offset; + FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); + + switch (atype) { + case NONSTATIC_BYTE: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, 1); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += 1; + break; + + case NONSTATIC_SHORT: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerShort); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += BytesPerShort; + break; + + case NONSTATIC_WORD: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerInt); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += BytesPerInt; + break; + + case NONSTATIC_DOUBLE: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerLong); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += BytesPerLong; + break; + + case NONSTATIC_OOP: + next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, heapOopSize); + real_offset = next_nonstatic_padded_offset; + next_nonstatic_padded_offset += heapOopSize; + + // Create new oop map + nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; + nonstatic_oop_counts [nonstatic_oop_map_count] = 1; + nonstatic_oop_map_count += 1; + if( first_nonstatic_oop_offset == 0 ) { // Undefined + first_nonstatic_oop_offset = real_offset; + } + break; + + default: + ShouldNotReachHere(); + } + + if (fs.contended_group() == 0) { + // Contended group defines the equivalence class over the fields: + // the fields within the same contended group are not inter-padded. + // The only exception is default group, which does not incur the + // equivalence, and so requires intra-padding. + next_nonstatic_padded_offset += pad_size; + } + + fs.set_offset(real_offset); + } // for + + // Start laying out the next group. + // Note that this will effectively pad the last group in the back; + // this is expected to alleviate memory contention effects for + // subclass fields and/or adjacent object. + // If this was the default group, the padding is already in place. + if (current_group != 0) { + next_nonstatic_padded_offset += pad_size; + } + } + + // handle static fields + } + + // Size of instances + int notaligned_offset = next_nonstatic_padded_offset; + + // Entire class is contended, pad in the back. + // This helps to alleviate memory contention effects for subclass fields + // and/or adjacent object. + if (parsed_annotations->is_contended()) { + notaligned_offset += pad_size; + } + + int next_static_type_offset = align_size_up(next_static_byte_offset, wordSize); + int static_field_size = (next_static_type_offset - + InstanceMirrorKlass::offset_of_static_fields()) / wordSize; + + next_nonstatic_type_offset = align_size_up(notaligned_offset, heapOopSize ); + nonstatic_field_size = nonstatic_field_size + ((next_nonstatic_type_offset + - first_nonstatic_field_offset)/heapOopSize); + + next_nonstatic_type_offset = align_size_up(notaligned_offset, wordSize ); + int instance_size = align_object_size(next_nonstatic_type_offset / wordSize); + + assert(instance_size == align_object_size(align_size_up( + (instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize + ((parsed_annotations->is_contended()) ? pad_size : 0)), + wordSize) / wordSize), "consistent layout helper value"); + + // Number of non-static oop map blocks allocated at end of klass. + const unsigned int total_oop_map_count = + compute_oop_map_count(_super_klass, nonstatic_oop_map_count, + first_nonstatic_oop_offset); + +#ifndef PRODUCT + if( PrintCompactFieldsSavings ) { + ResourceMark rm; + if( nonstatic_field_size < orig_nonstatic_field_size ) { + tty->print("[Saved %d of %d bytes in %s]\n", + (orig_nonstatic_field_size - nonstatic_field_size)*heapOopSize, + orig_nonstatic_field_size*heapOopSize, + _class_name); + } else if( nonstatic_field_size > orig_nonstatic_field_size ) { + tty->print("[Wasted %d over %d bytes in %s]\n", + (nonstatic_field_size - orig_nonstatic_field_size)*heapOopSize, + orig_nonstatic_field_size*heapOopSize, + _class_name); + } + } + + if (PrintFieldLayout) { + print_field_layout(_class_name, + _fields, + _cp, + instance_size, + first_nonstatic_field_offset, + next_nonstatic_field_offset, + next_static_type_offset); + } + +#endif + // Pass back information needed for InstanceKlass creation + info->nonstatic_oop_offsets = nonstatic_oop_offsets; + info->nonstatic_oop_counts = nonstatic_oop_counts; + info->nonstatic_oop_map_count = nonstatic_oop_map_count; + info->total_oop_map_count = total_oop_map_count; + info->instance_size = instance_size; + info->static_field_size = static_field_size; + info->nonstatic_field_size = nonstatic_field_size; + info->has_nonstatic_fields = has_nonstatic_fields; +} + + instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, ClassLoaderData* loader_data, Handle protection_domain, @@ -3176,7 +3676,7 @@ jt->get_thread_stat()->perf_timers_addr(), PerfClassTraceTime::PARSE_CLASS); - init_parsed_class_attributes(); + init_parsed_class_attributes(loader_data); if (JvmtiExport::should_post_class_file_load_hook()) { // Get the cached class file bytes (if any) from the class that @@ -3271,8 +3771,7 @@ _relax_verify = Verifier::relax_verify_for(class_loader()); // Constant pool - constantPoolHandle cp = parse_constant_pool(loader_data, CHECK_(nullHandle)); - ConstantPoolCleaner error_handler(cp); // set constant pool to be cleaned up. + constantPoolHandle cp = parse_constant_pool(CHECK_(nullHandle)); int cp_size = cp->length(); @@ -3290,7 +3789,6 @@ access_flags.set_flags(flags); // This class and superclass - instanceKlassHandle super_klass; u2 this_class_index = cfs->get_u2_fast(); check_property( valid_cp_range(this_class_index, cp_size) && @@ -3345,59 +3843,27 @@ } u2 super_class_index = cfs->get_u2_fast(); - if (super_class_index == 0) { - check_property(class_name == vmSymbols::java_lang_Object(), - "Invalid superclass index %u in class file %s", - super_class_index, - CHECK_(nullHandle)); - } else { - check_property(valid_cp_range(super_class_index, cp_size) && - is_klass_reference(cp, super_class_index), - "Invalid superclass index %u in class file %s", - super_class_index, - CHECK_(nullHandle)); - // The class name should be legal because it is checked when parsing constant pool. - // However, make sure it is not an array type. - bool is_array = false; - if (cp->tag_at(super_class_index).is_klass()) { - super_klass = instanceKlassHandle(THREAD, cp->resolved_klass_at(super_class_index)); - if (_need_verify) - is_array = super_klass->oop_is_array(); - } else if (_need_verify) { - is_array = (cp->unresolved_klass_at(super_class_index)->byte_at(0) == JVM_SIGNATURE_ARRAY); - } - if (_need_verify) { - guarantee_property(!is_array, - "Bad superclass name in class file %s", CHECK_(nullHandle)); - } - } + instanceKlassHandle super_klass = parse_super_class(super_class_index, + CHECK_NULL); // Interfaces u2 itfs_len = cfs->get_u2_fast(); - Array* local_interfaces; - if (itfs_len == 0) { - local_interfaces = Universe::the_empty_klass_array(); - } else { - local_interfaces = parse_interfaces( - cp, itfs_len, loader_data, protection_domain, _class_name, - &has_default_methods, CHECK_(nullHandle)); - } + Array* local_interfaces = + parse_interfaces(itfs_len, protection_domain, _class_name, + &has_default_methods, CHECK_(nullHandle)); u2 java_fields_count = 0; // Fields (offsets are filled in later) FieldAllocationCount fac; - Array* fields_annotations = NULL; - Array* fields_type_annotations = NULL; - Array* fields = parse_fields(loader_data, class_name, cp, access_flags.is_interface(), &fac, &fields_annotations, - &fields_type_annotations, - &java_fields_count, - CHECK_(nullHandle)); + Array* fields = parse_fields(class_name, + access_flags.is_interface(), + &fac, &java_fields_count, + CHECK_(nullHandle)); // Methods bool has_final_method = false; AccessFlags promoted_flags; promoted_flags.set_flags(0); - Array* methods = parse_methods(loader_data, - cp, access_flags.is_interface(), + Array* methods = parse_methods(access_flags.is_interface(), &promoted_flags, &has_final_method, &has_default_methods, @@ -3405,7 +3871,7 @@ // Additional attributes ClassAnnotationCollector parsed_annotations; - parse_classfile_attributes(loader_data, cp, &parsed_annotations, CHECK_(nullHandle)); + parse_classfile_attributes(&parsed_annotations, CHECK_(nullHandle)); // Make sure this is the end of class file stream guarantee_property(cfs->at_eos(), "Extra bytes at the end of class file %s", CHECK_(nullHandle)); @@ -3452,13 +3918,15 @@ } } + // save super klass for error handling. + _super_klass = super_klass; + // Compute the transitive list of all unique interfaces implemented by this class - Array* transitive_interfaces = compute_transitive_interfaces(loader_data, super_klass, local_interfaces, CHECK_(nullHandle)); + _transitive_interfaces = + compute_transitive_interfaces(super_klass, local_interfaces, CHECK_(nullHandle)); // sort methods - Array* method_ordering = sort_methods(loader_data, - methods, - CHECK_(nullHandle)); + intArray* method_ordering = sort_methods(methods); // promote flags from parse_methods() to the klass' flags access_flags.add_promoted_flags(promoted_flags.as_int()); @@ -3476,587 +3944,14 @@ CHECK_(nullHandle)); // Size of Java itable (in words) - itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(transitive_interfaces); - - // get the padding width from the option - // TODO: Ask VM about specific CPU we are running on - int pad_size = ContendedPaddingWidth; - - // Field size and offset computation - int nonstatic_field_size = super_klass() == NULL ? 0 : super_klass->nonstatic_field_size(); -#ifndef PRODUCT - int orig_nonstatic_field_size = 0; -#endif - int next_static_oop_offset; - int next_static_double_offset; - int next_static_word_offset; - int next_static_short_offset; - int next_static_byte_offset; - int next_static_padded_offset; - int next_nonstatic_oop_offset; - int next_nonstatic_double_offset; - int next_nonstatic_word_offset; - int next_nonstatic_short_offset; - int next_nonstatic_byte_offset; - int next_nonstatic_type_offset; - int first_nonstatic_oop_offset; - int first_nonstatic_field_offset; - int next_nonstatic_field_offset; - int next_nonstatic_padded_offset; - - // Count the contended fields by type. - int static_contended_count = 0; - int nonstatic_contended_count = 0; - FieldAllocationCount fac_contended; - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); - if (fs.is_contended()) { - fac_contended.count[atype]++; - if (fs.access_flags().is_static()) { - static_contended_count++; - } else { - nonstatic_contended_count++; - } - } - } - int contended_count = static_contended_count + nonstatic_contended_count; - - - // Calculate the starting byte offsets - next_static_oop_offset = InstanceMirrorKlass::offset_of_static_fields(); - - // class is contended, pad before all the fields - if (parsed_annotations.is_contended()) { - next_static_oop_offset += pad_size; - } - - next_static_double_offset = next_static_oop_offset + - ((fac.count[STATIC_OOP] - fac_contended.count[STATIC_OOP]) * heapOopSize); - if ( fac.count[STATIC_DOUBLE] && - (Universe::field_type_should_be_aligned(T_DOUBLE) || - Universe::field_type_should_be_aligned(T_LONG)) ) { - next_static_double_offset = align_size_up(next_static_double_offset, BytesPerLong); - } - - next_static_word_offset = next_static_double_offset + - ((fac.count[STATIC_DOUBLE] - fac_contended.count[STATIC_DOUBLE]) * BytesPerLong); - next_static_short_offset = next_static_word_offset + - ((fac.count[STATIC_WORD] - fac_contended.count[STATIC_WORD]) * BytesPerInt); - next_static_byte_offset = next_static_short_offset + - ((fac.count[STATIC_SHORT] - fac_contended.count[STATIC_SHORT]) * BytesPerShort); - next_static_padded_offset = next_static_byte_offset + - ((fac.count[STATIC_BYTE] - fac_contended.count[STATIC_BYTE]) * 1); - - first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() + - nonstatic_field_size * heapOopSize; - - // class is contended, pad before all the fields - if (parsed_annotations.is_contended()) { - first_nonstatic_field_offset += pad_size; - } - - next_nonstatic_field_offset = first_nonstatic_field_offset; - - unsigned int nonstatic_double_count = fac.count[NONSTATIC_DOUBLE] - fac_contended.count[NONSTATIC_DOUBLE]; - unsigned int nonstatic_word_count = fac.count[NONSTATIC_WORD] - fac_contended.count[NONSTATIC_WORD]; - unsigned int nonstatic_short_count = fac.count[NONSTATIC_SHORT] - fac_contended.count[NONSTATIC_SHORT]; - unsigned int nonstatic_byte_count = fac.count[NONSTATIC_BYTE] - fac_contended.count[NONSTATIC_BYTE]; - unsigned int nonstatic_oop_count = fac.count[NONSTATIC_OOP] - fac_contended.count[NONSTATIC_OOP]; - - bool super_has_nonstatic_fields = - (super_klass() != NULL && super_klass->has_nonstatic_fields()); - bool has_nonstatic_fields = super_has_nonstatic_fields || - ((nonstatic_double_count + nonstatic_word_count + - nonstatic_short_count + nonstatic_byte_count + - nonstatic_oop_count) != 0); - - - // Prepare list of oops for oop map generation. - int* nonstatic_oop_offsets; - unsigned int* nonstatic_oop_counts; - unsigned int nonstatic_oop_map_count = 0; - - nonstatic_oop_offsets = NEW_RESOURCE_ARRAY_IN_THREAD( - THREAD, int, nonstatic_oop_count + 1); - nonstatic_oop_counts = NEW_RESOURCE_ARRAY_IN_THREAD( - THREAD, unsigned int, nonstatic_oop_count + 1); - - first_nonstatic_oop_offset = 0; // will be set for first oop field - -#ifndef PRODUCT - if( PrintCompactFieldsSavings ) { - next_nonstatic_double_offset = next_nonstatic_field_offset + - (nonstatic_oop_count * heapOopSize); - if ( nonstatic_double_count > 0 ) { - next_nonstatic_double_offset = align_size_up(next_nonstatic_double_offset, BytesPerLong); - } - next_nonstatic_word_offset = next_nonstatic_double_offset + - (nonstatic_double_count * BytesPerLong); - next_nonstatic_short_offset = next_nonstatic_word_offset + - (nonstatic_word_count * BytesPerInt); - next_nonstatic_byte_offset = next_nonstatic_short_offset + - (nonstatic_short_count * BytesPerShort); - next_nonstatic_type_offset = align_size_up((next_nonstatic_byte_offset + - nonstatic_byte_count ), heapOopSize ); - orig_nonstatic_field_size = nonstatic_field_size + - ((next_nonstatic_type_offset - first_nonstatic_field_offset)/heapOopSize); - } -#endif - bool compact_fields = CompactFields; - int allocation_style = FieldsAllocationStyle; - if( allocation_style < 0 || allocation_style > 2 ) { // Out of range? - assert(false, "0 <= FieldsAllocationStyle <= 2"); - allocation_style = 1; // Optimistic - } - - // The next classes have predefined hard-coded fields offsets - // (see in JavaClasses::compute_hard_coded_offsets()). - // Use default fields allocation order for them. - if( (allocation_style != 0 || compact_fields ) && class_loader.is_null() && - (class_name == vmSymbols::java_lang_AssertionStatusDirectives() || - class_name == vmSymbols::java_lang_Class() || - class_name == vmSymbols::java_lang_ClassLoader() || - class_name == vmSymbols::java_lang_ref_Reference() || - class_name == vmSymbols::java_lang_ref_SoftReference() || - class_name == vmSymbols::java_lang_StackTraceElement() || - class_name == vmSymbols::java_lang_String() || - class_name == vmSymbols::java_lang_Throwable() || - class_name == vmSymbols::java_lang_Boolean() || - class_name == vmSymbols::java_lang_Character() || - class_name == vmSymbols::java_lang_Float() || - class_name == vmSymbols::java_lang_Double() || - class_name == vmSymbols::java_lang_Byte() || - class_name == vmSymbols::java_lang_Short() || - class_name == vmSymbols::java_lang_Integer() || - class_name == vmSymbols::java_lang_Long())) { - allocation_style = 0; // Allocate oops first - compact_fields = false; // Don't compact fields - } - - if( allocation_style == 0 ) { - // Fields order: oops, longs/doubles, ints, shorts/chars, bytes, padded fields - next_nonstatic_oop_offset = next_nonstatic_field_offset; - next_nonstatic_double_offset = next_nonstatic_oop_offset + - (nonstatic_oop_count * heapOopSize); - } else if( allocation_style == 1 ) { - // Fields order: longs/doubles, ints, shorts/chars, bytes, oops, padded fields - next_nonstatic_double_offset = next_nonstatic_field_offset; - } else if( allocation_style == 2 ) { - // Fields allocation: oops fields in super and sub classes are together. - if( nonstatic_field_size > 0 && super_klass() != NULL && - super_klass->nonstatic_oop_map_size() > 0 ) { - int map_count = super_klass->nonstatic_oop_map_count(); - OopMapBlock* first_map = super_klass->start_of_nonstatic_oop_maps(); - OopMapBlock* last_map = first_map + map_count - 1; - int next_offset = last_map->offset() + (last_map->count() * heapOopSize); - if (next_offset == next_nonstatic_field_offset) { - allocation_style = 0; // allocate oops first - next_nonstatic_oop_offset = next_nonstatic_field_offset; - next_nonstatic_double_offset = next_nonstatic_oop_offset + - (nonstatic_oop_count * heapOopSize); - } - } - if( allocation_style == 2 ) { - allocation_style = 1; // allocate oops last - next_nonstatic_double_offset = next_nonstatic_field_offset; - } - } else { - ShouldNotReachHere(); - } - - int nonstatic_oop_space_count = 0; - int nonstatic_word_space_count = 0; - int nonstatic_short_space_count = 0; - int nonstatic_byte_space_count = 0; - int nonstatic_oop_space_offset; - int nonstatic_word_space_offset; - int nonstatic_short_space_offset; - int nonstatic_byte_space_offset; - - if( nonstatic_double_count > 0 ) { - int offset = next_nonstatic_double_offset; - next_nonstatic_double_offset = align_size_up(offset, BytesPerLong); - if( compact_fields && offset != next_nonstatic_double_offset ) { - // Allocate available fields into the gap before double field. - int length = next_nonstatic_double_offset - offset; - assert(length == BytesPerInt, ""); - nonstatic_word_space_offset = offset; - if( nonstatic_word_count > 0 ) { - nonstatic_word_count -= 1; - nonstatic_word_space_count = 1; // Only one will fit - length -= BytesPerInt; - offset += BytesPerInt; - } - nonstatic_short_space_offset = offset; - while( length >= BytesPerShort && nonstatic_short_count > 0 ) { - nonstatic_short_count -= 1; - nonstatic_short_space_count += 1; - length -= BytesPerShort; - offset += BytesPerShort; - } - nonstatic_byte_space_offset = offset; - while( length > 0 && nonstatic_byte_count > 0 ) { - nonstatic_byte_count -= 1; - nonstatic_byte_space_count += 1; - length -= 1; - } - // Allocate oop field in the gap if there are no other fields for that. - nonstatic_oop_space_offset = offset; - if( length >= heapOopSize && nonstatic_oop_count > 0 && - allocation_style != 0 ) { // when oop fields not first - nonstatic_oop_count -= 1; - nonstatic_oop_space_count = 1; // Only one will fit - length -= heapOopSize; - offset += heapOopSize; - } - } - } - - next_nonstatic_word_offset = next_nonstatic_double_offset + - (nonstatic_double_count * BytesPerLong); - next_nonstatic_short_offset = next_nonstatic_word_offset + - (nonstatic_word_count * BytesPerInt); - next_nonstatic_byte_offset = next_nonstatic_short_offset + - (nonstatic_short_count * BytesPerShort); - next_nonstatic_padded_offset = next_nonstatic_byte_offset + - nonstatic_byte_count; - - // let oops jump before padding with this allocation style - if( allocation_style == 1 ) { - next_nonstatic_oop_offset = next_nonstatic_padded_offset; - if( nonstatic_oop_count > 0 ) { - next_nonstatic_oop_offset = align_size_up(next_nonstatic_oop_offset, heapOopSize); - } - next_nonstatic_padded_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize); - } - - // Iterate over fields again and compute correct offsets. - // The field allocation type was temporarily stored in the offset slot. - // oop fields are located before non-oop fields (static and non-static). - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - - // skip already laid out fields - if (fs.is_offset_set()) continue; - - // contended fields are handled below - if (fs.is_contended()) continue; - - int real_offset; - FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); - - // pack the rest of the fields - switch (atype) { - case STATIC_OOP: - real_offset = next_static_oop_offset; - next_static_oop_offset += heapOopSize; - break; - case STATIC_BYTE: - real_offset = next_static_byte_offset; - next_static_byte_offset += 1; - break; - case STATIC_SHORT: - real_offset = next_static_short_offset; - next_static_short_offset += BytesPerShort; - break; - case STATIC_WORD: - real_offset = next_static_word_offset; - next_static_word_offset += BytesPerInt; - break; - case STATIC_DOUBLE: - real_offset = next_static_double_offset; - next_static_double_offset += BytesPerLong; - break; - case NONSTATIC_OOP: - if( nonstatic_oop_space_count > 0 ) { - real_offset = nonstatic_oop_space_offset; - nonstatic_oop_space_offset += heapOopSize; - nonstatic_oop_space_count -= 1; - } else { - real_offset = next_nonstatic_oop_offset; - next_nonstatic_oop_offset += heapOopSize; - } - // Update oop maps - if( nonstatic_oop_map_count > 0 && - nonstatic_oop_offsets[nonstatic_oop_map_count - 1] == - real_offset - - int(nonstatic_oop_counts[nonstatic_oop_map_count - 1]) * - heapOopSize ) { - // Extend current oop map - nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1; - } else { - // Create new oop map - nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; - nonstatic_oop_counts [nonstatic_oop_map_count] = 1; - nonstatic_oop_map_count += 1; - if( first_nonstatic_oop_offset == 0 ) { // Undefined - first_nonstatic_oop_offset = real_offset; - } - } - break; - case NONSTATIC_BYTE: - if( nonstatic_byte_space_count > 0 ) { - real_offset = nonstatic_byte_space_offset; - nonstatic_byte_space_offset += 1; - nonstatic_byte_space_count -= 1; - } else { - real_offset = next_nonstatic_byte_offset; - next_nonstatic_byte_offset += 1; - } - break; - case NONSTATIC_SHORT: - if( nonstatic_short_space_count > 0 ) { - real_offset = nonstatic_short_space_offset; - nonstatic_short_space_offset += BytesPerShort; - nonstatic_short_space_count -= 1; - } else { - real_offset = next_nonstatic_short_offset; - next_nonstatic_short_offset += BytesPerShort; - } - break; - case NONSTATIC_WORD: - if( nonstatic_word_space_count > 0 ) { - real_offset = nonstatic_word_space_offset; - nonstatic_word_space_offset += BytesPerInt; - nonstatic_word_space_count -= 1; - } else { - real_offset = next_nonstatic_word_offset; - next_nonstatic_word_offset += BytesPerInt; - } - break; - case NONSTATIC_DOUBLE: - real_offset = next_nonstatic_double_offset; - next_nonstatic_double_offset += BytesPerLong; - break; - default: - ShouldNotReachHere(); - } - fs.set_offset(real_offset); - } - - - // Handle the contended cases. - // - // Each contended field should not intersect the cache line with another contended field. - // In the absence of alignment information, we end up with pessimistically separating - // the fields with full-width padding. - // - // Additionally, this should not break alignment for the fields, so we round the alignment up - // for each field. - if (contended_count > 0) { - - // if there is at least one contended field, we need to have pre-padding for them - if (nonstatic_contended_count > 0) { - next_nonstatic_padded_offset += pad_size; - } - - // collect all contended groups - BitMap bm(cp->size()); - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - // skip already laid out fields - if (fs.is_offset_set()) continue; - - if (fs.is_contended()) { - bm.set_bit(fs.contended_group()); - } - } - - int current_group = -1; - while ((current_group = (int)bm.get_next_one_offset(current_group + 1)) != (int)bm.size()) { - - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - - // skip already laid out fields - if (fs.is_offset_set()) continue; - - // skip non-contended fields and fields from different group - if (!fs.is_contended() || (fs.contended_group() != current_group)) continue; - - // handle statics below - if (fs.access_flags().is_static()) continue; - - int real_offset; - FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); - - switch (atype) { - case NONSTATIC_BYTE: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, 1); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += 1; - break; - - case NONSTATIC_SHORT: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerShort); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += BytesPerShort; - break; - - case NONSTATIC_WORD: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerInt); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += BytesPerInt; - break; - - case NONSTATIC_DOUBLE: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerLong); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += BytesPerLong; - break; - - case NONSTATIC_OOP: - next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, heapOopSize); - real_offset = next_nonstatic_padded_offset; - next_nonstatic_padded_offset += heapOopSize; - - // Create new oop map - nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; - nonstatic_oop_counts [nonstatic_oop_map_count] = 1; - nonstatic_oop_map_count += 1; - if( first_nonstatic_oop_offset == 0 ) { // Undefined - first_nonstatic_oop_offset = real_offset; - } - break; - - default: - ShouldNotReachHere(); - } - - if (fs.contended_group() == 0) { - // Contended group defines the equivalence class over the fields: - // the fields within the same contended group are not inter-padded. - // The only exception is default group, which does not incur the - // equivalence, and so requires intra-padding. - next_nonstatic_padded_offset += pad_size; - } - - fs.set_offset(real_offset); - } // for - - // Start laying out the next group. - // Note that this will effectively pad the last group in the back; - // this is expected to alleviate memory contention effects for - // subclass fields and/or adjacent object. - // If this was the default group, the padding is already in place. - if (current_group != 0) { - next_nonstatic_padded_offset += pad_size; - } - } - - // handle static fields - - // if there is at least one contended field, we need to have pre-padding for them - if (static_contended_count > 0) { - next_static_padded_offset += pad_size; - } - - current_group = -1; - while ((current_group = (int)bm.get_next_one_offset(current_group + 1)) != (int)bm.size()) { - - for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) { - - // skip already laid out fields - if (fs.is_offset_set()) continue; - - // skip non-contended fields and fields from different group - if (!fs.is_contended() || (fs.contended_group() != current_group)) continue; - - // non-statics already handled above - if (!fs.access_flags().is_static()) continue; - - int real_offset; - FieldAllocationType atype = (FieldAllocationType) fs.allocation_type(); - - switch (atype) { - - case STATIC_BYTE: - next_static_padded_offset = align_size_up(next_static_padded_offset, 1); - real_offset = next_static_padded_offset; - next_static_padded_offset += 1; - break; - - case STATIC_SHORT: - next_static_padded_offset = align_size_up(next_static_padded_offset, BytesPerShort); - real_offset = next_static_padded_offset; - next_static_padded_offset += BytesPerShort; - break; - - case STATIC_WORD: - next_static_padded_offset = align_size_up(next_static_padded_offset, BytesPerInt); - real_offset = next_static_padded_offset; - next_static_padded_offset += BytesPerInt; - break; - - case STATIC_DOUBLE: - next_static_padded_offset = align_size_up(next_static_padded_offset, BytesPerLong); - real_offset = next_static_padded_offset; - next_static_padded_offset += BytesPerLong; - break; - - case STATIC_OOP: - next_static_padded_offset = align_size_up(next_static_padded_offset, heapOopSize); - real_offset = next_static_padded_offset; - next_static_padded_offset += heapOopSize; - break; - - default: - ShouldNotReachHere(); - } - - if (fs.contended_group() == 0) { - // Contended group defines the equivalence class over the fields: - // the fields within the same contended group are not inter-padded. - // The only exception is default group, which does not incur the - // equivalence, and so requires intra-padding. - next_static_padded_offset += pad_size; - } - - fs.set_offset(real_offset); - } // for - - // Start laying out the next group. - // Note that this will effectively pad the last group in the back; - // this is expected to alleviate memory contention effects for - // subclass fields and/or adjacent object. - // If this was the default group, the padding is already in place. - if (current_group != 0) { - next_static_padded_offset += pad_size; - } - - } - - } // handle contended - - // Size of instances - int instance_size; - - int notaligned_offset = next_nonstatic_padded_offset; - - // Entire class is contended, pad in the back. - // This helps to alleviate memory contention effects for subclass fields - // and/or adjacent object. - if (parsed_annotations.is_contended()) { - notaligned_offset += pad_size; - next_static_padded_offset += pad_size; - } - - int next_static_type_offset = align_size_up(next_static_padded_offset, wordSize); - int static_field_size = (next_static_type_offset - - InstanceMirrorKlass::offset_of_static_fields()) / wordSize; - - next_nonstatic_type_offset = align_size_up(notaligned_offset, heapOopSize ); - nonstatic_field_size = nonstatic_field_size + ((next_nonstatic_type_offset - - first_nonstatic_field_offset)/heapOopSize); - - next_nonstatic_type_offset = align_size_up(notaligned_offset, wordSize ); - instance_size = align_object_size(next_nonstatic_type_offset / wordSize); - - assert(instance_size == align_object_size(align_size_up( - (instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize + ((parsed_annotations.is_contended()) ? pad_size : 0)), - wordSize) / wordSize), "consistent layout helper value"); - - // Number of non-static oop map blocks allocated at end of klass. - const unsigned int total_oop_map_count = - compute_oop_map_count(super_klass, nonstatic_oop_map_count, - first_nonstatic_oop_offset); + itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(_transitive_interfaces); + + FieldLayoutInfo info; + layout_fields(class_loader, &fac, &parsed_annotations, &info, CHECK_NULL); + + int total_oop_map_size2 = + InstanceKlass::nonstatic_oop_map_size(info.total_oop_map_count); + // Compute reference type ReferenceType rt; if (super_klass() == NULL) { @@ -4066,53 +3961,42 @@ } // We can now create the basic Klass* for this klass - int total_oop_map_size2 = - InstanceKlass::nonstatic_oop_map_size(total_oop_map_count); - - Klass* ik = InstanceKlass::allocate_instance_klass(loader_data, - vtable_size, - itable_size, - static_field_size, - total_oop_map_size2, - rt, - access_flags, - name, - super_klass(), - !host_klass.is_null(), - CHECK_(nullHandle)); - - // Add all classes to our internal class loader list here, - // including classes in the bootstrap (NULL) class loader. - loader_data->add_class(ik); - - instanceKlassHandle this_klass (THREAD, ik); - - assert(this_klass->static_field_size() == static_field_size, "sanity"); - assert(this_klass->nonstatic_oop_map_count() == total_oop_map_count, + _klass = InstanceKlass::allocate_instance_klass(loader_data, + vtable_size, + itable_size, + info.static_field_size, + total_oop_map_size2, + rt, + access_flags, + name, + super_klass(), + !host_klass.is_null(), + CHECK_(nullHandle)); + instanceKlassHandle this_klass (THREAD, _klass); + + assert(this_klass->static_field_size() == info.static_field_size, "sanity"); + assert(this_klass->nonstatic_oop_map_count() == info.total_oop_map_count, "sanity"); // Fill in information already parsed this_klass->set_should_verify_class(verify); - jint lh = Klass::instance_layout_helper(instance_size, false); + jint lh = Klass::instance_layout_helper(info.instance_size, false); this_klass->set_layout_helper(lh); assert(this_klass->oop_is_instance(), "layout is correct"); - assert(this_klass->size_helper() == instance_size, "correct size_helper"); + assert(this_klass->size_helper() == info.instance_size, "correct size_helper"); // Not yet: supers are done below to support the new subtype-checking fields //this_klass->set_super(super_klass()); this_klass->set_class_loader_data(loader_data); - this_klass->set_nonstatic_field_size(nonstatic_field_size); - this_klass->set_has_nonstatic_fields(has_nonstatic_fields); + this_klass->set_nonstatic_field_size(info.nonstatic_field_size); + this_klass->set_has_nonstatic_fields(info.has_nonstatic_fields); this_klass->set_static_oop_field_count(fac.count[STATIC_OOP]); - cp->set_pool_holder(this_klass()); - error_handler.set_in_error(false); // turn off error handler for cp - this_klass->set_constants(cp()); - this_klass->set_local_interfaces(local_interfaces); - this_klass->set_fields(fields, java_fields_count); - this_klass->set_methods(methods); + + apply_parsed_class_metadata(this_klass, java_fields_count, CHECK_NULL); + if (has_final_method) { this_klass->set_has_final_method(); } - this_klass->set_method_ordering(method_ordering); + this_klass->copy_method_ordering(method_ordering, CHECK_NULL); // The InstanceKlass::_methods_jmethod_ids cache and the // InstanceKlass::_methods_cached_itable_indices cache are // both managed on the assumption that the initial cache @@ -4124,17 +4008,6 @@ if (is_anonymous()) // I am well known to myself cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve - // Assign allocations if needed - if (_annotations != NULL || _type_annotations != NULL || - fields_annotations != NULL || fields_type_annotations != NULL) { - Annotations* annotations = Annotations::allocate(loader_data, CHECK_NULL); - annotations->set_class_annotations(_annotations); - annotations->set_class_type_annotations(_type_annotations); - annotations->set_fields_annotations(fields_annotations); - annotations->set_fields_type_annotations(fields_type_annotations); - this_klass->set_annotations(annotations); - } - this_klass->set_minor_version(minor_version); this_klass->set_major_version(major_version); this_klass->set_has_default_methods(has_default_methods); @@ -4169,8 +4042,6 @@ this_klass->set_has_miranda_methods(); // then set a flag } - this_klass->set_transitive_interfaces(transitive_interfaces); - // Fill in information needed to compute superclasses. this_klass->initialize_supers(super_klass(), CHECK_(nullHandle)); @@ -4179,7 +4050,7 @@ // Compute transitive closure of interfaces this class implements // Do final class setup - fill_oop_maps(this_klass, nonstatic_oop_map_count, nonstatic_oop_offsets, nonstatic_oop_counts); + fill_oop_maps(this_klass, info.nonstatic_oop_map_count, info.nonstatic_oop_offsets, info.nonstatic_oop_counts); // Fill in has_finalizer, has_vanilla_constructor, and layout_helper set_precomputed_flags(this_klass); @@ -4278,35 +4149,6 @@ } } -#ifndef PRODUCT - if( PrintCompactFieldsSavings ) { - ResourceMark rm; - if( nonstatic_field_size < orig_nonstatic_field_size ) { - tty->print("[Saved %d of %d bytes in %s]\n", - (orig_nonstatic_field_size - nonstatic_field_size)*heapOopSize, - orig_nonstatic_field_size*heapOopSize, - this_klass->external_name()); - } else if( nonstatic_field_size > orig_nonstatic_field_size ) { - tty->print("[Wasted %d over %d bytes in %s]\n", - (nonstatic_field_size - orig_nonstatic_field_size)*heapOopSize, - orig_nonstatic_field_size*heapOopSize, - this_klass->external_name()); - } - } -#endif - -#ifndef PRODUCT - if (PrintFieldLayout) { - print_field_layout(name, - fields, - cp, - instance_size, - first_nonstatic_field_offset, - next_nonstatic_field_offset, - next_static_type_offset); - } -#endif - // preserve result across HandleMark preserve_this_klass = this_klass(); } @@ -4316,9 +4158,40 @@ instanceKlassHandle this_klass (THREAD, preserve_this_klass); debug_only(this_klass->verify();) + // Clear class if no error has occurred so destructor doesn't deallocate it + _klass = NULL; return this_klass; } +// Destructor to clean up if there's an error +ClassFileParser::~ClassFileParser() { + MetadataFactory::free_metadata(_loader_data, _cp); + MetadataFactory::free_array(_loader_data, _fields); + + // Free methods + InstanceKlass::deallocate_methods(_loader_data, _methods); + + // beware of the Universe::empty_blah_array!! + if (_inner_classes != Universe::the_empty_short_array()) { + MetadataFactory::free_array(_loader_data, _inner_classes); + } + + // Free interfaces + InstanceKlass::deallocate_interfaces(_loader_data, _super_klass(), + _local_interfaces, _transitive_interfaces); + + MetadataFactory::free_array(_loader_data, _annotations); + MetadataFactory::free_array(_loader_data, _type_annotations); + Annotations::free_contents(_loader_data, _fields_annotations); + Annotations::free_contents(_loader_data, _fields_type_annotations); + + clear_class_metadata(); + + // deallocate the klass if already created. + MetadataFactory::free_metadata(_loader_data, _klass); + _klass = NULL; +} + void ClassFileParser::print_field_layout(Symbol* name, Array* fields, constantPoolHandle cp, @@ -4510,7 +4383,7 @@ } } -// utility method for appending and array with check for duplicates +// utility methods for appending an array with check for duplicates void append_interfaces(GrowableArray* result, Array* ifs) { // iterate over new interfaces @@ -4522,8 +4395,9 @@ } } - -Array* ClassFileParser::compute_transitive_interfaces(ClassLoaderData* loader_data, instanceKlassHandle super, Array* local_ifs, TRAPS) { +Array* ClassFileParser::compute_transitive_interfaces( + instanceKlassHandle super, + Array* local_ifs, TRAPS) { // Compute maximum size for transitive interfaces int max_transitive_size = 0; int super_size = 0; @@ -4570,7 +4444,7 @@ // length will be less than the max_transitive_size if duplicates were removed int length = result->length(); assert(length <= max_transitive_size, "just checking"); - Array* new_result = MetadataFactory::new_array(loader_data, length, CHECK_NULL); + Array* new_result = MetadataFactory::new_array(_loader_data, length, CHECK_NULL); for (int i = 0; i < length; i++) { Klass* e = result->at(i); assert(e != NULL, "just checking"); @@ -4580,7 +4454,6 @@ } } - void ClassFileParser::check_super_class_access(instanceKlassHandle this_klass, TRAPS) { Klass* super = this_klass->super(); if ((super != NULL) && diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/classfile/classFileParser.hpp --- a/src/share/vm/classfile/classFileParser.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/classfile/classFileParser.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -34,6 +34,7 @@ #include "classfile/symbolTable.hpp" class FieldAllocationCount; +class FieldLayoutInfo; // Parser for for .class files @@ -47,6 +48,7 @@ u2 _major_version; u2 _minor_version; Symbol* _class_name; + ClassLoaderData* _loader_data; KlassHandle _host_klass; GrowableArray* _cp_patches; // overrides for CP entries @@ -58,39 +60,66 @@ // class attributes parsed before the instance klass is created: bool _synthetic_flag; + int _sde_length; + char* _sde_buffer; Symbol* _sourcefile; Symbol* _generic_signature; - char* _sde_buffer; - int _sde_length; - Array* _inner_classes; + + // Metadata created before the instance klass is created. Must be deallocated + // if not transferred to the InstanceKlass upon successful class loading + // in which case these pointers have been set to NULL. + instanceKlassHandle _super_klass; + ConstantPool* _cp; + Array* _fields; + Array* _methods; + Array* _inner_classes; + Array* _local_interfaces; + Array* _transitive_interfaces; AnnotationArray* _annotations; AnnotationArray* _type_annotations; + Array* _fields_annotations; + Array* _fields_type_annotations; + InstanceKlass* _klass; // InstanceKlass once created. void set_class_synthetic_flag(bool x) { _synthetic_flag = x; } void set_class_sourcefile(Symbol* x) { _sourcefile = x; } void set_class_generic_signature(Symbol* x) { _generic_signature = x; } void set_class_sde_buffer(char* x, int len) { _sde_buffer = x; _sde_length = len; } - void set_class_inner_classes(Array* x) { _inner_classes = x; } - void set_class_annotations(AnnotationArray* x) { _annotations = x; } - void set_class_type_annotations(AnnotationArray* x) { _type_annotations = x; } - void init_parsed_class_attributes() { + + void init_parsed_class_attributes(ClassLoaderData* loader_data) { + _loader_data = loader_data; _synthetic_flag = false; _sourcefile = NULL; _generic_signature = NULL; _sde_buffer = NULL; _sde_length = 0; - _annotations = _type_annotations = NULL; // initialize the other flags too: _has_finalizer = _has_empty_finalizer = _has_vanilla_constructor = false; _max_bootstrap_specifier_index = -1; + clear_class_metadata(); + _klass = NULL; } void apply_parsed_class_attributes(instanceKlassHandle k); // update k + void apply_parsed_class_metadata(instanceKlassHandle k, int fields_count, TRAPS); + void clear_class_metadata() { + // metadata created before the instance klass is created. Must be + // deallocated if classfile parsing returns an error. + _cp = NULL; + _fields = NULL; + _methods = NULL; + _inner_classes = NULL; + _local_interfaces = NULL; + _transitive_interfaces = NULL; + _annotations = _type_annotations = NULL; + _fields_annotations = _fields_type_annotations = NULL; + } class AnnotationCollector { public: enum Location { _in_field, _in_method, _in_class }; enum ID { _unknown = 0, + _method_CallerSensitive, _method_ForceInline, _method_DontInline, _method_LambdaForm_Compiled, @@ -121,14 +150,29 @@ void set_contended_group(u2 group) { _contended_group = group; } u2 contended_group() { return _contended_group; } - void set_contended(bool contended) { set_annotation(_sun_misc_Contended); } bool is_contended() { return has_annotation(_sun_misc_Contended); } }; + + // This class also doubles as a holder for metadata cleanup. class FieldAnnotationCollector: public AnnotationCollector { + ClassLoaderData* _loader_data; + AnnotationArray* _field_annotations; + AnnotationArray* _field_type_annotations; public: - FieldAnnotationCollector() : AnnotationCollector(_in_field) { } + FieldAnnotationCollector(ClassLoaderData* loader_data) : + AnnotationCollector(_in_field), + _loader_data(loader_data), + _field_annotations(NULL), + _field_type_annotations(NULL) {} void apply_to(FieldInfo* f); + ~FieldAnnotationCollector(); + AnnotationArray* field_annotations() { return _field_annotations; } + AnnotationArray* field_type_annotations() { return _field_type_annotations; } + + void set_field_annotations(AnnotationArray* a) { _field_annotations = a; } + void set_field_type_annotations(AnnotationArray* a) { _field_type_annotations = a; } }; + class MethodAnnotationCollector: public AnnotationCollector { public: MethodAnnotationCollector() : AnnotationCollector(_in_method) { } @@ -152,38 +196,30 @@ void set_stream(ClassFileStream* st) { _stream = st; } // Constant pool parsing - void parse_constant_pool_entries(ClassLoaderData* loader_data, - constantPoolHandle cp, int length, TRAPS); + void parse_constant_pool_entries(int length, TRAPS); - constantPoolHandle parse_constant_pool(ClassLoaderData* loader_data, TRAPS); + constantPoolHandle parse_constant_pool(TRAPS); // Interface parsing - Array* parse_interfaces(constantPoolHandle cp, - int length, - ClassLoaderData* loader_data, + Array* parse_interfaces(int length, Handle protection_domain, Symbol* class_name, bool* has_default_methods, TRAPS); void record_defined_class_dependencies(instanceKlassHandle defined_klass, TRAPS); + instanceKlassHandle parse_super_class(int super_class_index, TRAPS); // Field parsing - void parse_field_attributes(ClassLoaderData* loader_data, - constantPoolHandle cp, u2 attributes_count, + void parse_field_attributes(u2 attributes_count, bool is_static, u2 signature_index, u2* constantvalue_index_addr, bool* is_synthetic_addr, u2* generic_signature_index_addr, - AnnotationArray** field_annotations, - AnnotationArray** field_type_annotations, FieldAnnotationCollector* parsed_annotations, TRAPS); - Array* parse_fields(ClassLoaderData* loader_data, - Symbol* class_name, - constantPoolHandle cp, bool is_interface, + Array* parse_fields(Symbol* class_name, + bool is_interface, FieldAllocationCount *fac, - Array** fields_annotations, - Array** fields_type_annotations, u2* java_fields_count_ptr, TRAPS); void print_field_layout(Symbol* name, @@ -195,65 +231,52 @@ int static_fields_end); // Method parsing - methodHandle parse_method(ClassLoaderData* loader_data, - constantPoolHandle cp, - bool is_interface, + methodHandle parse_method(bool is_interface, AccessFlags* promoted_flags, TRAPS); - Array* parse_methods(ClassLoaderData* loader_data, - constantPoolHandle cp, - bool is_interface, + Array* parse_methods(bool is_interface, AccessFlags* promoted_flags, bool* has_final_method, bool* has_default_method, TRAPS); - Array* sort_methods(ClassLoaderData* loader_data, - Array* methods, - TRAPS); - u2* parse_exception_table(ClassLoaderData* loader_data, - u4 code_length, u4 exception_table_length, - constantPoolHandle cp, TRAPS); + intArray* sort_methods(Array* methods); + + u2* parse_exception_table(u4 code_length, u4 exception_table_length, + TRAPS); void parse_linenumber_table( u4 code_attribute_length, u4 code_length, CompressedLineNumberWriteStream** write_stream, TRAPS); u2* parse_localvariable_table(u4 code_length, u2 max_locals, u4 code_attribute_length, - constantPoolHandle cp, u2* localvariable_table_length, + u2* localvariable_table_length, bool isLVTT, TRAPS); u2* parse_checked_exceptions(u2* checked_exceptions_length, u4 method_attribute_length, - constantPoolHandle cp, TRAPS); + TRAPS); void parse_type_array(u2 array_length, u4 code_length, u4* u1_index, u4* u2_index, - u1* u1_array, u2* u2_array, constantPoolHandle cp, TRAPS); - Array* parse_stackmap_table(ClassLoaderData* loader_data, u4 code_attribute_length, TRAPS); + u1* u1_array, u2* u2_array, TRAPS); + u1* parse_stackmap_table(u4 code_attribute_length, TRAPS); // Classfile attribute parsing - void parse_classfile_sourcefile_attribute(constantPoolHandle cp, TRAPS); - void parse_classfile_source_debug_extension_attribute(constantPoolHandle cp, - int length, TRAPS); - u2 parse_classfile_inner_classes_attribute(ClassLoaderData* loader_data, - u1* inner_classes_attribute_start, + void parse_classfile_sourcefile_attribute(TRAPS); + void parse_classfile_source_debug_extension_attribute(int length, TRAPS); + u2 parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start, bool parsed_enclosingmethod_attribute, u2 enclosing_method_class_index, u2 enclosing_method_method_index, - constantPoolHandle cp, TRAPS); - void parse_classfile_attributes(ClassLoaderData* loader_data, - constantPoolHandle cp, - ClassAnnotationCollector* parsed_annotations, + void parse_classfile_attributes(ClassAnnotationCollector* parsed_annotations, TRAPS); - void parse_classfile_synthetic_attribute(constantPoolHandle cp, TRAPS); - void parse_classfile_signature_attribute(constantPoolHandle cp, TRAPS); - void parse_classfile_bootstrap_methods_attribute(ClassLoaderData* loader_data, constantPoolHandle cp, u4 attribute_length, TRAPS); + void parse_classfile_synthetic_attribute(TRAPS); + void parse_classfile_signature_attribute(TRAPS); + void parse_classfile_bootstrap_methods_attribute(u4 attribute_length, TRAPS); // Annotations handling - AnnotationArray* assemble_annotations(ClassLoaderData* loader_data, - u1* runtime_visible_annotations, + AnnotationArray* assemble_annotations(u1* runtime_visible_annotations, int runtime_visible_annotations_length, u1* runtime_invisible_annotations, int runtime_invisible_annotations_length, TRAPS); int skip_annotation(u1* buffer, int limit, int index); int skip_annotation_value(u1* buffer, int limit, int index); - void parse_annotations(ClassLoaderData* loader_data, - u1* buffer, int limit, constantPoolHandle cp, + void parse_annotations(u1* buffer, int limit, /* Results (currently, only one result is supported): */ AnnotationCollector* result, TRAPS); @@ -267,8 +290,7 @@ int* nonstatic_oop_offsets, unsigned int* nonstatic_oop_counts); void set_precomputed_flags(instanceKlassHandle k); - Array* compute_transitive_interfaces(ClassLoaderData* loader_data, - instanceKlassHandle super, + Array* compute_transitive_interfaces(instanceKlassHandle super, Array* local_ifs, TRAPS); // Format checker methods @@ -318,7 +340,7 @@ bool is_supported_version(u2 major, u2 minor); bool has_illegal_visibility(jint flags); - void verify_constantvalue(int constantvalue_index, int signature_index, constantPoolHandle cp, TRAPS); + void verify_constantvalue(int constantvalue_index, int signature_index, TRAPS); void verify_legal_utf8(const unsigned char* buffer, int length, TRAPS); void verify_legal_class_name(Symbol* name, TRAPS); void verify_legal_field_name(Symbol* name, TRAPS); @@ -359,10 +381,17 @@ // In older versions of the VM, Klass*s cannot sneak into early phases of // constant pool construction, but in later versions they can. // %%% Let's phase out the old is_klass_reference. - bool is_klass_reference(constantPoolHandle cp, int index) { - return (EnableInvokeDynamic - ? cp->tag_at(index).is_klass_or_reference() - : cp->tag_at(index).is_klass_reference()); + bool valid_klass_reference_at(int index) { + return _cp->is_within_bounds(index) && + (EnableInvokeDynamic + ? _cp->tag_at(index).is_klass_or_reference() + : _cp->tag_at(index).is_klass_reference()); + } + + // Checks that the cpool index is in range and is a utf8 + bool valid_symbol_at(int cpool_index) { + return (_cp->is_within_bounds(cpool_index) && + _cp->tag_at(cpool_index).is_utf8()); } void copy_localvariable_table(ConstMethod* cm, int lvt_cnt, @@ -373,8 +402,7 @@ u2** localvariable_type_table_start, TRAPS); - void copy_method_annotations(ClassLoaderData* loader_data, - ConstMethod* cm, + void copy_method_annotations(ConstMethod* cm, u1* runtime_visible_annotations, int runtime_visible_annotations_length, u1* runtime_invisible_annotations, @@ -391,9 +419,15 @@ int annotation_default_length, TRAPS); + // lays out fields in class and returns the total oopmap count + void layout_fields(Handle class_loader, FieldAllocationCount* fac, + ClassAnnotationCollector* parsed_annotations, + FieldLayoutInfo* info, TRAPS); + public: // Constructor ClassFileParser(ClassFileStream* st) { set_stream(st); } + ~ClassFileParser(); // Parse .class file and return new Klass*. The Klass* is not hooked up // to the system dictionary or any other structures, so a .class file can diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/classfile/classLoaderData.cpp --- a/src/share/vm/classfile/classLoaderData.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/classfile/classLoaderData.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -70,15 +70,19 @@ _is_anonymous(is_anonymous), _keep_alive(is_anonymous), // initially _metaspace(NULL), _unloading(false), _klasses(NULL), _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL), - _next(NULL), _dependencies(NULL), + _next(NULL), _dependencies(), _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) { // empty } void ClassLoaderData::init_dependencies(TRAPS) { + _dependencies.init(CHECK); +} + +void ClassLoaderData::Dependencies::init(TRAPS) { // Create empty dependencies array to add to. CMS requires this to be // an oop so that it can track additions via card marks. We think. - _dependencies = (oop)oopFactory::new_objectArray(2, CHECK); + _list_head = oopFactory::new_objectArray(2, CHECK); } bool ClassLoaderData::claim() { @@ -95,16 +99,21 @@ } f->do_oop(&_class_loader); - f->do_oop(&_dependencies); + _dependencies.oops_do(f); _handles->oops_do(f); if (klass_closure != NULL) { classes_do(klass_closure); } } +void ClassLoaderData::Dependencies::oops_do(OopClosure* f) { + f->do_oop((oop*)&_list_head); +} + 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 +122,7 @@ if (k->oop_is_instance()) { f(InstanceKlass::cast(k)); } + assert(k != k->next_link(), "no loops!"); } } @@ -152,14 +162,14 @@ // It's a dependency we won't find through GC, add it. This is relatively rare // Must handle over GC point. Handle dependency(THREAD, to); - from_cld->add_dependency(dependency, CHECK); + from_cld->_dependencies.add(dependency, CHECK); } -void ClassLoaderData::add_dependency(Handle dependency, TRAPS) { +void ClassLoaderData::Dependencies::add(Handle dependency, TRAPS) { // Check first if this dependency is already in the list. // Save a pointer to the last to add to under the lock. - objArrayOop ok = (objArrayOop)_dependencies; + objArrayOop ok = _list_head; objArrayOop last = NULL; while (ok != NULL) { last = ok; @@ -182,16 +192,17 @@ objArrayHandle new_dependency(THREAD, deps); // Add the dependency under lock - locked_add_dependency(last_handle, new_dependency); + locked_add(last_handle, new_dependency, THREAD); } -void ClassLoaderData::locked_add_dependency(objArrayHandle last_handle, - objArrayHandle new_dependency) { +void ClassLoaderData::Dependencies::locked_add(objArrayHandle last_handle, + objArrayHandle new_dependency, + Thread* THREAD) { // Have to lock and put the new dependency on the end of the dependency // array so the card mark for CMS sees that this dependency is new. // Can probably do this lock free with some effort. - MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); + ObjectLocker ol(Handle(THREAD, _list_head), THREAD); oop loader_or_mirror = new_dependency->obj_at(0); @@ -258,6 +269,7 @@ return; } prev = k; + assert(k != k->next_link(), "no loops!"); } ShouldNotReachHere(); // should have found this class!! } @@ -318,6 +330,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 +458,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 +485,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/classfile/classLoaderData.hpp --- a/src/share/vm/classfile/classLoaderData.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/classfile/classLoaderData.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -93,6 +93,18 @@ class ClassLoaderData : public CHeapObj { friend class VMStructs; private: + class Dependencies VALUE_OBJ_CLASS_SPEC { + objArrayOop _list_head; + void locked_add(objArrayHandle last, + objArrayHandle new_dependency, + Thread* THREAD); + public: + Dependencies() : _list_head(NULL) {} + void add(Handle dependency, TRAPS); + void init(TRAPS); + void oops_do(OopClosure* f); + }; + friend class ClassLoaderDataGraph; friend class ClassLoaderDataGraphMetaspaceIterator; friend class MetaDataFactory; @@ -100,10 +112,11 @@ static ClassLoaderData * _the_null_class_loader_data; - oop _class_loader; // oop used to uniquely identify a class loader - // class loader or a canonical class path - oop _dependencies; // oop to hold dependencies from this class loader - // data to others. + oop _class_loader; // oop used to uniquely identify a class loader + // class loader or a canonical class path + Dependencies _dependencies; // holds dependencies from this class loader + // data to others. + Metaspace * _metaspace; // Meta-space where meta-data defined by the // classes in the class loader are allocated. Mutex* _metaspace_lock; // Locks the metaspace for allocations and setup. @@ -134,9 +147,6 @@ static Metaspace* _ro_metaspace; static Metaspace* _rw_metaspace; - void add_dependency(Handle dependency, TRAPS); - void locked_add_dependency(objArrayHandle last, objArrayHandle new_dependency); - void set_next(ClassLoaderData* next) { _next = next; } ClassLoaderData* next() const { return _next; } @@ -191,6 +201,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. @@ -234,6 +245,7 @@ void add_to_deallocate_list(Metadata* m); static ClassLoaderData* class_loader_data(oop loader); + static ClassLoaderData* class_loader_data_or_null(oop loader); static ClassLoaderData* anonymous_class_loader_data(oop loader, TRAPS); static void print_loader(ClassLoaderData *loader_data, outputStream *out); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/classfile/classLoaderData.inline.hpp --- a/src/share/vm/classfile/classLoaderData.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/classfile/classLoaderData.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -25,9 +25,15 @@ #include "classfile/classLoaderData.hpp" #include "classfile/javaClasses.hpp" +inline ClassLoaderData* ClassLoaderData::class_loader_data_or_null(oop loader) { + if (loader == NULL) { + return ClassLoaderData::the_null_class_loader_data(); + } + return java_lang_ClassLoader::loader_data(loader); +} + inline ClassLoaderData* ClassLoaderData::class_loader_data(oop loader) { - if (loader == NULL) return ClassLoaderData::the_null_class_loader_data(); - ClassLoaderData* loader_data = java_lang_ClassLoader::loader_data(loader); + ClassLoaderData* loader_data = class_loader_data_or_null(loader); assert(loader_data != NULL, "Must be"); return loader_data; } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/classfile/defaultMethods.cpp --- a/src/share/vm/classfile/defaultMethods.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/classfile/defaultMethods.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/classfile/dictionary.cpp --- a/src/share/vm/classfile/dictionary.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/classfile/dictionary.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -347,6 +347,7 @@ assert_locked_or_safepoint(SystemDictionary_lock); assert(obj() != NULL, "adding NULL obj"); assert(obj()->name() == class_name, "sanity check on name"); + assert(loader_data != NULL, "Must be non-NULL"); unsigned int hash = compute_hash(class_name, loader_data); int index = hash_to_index(hash); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/classfile/javaClasses.hpp --- a/src/share/vm/classfile/javaClasses.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/classfile/javaClasses.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1060,15 +1060,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/classfile/symbolTable.cpp --- a/src/share/vm/classfile/symbolTable.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/classfile/symbolTable.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 @@ -49,18 +49,17 @@ Symbol* sym; - if (c_heap) { + if (DumpSharedSpaces) { + // Allocate all symbols to CLD shared metaspace + sym = new (len, ClassLoaderData::the_null_class_loader_data(), THREAD) Symbol(name, len, -1); + } else if (c_heap) { // refcount starts as 1 - assert(!DumpSharedSpaces, "never allocate to C heap"); sym = new (len, THREAD) Symbol(name, len, 1); assert(sym != NULL, "new should call vm_exit_out_of_memory if C_HEAP is exhausted"); } else { - if (DumpSharedSpaces) { - sym = new (len, ClassLoaderData::the_null_class_loader_data(), THREAD) Symbol(name, len, -1); - } else { + // Allocate to global arena sym = new (len, arena(), THREAD) Symbol(name, len, -1); } - } return sym; } @@ -678,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/classfile/symbolTable.hpp --- a/src/share/vm/classfile/symbolTable.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/classfile/symbolTable.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/classfile/systemDictionary.cpp --- a/src/share/vm/classfile/systemDictionary.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/classfile/systemDictionary.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 @@ -866,16 +918,22 @@ // the new entry. Klass* SystemDictionary::find(Symbol* class_name, - Handle class_loader, - Handle protection_domain, - TRAPS) { + Handle class_loader, + Handle protection_domain, + TRAPS) { // UseNewReflection // The result of this call should be consistent with the result // of the call to resolve_instance_class_or_null(). // See evaluation 6790209 and 4474172 for more details. class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader())); - ClassLoaderData* loader_data = register_loader(class_loader, CHECK_NULL); + ClassLoaderData* loader_data = ClassLoaderData::class_loader_data_or_null(class_loader()); + + if (loader_data == NULL) { + // If the ClassLoaderData has not been setup, + // then the class loader has no entries in the dictionary. + return NULL; + } unsigned int d_hash = dictionary()->compute_hash(class_name, loader_data); int d_index = dictionary()->hash_to_index(d_hash); @@ -1134,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?"); @@ -1199,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 @@ -1526,9 +1592,10 @@ // Used for assertions and verification only Klass* SystemDictionary::find_class(Symbol* class_name, ClassLoaderData* loader_data) { #ifndef ASSERT - guarantee(VerifyBeforeGC || - VerifyDuringGC || - VerifyBeforeExit || + guarantee(VerifyBeforeGC || + VerifyDuringGC || + VerifyBeforeExit || + VerifyDuringStartup || VerifyAfterGC, "too expensive"); #endif assert_locked_or_safepoint(SystemDictionary_lock); @@ -2145,10 +2212,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. @@ -2156,14 +2222,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/classfile/systemDictionary.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 ) \ @@ -197,8 +199,10 @@ /* graal.api.code */ \ do_klass(Assumptions_klass, com_oracle_graal_api_code_Assumptions, Opt) \ do_klass(Assumptions_ConcreteMethod_klass, com_oracle_graal_api_code_Assumptions_ConcreteMethod, Opt) \ + do_klass(Assumptions_NoFinalizableSubclass_klass, com_oracle_graal_api_code_Assumptions_NoFinalizableSubclass, Opt) \ do_klass(Assumptions_ConcreteSubtype_klass, com_oracle_graal_api_code_Assumptions_ConcreteSubtype, Opt) \ do_klass(Assumptions_MethodContents_klass, com_oracle_graal_api_code_Assumptions_MethodContents, Opt) \ + do_klass(Assumptions_CallSiteTargetValue_klass, com_oracle_graal_api_code_Assumptions_CallSiteTargetValue, Opt) \ do_klass(BytecodePosition_klass, com_oracle_graal_api_code_BytecodePosition, Opt) \ do_klass(DebugInfo_klass, com_oracle_graal_api_code_DebugInfo, Opt) \ do_klass(BytecodeFrame_klass, com_oracle_graal_api_code_BytecodeFrame, Opt) \ @@ -207,8 +211,9 @@ do_klass(CompilationResult_DataPatch_klass, com_oracle_graal_api_code_CompilationResult_DataPatch, Opt) \ do_klass(CompilationResult_ExceptionHandler_klass, com_oracle_graal_api_code_CompilationResult_ExceptionHandler, Opt) \ do_klass(CompilationResult_Mark_klass, com_oracle_graal_api_code_CompilationResult_Mark, Opt) \ - do_klass(CompilationResult_Safepoint_klass, com_oracle_graal_api_code_CompilationResult_Safepoint, Opt) \ + do_klass(CompilationResult_Infopoint_klass, com_oracle_graal_api_code_CompilationResult_Infopoint, Opt) \ do_klass(CompilationResult_Site_klass, com_oracle_graal_api_code_CompilationResult_Site, Opt) \ + do_klass(InfopointReason_klass, com_oracle_graal_api_code_InfopointReason, Opt) \ do_klass(code_Register_klass, com_oracle_graal_api_code_Register, Opt) \ do_klass(RegisterValue_klass, com_oracle_graal_api_code_RegisterValue, Opt) \ do_klass(StackSlot_klass, com_oracle_graal_api_code_StackSlot, Opt) \ @@ -525,8 +530,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 @@ -663,18 +668,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/classfile/verifier.cpp --- a/src/share/vm/classfile/verifier.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/classfile/verifier.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/classfile/vmSymbols.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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") \ @@ -296,6 +299,7 @@ template(com_oracle_graal_hotspot_HotSpotCompilationResult, "com/oracle/graal/hotspot/HotSpotCompilationResult") \ template(com_oracle_graal_hotspot_HotSpotRuntimeCallTarget, "com/oracle/graal/hotspot/HotSpotRuntimeCallTarget") \ template(com_oracle_graal_hotspot_bridge_VMToCompiler, "com/oracle/graal/hotspot/bridge/VMToCompiler") \ + template(com_oracle_graal_hotspot_bridge_CompilerToVMImpl, "com/oracle/graal/hotspot/bridge/CompilerToVMImpl") \ template(com_oracle_graal_hotspot_meta_HotSpotCodeInfo, "com/oracle/graal/hotspot/meta/HotSpotCodeInfo") \ template(com_oracle_graal_hotspot_meta_HotSpotInstalledCode, "com/oracle/graal/hotspot/meta/HotSpotInstalledCode") \ template(com_oracle_graal_hotspot_meta_HotSpotJavaType, "com/oracle/graal/hotspot/meta/HotSpotJavaType") \ @@ -319,14 +323,17 @@ template(com_oracle_graal_api_code_Assumptions, "com/oracle/graal/api/code/Assumptions") \ template(com_oracle_graal_api_code_Assumptions_MethodContents, "com/oracle/graal/api/code/Assumptions$MethodContents") \ template(com_oracle_graal_api_code_Assumptions_ConcreteSubtype, "com/oracle/graal/api/code/Assumptions$ConcreteSubtype") \ + template(com_oracle_graal_api_code_Assumptions_NoFinalizableSubclass, "com/oracle/graal/api/code/Assumptions$NoFinalizableSubclass") \ template(com_oracle_graal_api_code_Assumptions_ConcreteMethod, "com/oracle/graal/api/code/Assumptions$ConcreteMethod") \ + template(com_oracle_graal_api_code_Assumptions_CallSiteTargetValue,"com/oracle/graal/api/code/Assumptions$CallSiteTargetValue") \ template(com_oracle_graal_api_code_CompilationResult, "com/oracle/graal/api/code/CompilationResult") \ template(com_oracle_graal_api_code_CompilationResult_Call, "com/oracle/graal/api/code/CompilationResult$Call") \ template(com_oracle_graal_api_code_CompilationResult_DataPatch, "com/oracle/graal/api/code/CompilationResult$DataPatch") \ template(com_oracle_graal_api_code_CompilationResult_ExceptionHandler, "com/oracle/graal/api/code/CompilationResult$ExceptionHandler") \ template(com_oracle_graal_api_code_CompilationResult_Mark, "com/oracle/graal/api/code/CompilationResult$Mark") \ - template(com_oracle_graal_api_code_CompilationResult_Safepoint, "com/oracle/graal/api/code/CompilationResult$Safepoint") \ + template(com_oracle_graal_api_code_CompilationResult_Infopoint, "com/oracle/graal/api/code/CompilationResult$Infopoint") \ template(com_oracle_graal_api_code_CompilationResult_Site, "com/oracle/graal/api/code/CompilationResult$Site") \ + template(com_oracle_graal_api_code_InfopointReason, "com/oracle/graal/api/code/InfopointReason") \ template(com_oracle_graal_api_code_BytecodeFrame, "com/oracle/graal/api/code/BytecodeFrame") \ template(com_oracle_graal_api_code_BytecodePosition, "com/oracle/graal/api/code/BytecodePosition") \ template(com_oracle_graal_api_code_DebugInfo, "com/oracle/graal/api/code/DebugInfo") \ @@ -334,6 +341,7 @@ template(com_oracle_graal_api_code_RegisterValue, "com/oracle/graal/api/code/RegisterValue") \ template(com_oracle_graal_api_code_StackSlot, "com/oracle/graal/api/code/StackSlot") \ template(com_oracle_graal_api_code_VirtualObject, "com/oracle/graal/api/code/VirtualObject") \ + template(com_oracle_graal_api_code_InvalidInstalledCodeException, "com/oracle/graal/api/code/InvalidInstalledCodeException") \ template(startCompiler_name, "startCompiler") \ template(bootstrap_name, "bootstrap") \ template(shutdownCompiler_name, "shutdownCompiler") \ @@ -374,7 +382,6 @@ template(forObject_name, "forObject") \ template(callbackInternal_name, "callbackInternal") \ template(callback_signature, "(Ljava/lang/Object;)Ljava/lang/Object;") \ - template(MethodInvalidatedException, "com/oracle/graal/api/code/InstalledCode$MethodInvalidatedException") \ /* graal.api.interpreter */ \ template(com_oracle_graal_api_interpreter_Interpreter, "com/oracle/graal/api/interpreter/Interpreter") \ template(interpreter_execute_name, "execute") \ @@ -438,6 +445,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") \ @@ -561,6 +569,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;")\ @@ -803,9 +812,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") \ @@ -1122,6 +1130,9 @@ do_intrinsic(_Double_valueOf, java_lang_Double, valueOf_name, Double_valueOf_signature, F_S) \ do_name( Double_valueOf_signature, "(D)Ljava/lang/Double;") \ \ + do_intrinsic(_CompilerToVMImpl_executeCompiledMethod, com_oracle_graal_hotspot_bridge_CompilerToVMImpl, executeCompiledMethod_name, CompilerToVMImpl_executeCompiledMethod_signature, F_SN)\ + do_name( CompilerToVMImpl_executeCompiledMethod_signature, "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;J)Ljava/lang/Object;") \ + do_name( executeCompiledMethod_name, "executeCompiledMethodIntrinsic") \ /*end*/ diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/code/codeBlob.cpp --- a/src/share/vm/code/codeBlob.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/code/codeBlob.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -186,7 +186,7 @@ FREE_C_HEAP_ARRAY(unsigned char, _oop_maps, mtCode); _oop_maps = NULL; } - _comments.free(); + _strings.free(); } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/code/codeBlob.hpp --- a/src/share/vm/code/codeBlob.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/code/codeBlob.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 @@ -187,12 +187,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); } }; @@ -358,10 +358,11 @@ int _unpack_with_exception_in_tls; +#ifdef GRAAL // (thomaswue) Offset when Graal calls uncommon_trap. int _uncommon_trap_offset; int _implicit_exception_uncommon_trap_offset; - +#endif // Creation support DeoptimizationBlob( @@ -416,6 +417,7 @@ } address unpack_with_exception_in_tls() const { return code_begin() + _unpack_with_exception_in_tls; } +#ifdef GRAAL // (thomaswue) Offset when Graal calls uncommon_trap. void set_uncommon_trap_offset(int offset) { _uncommon_trap_offset = offset; @@ -427,7 +429,7 @@ assert(contains(code_begin() + _implicit_exception_uncommon_trap_offset), "must be PC inside codeblob"); } address implicit_exception_uncommon_trap() const { return code_begin() + _implicit_exception_uncommon_trap_offset; } - +#endif }; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/code/codeCache.hpp --- a/src/share/vm/code/codeCache.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/code/codeCache.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/code/compiledIC.cpp --- a/src/share/vm/code/compiledIC.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/code/compiledIC.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -567,7 +567,7 @@ return; } #endif - assert(stub!=NULL, "stub not found"); + guarantee(stub != NULL, "stub not found"); if (TraceICs) { ResourceMark rm; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/code/compressedStream.cpp --- a/src/share/vm/code/compressedStream.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/code/compressedStream.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -195,7 +195,7 @@ // for this block (a matching directive turns it back on later). // These directives can be removed once the MS VS.NET 2005 // compiler stack overflow is fixed. -#if _MSC_VER >=1400 && !defined(_WIN64) +#if defined(_MSC_VER) && _MSC_VER >=1400 && !defined(_WIN64) #pragma optimize("", off) #pragma warning(disable: 4748) #endif @@ -276,7 +276,7 @@ guarantee(fails == 0, "test failures"); } -#if _MSC_VER >=1400 && !defined(_WIN64) +#if defined(_MSC_VER) &&_MSC_VER >=1400 && !defined(_WIN64) #pragma warning(default: 4748) #pragma optimize("", on) #endif diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/code/dependencies.cpp --- a/src/share/vm/code/dependencies.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/code/dependencies.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -144,6 +144,11 @@ assert_common_1(evol_method, DepValue(_oop_recorder, m)); } +void Dependencies::assert_has_no_finalizable_subclasses(Klass* ctxk) { + check_ctxk(ctxk); + assert_common_1(no_finalizable_subclasses, DepValue(_oop_recorder, ctxk)); +} + void Dependencies::assert_leaf_type(Klass* ctxk) { if (ctxk->oop_is_array()) { // As a special case, support this assertion on an array type, @@ -170,6 +175,10 @@ check_ctxk(ctxk); assert_common_2(unique_concrete_method, DepValue(_oop_recorder, ctxk), DepValue(_oop_recorder, uniqm)); } + +void Dependencies::assert_call_site_target_value(oop call_site, oop method_handle) { + assert_common_2(call_site_target_value, DepValue(_oop_recorder, JNIHandles::make_local(call_site)), DepValue(_oop_recorder, JNIHandles::make_local(method_handle))); +} #endif // GRAAL diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/code/dependencies.hpp --- a/src/share/vm/code/dependencies.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/code/dependencies.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -360,9 +360,11 @@ public: void assert_evol_method(Method* m); + void assert_has_no_finalizable_subclasses(Klass* ctxk); void assert_leaf_type(Klass* ctxk); void assert_unique_concrete_method(Klass* ctxk, Method* uniqm); void assert_abstract_with_unique_concrete_subtype(Klass* ctxk, Klass* conck); + void assert_call_site_target_value(oop callSite, oop methodHandle); #endif // GRAAL // Define whether a given method or type is concrete. diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/code/icBuffer.hpp --- a/src/share/vm/code/icBuffer.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/code/icBuffer.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/code/nmethod.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -497,7 +497,6 @@ #endif // def HAVE_DTRACE_H } - nmethod* nmethod::new_native_nmethod(methodHandle method, int compile_id, CodeBuffer *code_buffer, @@ -513,17 +512,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 @@ -548,16 +549,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); - - 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); + 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); + + 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 @@ -604,8 +608,9 @@ + round_to(handler_table->size_in_bytes(), oopSize) + round_to(nul_chk_table->size_in_bytes(), oopSize) + round_to(debug_info->data_size() , oopSize) - + leaf_graph_ids_size; - nm = new (nmethod_size) + + leaf_graph_ids_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, @@ -618,7 +623,8 @@ , installed_code, triggered_deoptimizations #endif - ); + ); + } if (nm != NULL) { // To make dependency checking during class loading fast, record // the nmethod dependencies in the classes it is dependent on. @@ -818,9 +824,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; } @@ -1301,10 +1307,12 @@ } #ifdef GRAAL - if (_graal_installed_code != NULL) { - HotSpotInstalledCode::set_nmethod(_graal_installed_code, 0); - _graal_installed_code = NULL; - } + // The method can only be unloaded after the pointer to the installed code + // Java wrapper is no longer alive. Here we need to clear out this weak + // reference to the dead object. + if (_graal_installed_code != NULL) { + _graal_installed_code = NULL; + } #endif // Make the class unloaded - i.e., change state and notify sweeper @@ -1388,18 +1396,17 @@ return false; } -#ifdef GRAAL - if (_graal_installed_code != NULL) { - HotSpotInstalledCode::set_nmethod(_graal_installed_code, 0); - _graal_installed_code = NULL; - } -#endif - // The caller can be calling the method statically or through an inline // cache call. if (!is_osr_method() && !is_not_entrant()) { - NativeJump::patch_verified_entry(entry_point(), verified_entry_point(), - SharedRuntime::get_handle_wrong_method_stub()); + address stub = SharedRuntime::get_handle_wrong_method_stub(); +#ifdef GRAAL + if (_graal_installed_code != NULL && !HotSpotInstalledCode::isDefault(_graal_installed_code)) { + // This was manually installed machine code. Patch entry with stub that throws an exception. + stub = SharedRuntime::get_deoptimized_installed_code_stub(); + } +#endif + NativeJump::patch_verified_entry(entry_point(), verified_entry_point(), stub); } if (is_in_use()) { diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/code/stubs.cpp --- a/src/share/vm/code/stubs.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/code/stubs.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/code/stubs.hpp --- a/src/share/vm/code/stubs.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/code/stubs.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/compiler/compileBroker.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -68,9 +68,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(); \ @@ -81,9 +80,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(); \ @@ -96,22 +95,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(); \ @@ -125,8 +123,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 @@ -362,7 +360,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); } @@ -371,7 +369,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(); } @@ -508,7 +506,7 @@ ResourceMark rm(thread); // - if (_compile_id != 0) log->print(" compile_id='%d'", _compile_id); + log->print(" compile_id='%d'", _compile_id); if (_osr_bci != CompileBroker::standard_entry_bci) { log->print(" compile_kind='osr'"); // same as nmethod::compile_kind } // else compile_kind='c2c' @@ -1227,18 +1225,16 @@ assert(method->method_holder()->oop_is_instance(), "not an instance method"); assert(osr_bci == InvocationEntryBci || (0 <= osr_bci && osr_bci < method->code_size()), "bci out of range"); assert(!method->is_abstract() && (osr_bci == InvocationEntryBci || !method->is_native()), "cannot compile abstract/native methods"); - assert(!method->method_holder()->is_not_initialized(), "method holder must be initialized"); - - if (!TieredCompilation) { - comp_level = CompLevel_highest_tier; - } - + assert(!method->method_holder()->is_not_initialized() || method->intrinsic_id() == vmIntrinsics::_CompilerToVMImpl_executeCompiledMethod, "method holder must be initialized"); + // allow any levels for WhiteBox + assert(WhiteBoxAPI || TieredCompilation || comp_level == CompLevel_highest_tier, "only CompLevel_highest_tier must be used in non-tiered"); // return quickly if possible // 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; } @@ -1275,7 +1271,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. @@ -1392,8 +1388,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; } @@ -1401,7 +1398,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; } @@ -1773,6 +1770,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 @@ -1786,9 +1784,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. @@ -1825,7 +1824,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"); @@ -1863,7 +1867,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); @@ -1888,9 +1893,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; } @@ -2156,7 +2161,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(); @@ -2170,13 +2182,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/compiler/compileBroker.hpp --- a/src/share/vm/compiler/compileBroker.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/compiler/compileBroker.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/compiler/compileLog.cpp --- a/src/share/vm/compiler/compileLog.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/compiler/compileLog.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/compiler/compilerOracle.cpp --- a/src/share/vm/compiler/compilerOracle.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/compiler/compilerOracle.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/compiler/disassembler.cpp --- a/src/share/vm/compiler/disassembler.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/compiler/disassembler.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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); } @@ -499,7 +499,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/compiler/disassembler.hpp --- a/src/share/vm/compiler/disassembler.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/compiler/disassembler.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -48,6 +48,7 @@ #include "memory/iterator.hpp" #include "memory/referencePolicy.hpp" #include "memory/resourceArea.hpp" +#include "memory/tenuredGeneration.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/globals_extension.hpp" @@ -916,7 +917,31 @@ return; } - size_t expand_bytes = 0; + // Compute some numbers about the state of the heap. + const size_t used_after_gc = used(); + const size_t capacity_after_gc = capacity(); + + CardGeneration::compute_new_size(); + + // Reset again after a possible resizing + cmsSpace()->reset_after_compaction(); + + assert(used() == used_after_gc && used_after_gc <= capacity(), + err_msg("used: " SIZE_FORMAT " used_after_gc: " SIZE_FORMAT + " capacity: " SIZE_FORMAT, used(), used_after_gc, capacity())); +} + +void ConcurrentMarkSweepGeneration::compute_new_size_free_list() { + assert_locked_or_safepoint(Heap_lock); + + // If incremental collection failed, we just want to expand + // to the limit. + if (incremental_collection_failed()) { + clear_incremental_collection_failed(); + grow_to_reserved(); + return; + } + double free_percentage = ((double) free()) / capacity(); double desired_free_percentage = (double) MinHeapFreeRatio / 100; double maximum_free_percentage = (double) MaxHeapFreeRatio / 100; @@ -925,9 +950,7 @@ if (free_percentage < desired_free_percentage) { size_t desired_capacity = (size_t)(used() / ((double) 1 - desired_free_percentage)); assert(desired_capacity >= capacity(), "invalid expansion size"); - expand_bytes = MAX2(desired_capacity - capacity(), MinHeapDeltaBytes); - } - if (expand_bytes > 0) { + size_t expand_bytes = MAX2(desired_capacity - capacity(), MinHeapDeltaBytes); if (PrintGCDetails && Verbose) { size_t desired_capacity = (size_t)(used() / ((double) 1 - desired_free_percentage)); gclog_or_tty->print_cr("\nFrom compute_new_size: "); @@ -961,6 +984,14 @@ gclog_or_tty->print_cr(" Expanded free fraction %f", ((double) free()) / capacity()); } + } else { + size_t desired_capacity = (size_t)(used() / ((double) 1 - desired_free_percentage)); + assert(desired_capacity <= capacity(), "invalid expansion size"); + size_t shrink_bytes = capacity() - desired_capacity; + // Don't shrink unless the delta is greater than the minimum shrink we want + if (shrink_bytes >= MinHeapDeltaBytes) { + shrink_free_list_by(shrink_bytes); + } } } @@ -1872,7 +1903,7 @@ assert_locked_or_safepoint(Heap_lock); FreelistLocker z(this); MetaspaceGC::compute_new_size(); - _cmsGen->compute_new_size(); + _cmsGen->compute_new_size_free_list(); } // A work method used by foreground collection to determine @@ -2063,11 +2094,6 @@ // required. _collectorState = FinalMarking; } - if (PrintGCDetails && - (_collectorState > Idling || - !GCCause::is_user_requested_gc(GenCollectedHeap::heap()->gc_cause()))) { - gclog_or_tty->print(" (concurrent mode failure)"); - } collect_in_foreground(clear_all_soft_refs); // For a mark-sweep, compute_new_size() will be called @@ -2606,6 +2632,10 @@ } void ConcurrentMarkSweepGeneration::gc_prologue(bool full) { + + _capacity_at_prologue = capacity(); + _used_at_prologue = used(); + // Delegate to CMScollector which knows how to coordinate between // this and any other CMS generations that it is responsible for // collecting. @@ -2779,6 +2809,23 @@ } } + +void +CMSCollector::print_on_error(outputStream* st) { + CMSCollector* collector = ConcurrentMarkSweepGeneration::_collector; + if (collector != NULL) { + CMSBitMap* bitmap = &collector->_markBitMap; + st->print_cr("Marking Bits: (CMSBitMap*) " PTR_FORMAT, bitmap); + bitmap->print_on_error(st, " Bits: "); + + st->cr(); + + CMSBitMap* mut_bitmap = &collector->_modUnionTable; + st->print_cr("Mod Union Table: (CMSBitMap*) " PTR_FORMAT, mut_bitmap); + mut_bitmap->print_on_error(st, " Bits: "); + } +} + //////////////////////////////////////////////////////// // CMS Verification Support //////////////////////////////////////////////////////// @@ -3305,6 +3352,26 @@ } +void ConcurrentMarkSweepGeneration::shrink_by(size_t bytes) { + assert_locked_or_safepoint(ExpandHeap_lock); + // Shrink committed space + _virtual_space.shrink_by(bytes); + // Shrink space; this also shrinks the space's BOT + _cmsSpace->set_end((HeapWord*) _virtual_space.high()); + size_t new_word_size = heap_word_size(_cmsSpace->capacity()); + // Shrink the shared block offset array + _bts->resize(new_word_size); + MemRegion mr(_cmsSpace->bottom(), new_word_size); + // Shrink the card table + Universe::heap()->barrier_set()->resize_covered_region(mr); + + if (Verbose && PrintGC) { + size_t new_mem_size = _virtual_space.committed_size(); + size_t old_mem_size = new_mem_size + bytes; + gclog_or_tty->print_cr("Shrinking %s from " SIZE_FORMAT "K to " SIZE_FORMAT "K", + name(), old_mem_size/K, new_mem_size/K); + } +} void ConcurrentMarkSweepGeneration::shrink(size_t bytes) { assert_locked_or_safepoint(Heap_lock); @@ -3356,7 +3423,7 @@ return success; } -void ConcurrentMarkSweepGeneration::shrink_by(size_t bytes) { +void ConcurrentMarkSweepGeneration::shrink_free_list_by(size_t bytes) { assert_locked_or_safepoint(Heap_lock); assert_lock_strong(freelistLock()); // XXX Fix when compaction is implemented. @@ -3400,10 +3467,10 @@ if (PrintCMSStatistics != 0) { _collector->resetYields(); } - if (PrintGCDetails && PrintGCTimeStamps) { + if (PrintGCDetails) { gclog_or_tty->date_stamp(PrintGCDateStamps); - gclog_or_tty->stamp(); - gclog_or_tty->print_cr(": [%s-concurrent-%s-start]", + gclog_or_tty->stamp(PrintGCTimeStamps); + gclog_or_tty->print_cr("[%s-concurrent-%s-start]", _collector->cmsGen()->short_name(), _phase); } _collector->resetTimer(); @@ -6073,6 +6140,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()); @@ -6477,6 +6548,10 @@ } } +void CMSBitMap::print_on_error(outputStream* st, const char* prefix) const { + _bm.print_on_error(st, prefix); +} + #ifndef PRODUCT void CMSBitMap::assert_locked() const { CMSLockVerifier::assert_locked(lock()); @@ -9075,51 +9150,6 @@ } } -// The desired expansion delta is computed so that: -// . desired free percentage or greater is used -void ASConcurrentMarkSweepGeneration::compute_new_size() { - assert_locked_or_safepoint(Heap_lock); - - GenCollectedHeap* gch = (GenCollectedHeap*) GenCollectedHeap::heap(); - - // If incremental collection failed, we just want to expand - // to the limit. - if (incremental_collection_failed()) { - clear_incremental_collection_failed(); - grow_to_reserved(); - return; - } - - assert(UseAdaptiveSizePolicy, "Should be using adaptive sizing"); - - assert(gch->kind() == CollectedHeap::GenCollectedHeap, - "Wrong type of heap"); - int prev_level = level() - 1; - assert(prev_level >= 0, "The cms generation is the lowest generation"); - Generation* prev_gen = gch->get_gen(prev_level); - assert(prev_gen->kind() == Generation::ASParNew, - "Wrong type of young generation"); - ParNewGeneration* younger_gen = (ParNewGeneration*) prev_gen; - size_t cur_eden = younger_gen->eden()->capacity(); - CMSAdaptiveSizePolicy* size_policy = cms_size_policy(); - size_t cur_promo = free(); - size_policy->compute_tenured_generation_free_space(cur_promo, - max_available(), - cur_eden); - resize(cur_promo, size_policy->promo_size()); - - // Record the new size of the space in the cms generation - // that is available for promotions. This is temporary. - // It should be the desired promo size. - size_policy->avg_cms_promo()->sample(free()); - size_policy->avg_old_live()->sample(used()); - - if (UsePerfData) { - CMSGCAdaptivePolicyCounters* counters = gc_adaptive_policy_counters(); - counters->update_cms_capacity_counter(capacity()); - } -} - void ASConcurrentMarkSweepGeneration::shrink_by(size_t desired_bytes) { assert_locked_or_safepoint(Heap_lock); assert_lock_strong(freelistLock()); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -60,6 +60,7 @@ class FreeChunk; class PromotionInfo; class ScanMarkedObjectsAgainCarefullyClosure; +class TenuredGeneration; // A generic CMS bit map. It's the basis for both the CMS marking bit map // as well as for the mod union table (in each case only a subset of the @@ -150,6 +151,8 @@ size_t heapWordToOffset(HeapWord* addr) const; size_t heapWordDiffToOffsetDiff(size_t diff) const; + void print_on_error(outputStream* st, const char* prefix) const; + // debugging // is this address range covered by the bit-map? NOT_PRODUCT( @@ -810,9 +813,6 @@ // used regions of each generation to limit the extent of sweep void save_sweep_limits(); - // Resize the generations included in the collector. - void compute_new_size(); - // A work method used by foreground collection to determine // what type of collection (compacting or not, continuing or fresh) // it should do. @@ -909,6 +909,9 @@ void releaseFreelistLocks() const; bool haveFreelistLocks() const; + // Adjust size of underlying generation + void compute_new_size(); + // GC prologue and epilogue void gc_prologue(bool full); void gc_epilogue(bool full); @@ -983,6 +986,8 @@ CMSAdaptiveSizePolicy* size_policy(); CMSGCAdaptivePolicyCounters* gc_adaptive_policy_counters(); + static void print_on_error(outputStream* st); + // debugging void verify(); bool verify_after_remark(); @@ -1082,7 +1087,7 @@ protected: // Shrink generation by specified size (returns false if unable to shrink) - virtual void shrink_by(size_t bytes); + void shrink_free_list_by(size_t bytes); // Update statistics for GC virtual void update_gc_stats(int level, bool full); @@ -1233,6 +1238,7 @@ CMSExpansionCause::Cause cause); virtual bool expand(size_t bytes, size_t expand_bytes); void shrink(size_t bytes); + void shrink_by(size_t bytes); HeapWord* expand_and_par_lab_allocate(CMSParGCThreadState* ps, size_t word_sz); bool expand_and_ensure_spooling_space(PromotionInfo* promo); @@ -1293,7 +1299,13 @@ bool must_be_youngest() const { return false; } bool must_be_oldest() const { return true; } - void compute_new_size(); + // Resize the generation after a compacting GC. The + // generation can be treated as a contiguous space + // after the compaction. + virtual void compute_new_size(); + // Resize the generation after a non-compacting + // collection. + void compute_new_size_free_list(); CollectionTypes debug_collection_type() { return _debug_collection_type; } void rotate_debug_collection_type(); @@ -1315,7 +1327,6 @@ virtual void shrink_by(size_t bytes); public: - virtual void compute_new_size(); ASConcurrentMarkSweepGeneration(ReservedSpace rs, size_t initial_byte_size, int level, CardTableRS* ct, bool use_adaptive_freelists, diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -300,8 +300,7 @@ } } -// Wait until the next synchronous GC, a concurrent full gc request, -// or a timeout, whichever is earlier. +// Wait until any cms_lock event void ConcurrentMarkSweepThread::wait_on_cms_lock(long t_millis) { MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag); @@ -315,15 +314,100 @@ "Should not be set"); } +// Wait until the next synchronous GC, a concurrent full gc request, +// or a timeout, whichever is earlier. +void ConcurrentMarkSweepThread::wait_on_cms_lock_for_scavenge(long t_millis) { + // Wait time in millis or 0 value representing infinite wait for a scavenge + assert(t_millis >= 0, "Wait time for scavenge should be 0 or positive"); + + GenCollectedHeap* gch = GenCollectedHeap::heap(); + double start_time_secs = os::elapsedTime(); + double end_time_secs = start_time_secs + (t_millis / ((double) MILLIUNITS)); + + // Total collections count before waiting loop + unsigned int before_count; + { + MutexLockerEx hl(Heap_lock, Mutex::_no_safepoint_check_flag); + before_count = gch->total_collections(); + } + + unsigned int loop_count = 0; + + while(!_should_terminate) { + double now_time = os::elapsedTime(); + long wait_time_millis; + + if(t_millis != 0) { + // New wait limit + wait_time_millis = (long) ((end_time_secs - now_time) * MILLIUNITS); + if(wait_time_millis <= 0) { + // Wait time is over + break; + } + } else { + // No wait limit, wait if necessary forever + wait_time_millis = 0; + } + + // Wait until the next event or the remaining timeout + { + MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag); + + if (_should_terminate || _collector->_full_gc_requested) { + return; + } + set_CMS_flag(CMS_cms_wants_token); // to provoke notifies + assert(t_millis == 0 || wait_time_millis > 0, "Sanity"); + CGC_lock->wait(Mutex::_no_safepoint_check_flag, wait_time_millis); + clear_CMS_flag(CMS_cms_wants_token); + assert(!CMS_flag_is_set(CMS_cms_has_token | CMS_cms_wants_token), + "Should not be set"); + } + + // Extra wait time check before entering the heap lock to get the collection count + if(t_millis != 0 && os::elapsedTime() >= end_time_secs) { + // Wait time is over + break; + } + + // Total collections count after the event + unsigned int after_count; + { + MutexLockerEx hl(Heap_lock, Mutex::_no_safepoint_check_flag); + after_count = gch->total_collections(); + } + + if(before_count != after_count) { + // There was a collection - success + break; + } + + // Too many loops warning + if(++loop_count == 0) { + warning("wait_on_cms_lock_for_scavenge() has looped %u times", loop_count - 1); + } + } +} + void ConcurrentMarkSweepThread::sleepBeforeNextCycle() { while (!_should_terminate) { if (CMSIncrementalMode) { icms_wait(); + if(CMSWaitDuration >= 0) { + // Wait until the next synchronous GC, a concurrent full gc + // request or a timeout, whichever is earlier. + wait_on_cms_lock_for_scavenge(CMSWaitDuration); + } return; } else { - // Wait until the next synchronous GC, a concurrent full gc - // request or a timeout, whichever is earlier. - wait_on_cms_lock(CMSWaitDuration); + if(CMSWaitDuration >= 0) { + // Wait until the next synchronous GC, a concurrent full gc + // request or a timeout, whichever is earlier. + wait_on_cms_lock_for_scavenge(CMSWaitDuration); + } else { + // Wait until any cms_lock event or check interval not to call shouldConcurrentCollect permanently + wait_on_cms_lock(CMSCheckInterval); + } } // Check if we should start a CMS collection cycle if (_collector->shouldConcurrentCollect()) { diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -130,6 +130,12 @@ // A concurrent full gc request terminates the wait. void wait_on_cms_lock(long t_millis); + // Wait on CMS lock until the next synchronous GC + // or given timeout, whichever is earlier. A timeout value + // of 0 indicates that there is no upper bound on the wait time. + // A concurrent full gc request terminates the wait. + void wait_on_cms_lock_for_scavenge(long t_millis); + // The CMS thread will yield during the work portion of its cycle // only when requested to. Both synchronous and asychronous requests // are provided: diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/g1/collectionSetChooser.cpp --- a/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -146,43 +146,6 @@ verify(); } -uint CollectionSetChooser::calc_min_old_cset_length() { - // The min old CSet region bound is based on the maximum desired - // number of mixed GCs after a cycle. I.e., even if some old regions - // look expensive, we should add them to the CSet anyway to make - // sure we go through the available old regions in no more than the - // maximum desired number of mixed GCs. - // - // The calculation is based on the number of marked regions we added - // to the CSet chooser in the first place, not how many remain, so - // that the result is the same during all mixed GCs that follow a cycle. - - const size_t region_num = (size_t) _length; - const size_t gc_num = (size_t) G1MixedGCCountTarget; - size_t result = region_num / gc_num; - // emulate ceiling - if (result * gc_num < region_num) { - result += 1; - } - return (uint) result; -} - -uint CollectionSetChooser::calc_max_old_cset_length() { - // The max old CSet region bound is based on the threshold expressed - // as a percentage of the heap size. I.e., it should bound the - // number of old regions added to the CSet irrespective of how many - // of them are available. - - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - const size_t region_num = g1h->n_regions(); - const size_t perc = (size_t) G1OldCSetRegionThresholdPercent; - size_t result = region_num * perc / 100; - // emulate ceiling - if (100 * result < region_num * perc) { - result += 1; - } - return (uint) result; -} void CollectionSetChooser::add_region(HeapRegion* hr) { assert(!hr->isHumongous(), diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/g1/collectionSetChooser.hpp --- a/src/share/vm/gc_implementation/g1/collectionSetChooser.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/collectionSetChooser.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -51,6 +51,8 @@ uint _curr_index; // The number of candidate old regions added to the CSet chooser. + // Note: this is not updated when removing a region using + // remove_and_move_to_next() below. uint _length; // Keeps track of the start of the next array chunk to be claimed by @@ -111,13 +113,8 @@ hr->live_bytes() < _region_live_threshold_bytes; } - // Calculate the minimum number of old regions we'll add to the CSet - // during a mixed GC. - uint calc_min_old_cset_length(); - - // Calculate the maximum number of old regions we'll add to the CSet - // during a mixed GC. - uint calc_max_old_cset_length(); + // Returns the number candidate old regions added + uint length() { return _length; } // Serial version. void add_region(HeapRegion *hr); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -101,6 +101,10 @@ } #endif +void CMBitMapRO::print_on_error(outputStream* st, const char* prefix) const { + _bm.print_on_error(st, prefix); +} + bool CMBitMap::allocate(ReservedSpace heap_rs) { _bmStartWord = (HeapWord*)(heap_rs.base()); _bmWordSize = heap_rs.size()/HeapWordSize; // heap_rs.size() is in bytes @@ -784,7 +788,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 +797,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 +814,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 +984,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 +1025,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 +1083,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 +1240,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 +1293,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. @@ -1310,11 +1338,6 @@ _markStack.expand(); } -#if VERIFY_OBJS_PROCESSED - _scan_obj_cl.objs_processed = 0; - ThreadLocalObjQueue::objs_enqueued = 0; -#endif - // Statistics double now = os::elapsedTime(); _remark_mark_times.add((mark_work_end - start) * 1000.0); @@ -2189,14 +2212,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; } @@ -2235,8 +2261,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; } @@ -2258,27 +2284,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 @@ -2299,8 +2316,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()); } }; @@ -2333,7 +2350,6 @@ ProcessTask& _proc_task; G1CollectedHeap* _g1h; ConcurrentMark* _cm; - bool _processing_is_mt; public: G1CMRefProcTaskProxy(ProcessTask& proc_task, @@ -2341,15 +2357,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); } @@ -2361,9 +2377,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); @@ -2389,12 +2407,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; @@ -2420,26 +2455,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 @@ -2459,6 +2507,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. @@ -2487,8 +2536,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 @@ -2498,8 +2547,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. @@ -2507,8 +2556,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); } }; @@ -2529,43 +2578,42 @@ 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(); - -#if VERIFY_OBJS_PROCESSED - if (_scan_obj_cl.objs_processed != ThreadLocalObjQueue::objs_enqueued) { - gclog_or_tty->print_cr("Processed = %d, enqueued = %d.", - _scan_obj_cl.objs_processed, - ThreadLocalObjQueue::objs_enqueued); - guarantee(_scan_obj_cl.objs_processed == - ThreadLocalObjQueue::objs_enqueued, - "Different number of objs processed and enqueued."); - } -#endif } #ifndef PRODUCT @@ -3233,6 +3281,13 @@ } } +void ConcurrentMark::print_on_error(outputStream* st) const { + st->print_cr("Marking Bits (Prev, Next): (CMBitMap*) " PTR_FORMAT ", (CMBitMap*) " PTR_FORMAT, + _prevMarkBitMap, _nextMarkBitMap); + _prevMarkBitMap->print_on_error(st, " Prev Bits: "); + _nextMarkBitMap->print_on_error(st, " Next Bits: "); +} + // We take a break if someone is trying to stop the world. bool ConcurrentMark::do_yield_check(uint worker_id) { if (should_yield()) { @@ -3870,8 +3925,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 @@ -3881,7 +3936,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 @@ -3930,7 +3985,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. @@ -3967,11 +4022,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"); @@ -3992,6 +4061,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; @@ -4111,7 +4186,7 @@ // bitmap knows by how much we need to move it as it knows its // granularity). assert(_finger < _region_limit, "invariant"); - HeapWord* new_finger = _nextMarkBitMap->nextWord(_finger); + HeapWord* new_finger = _nextMarkBitMap->nextObject(_finger); // Check if bitmap iteration was aborted while scanning the last object if (new_finger >= _region_limit) { giveup_current_region(); @@ -4253,10 +4328,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; @@ -4336,20 +4413,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/g1/concurrentMark.hpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -97,7 +97,6 @@ HeapWord* limit = NULL) const; // conversion utilities - // XXX Fix these so that offsets are size_t's... HeapWord* offsetToHeapWord(size_t offset) const { return _bmStartWord + (offset << _shifter); } @@ -105,10 +104,17 @@ return pointer_delta(addr, _bmStartWord) >> _shifter; } int heapWordDiffToOffsetDiff(size_t diff) const; - HeapWord* nextWord(HeapWord* addr) { - return offsetToHeapWord(heapWordToOffset(addr) + 1); + + // The argument addr should be the start address of a valid object + HeapWord* nextObject(HeapWord* addr) { + oop obj = (oop) addr; + HeapWord* res = addr + obj->size(); + assert(offsetToHeapWord(heapWordToOffset(res)) == res, "sanity"); + return res; } + void print_on_error(outputStream* st, const char* prefix) const; + // debugging NOT_PRODUCT(bool covers(ReservedSpace rs) const;) }; @@ -162,7 +168,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 @@ -487,9 +493,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(); @@ -822,6 +831,8 @@ void print_worker_threads_on(outputStream* st) const; + void print_on_error(outputStream* st) const; + // The following indicate whether a given verbose level has been // set. Notice that anything above stats is conditional to // _MARKING_VERBOSE_ having been set to 1 @@ -1142,7 +1153,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -252,12 +252,10 @@ start_offset = _bm.get_next_one_offset(start_offset, end_offset); while (start_offset < end_offset) { - HeapWord* obj_addr = offsetToHeapWord(start_offset); - oop obj = (oop) obj_addr; if (!cl->do_bit(start_offset)) { return false; } - HeapWord* next_addr = MIN2(obj_addr + obj->size(), end_addr); + HeapWord* next_addr = MIN2(nextObject(offsetToHeapWord(start_offset)), end_addr); BitMap::idx_t next_offset = heapWordToOffset(next_addr); start_offset = _bm.get_next_one_offset(next_offset, end_offset); } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 @@ -3280,12 +3298,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); @@ -3370,7 +3388,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) "); } } @@ -3418,6 +3437,15 @@ heap_region_iterate(&blk); } +void G1CollectedHeap::print_on_error(outputStream* st) const { + this->CollectedHeap::print_on_error(st); + + if (_cm != NULL) { + st->cr(); + _cm->print_on_error(st); + } +} + void G1CollectedHeap::print_gc_threads_on(outputStream* st) const { if (G1CollectedHeap::use_parallel_gc_threads()) { workers()->print_worker_threads_on(st); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 @@ -1578,6 +1581,7 @@ virtual void verify(bool silent); virtual void print_on(outputStream* st) const; virtual void print_extended_on(outputStream* st) const; + virtual void print_on_error(outputStream* st) const; virtual void print_gc_threads_on(outputStream* st) const; virtual void gc_threads_do(ThreadClosure* tc) const; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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: @@ -1806,6 +1794,14 @@ } #endif // !PRODUCT +double G1CollectorPolicy::reclaimable_bytes_perc(size_t reclaimable_bytes) { + // Returns the given amount of reclaimable bytes (that represents + // the amount of reclaimable space still to be collected) as a + // percentage of the current heap capacity. + size_t capacity_bytes = _g1->capacity(); + return (double) reclaimable_bytes * 100.0 / (double) capacity_bytes; +} + bool G1CollectorPolicy::next_gc_should_be_mixed(const char* true_action_str, const char* false_action_str) { CollectionSetChooser* cset_chooser = _collectionSetChooser; @@ -1815,19 +1811,21 @@ ergo_format_reason("candidate old regions not available")); return false; } + + // Is the amount of uncollected reclaimable space above G1HeapWastePercent? size_t reclaimable_bytes = cset_chooser->remaining_reclaimable_bytes(); - size_t capacity_bytes = _g1->capacity(); - double perc = (double) reclaimable_bytes * 100.0 / (double) capacity_bytes; + double reclaimable_perc = reclaimable_bytes_perc(reclaimable_bytes); double threshold = (double) G1HeapWastePercent; - if (perc < threshold) { + if (reclaimable_perc <= threshold) { ergo_verbose4(ErgoMixedGCs, false_action_str, - ergo_format_reason("reclaimable percentage lower than threshold") + ergo_format_reason("reclaimable percentage not over threshold") ergo_format_region("candidate old regions") ergo_format_byte_perc("reclaimable") ergo_format_perc("threshold"), cset_chooser->remaining_regions(), - reclaimable_bytes, perc, threshold); + reclaimable_bytes, + reclaimable_perc, threshold); return false; } @@ -1838,10 +1836,50 @@ ergo_format_byte_perc("reclaimable") ergo_format_perc("threshold"), cset_chooser->remaining_regions(), - reclaimable_bytes, perc, threshold); + reclaimable_bytes, + reclaimable_perc, threshold); return true; } +uint G1CollectorPolicy::calc_min_old_cset_length() { + // The min old CSet region bound is based on the maximum desired + // number of mixed GCs after a cycle. I.e., even if some old regions + // look expensive, we should add them to the CSet anyway to make + // sure we go through the available old regions in no more than the + // maximum desired number of mixed GCs. + // + // The calculation is based on the number of marked regions we added + // to the CSet chooser in the first place, not how many remain, so + // that the result is the same during all mixed GCs that follow a cycle. + + const size_t region_num = (size_t) _collectionSetChooser->length(); + const size_t gc_num = (size_t) MAX2(G1MixedGCCountTarget, (uintx) 1); + size_t result = region_num / gc_num; + // emulate ceiling + if (result * gc_num < region_num) { + result += 1; + } + return (uint) result; +} + +uint G1CollectorPolicy::calc_max_old_cset_length() { + // The max old CSet region bound is based on the threshold expressed + // as a percentage of the heap size. I.e., it should bound the + // number of old regions added to the CSet irrespective of how many + // of them are available. + + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + const size_t region_num = g1h->n_regions(); + const size_t perc = (size_t) G1OldCSetRegionThresholdPercent; + size_t result = region_num * perc / 100; + // emulate ceiling + if (100 * result < region_num * perc) { + result += 1; + } + return (uint) result; +} + + void G1CollectorPolicy::finalize_cset(double target_pause_time_ms) { double young_start_time_sec = os::elapsedTime(); @@ -1855,7 +1893,7 @@ double base_time_ms = predict_base_elapsed_time_ms(_pending_cards); double predicted_pause_time_ms = base_time_ms; - double time_remaining_ms = target_pause_time_ms - base_time_ms; + double time_remaining_ms = MAX2(target_pause_time_ms - base_time_ms, 0.0); ergo_verbose4(ErgoCSetConstruction | ErgoHigh, "start choosing CSet", @@ -1893,7 +1931,7 @@ _collection_set = _inc_cset_head; _collection_set_bytes_used_before = _inc_cset_bytes_used_before; - time_remaining_ms -= _inc_cset_predicted_elapsed_time_ms; + time_remaining_ms = MAX2(time_remaining_ms - _inc_cset_predicted_elapsed_time_ms, 0.0); predicted_pause_time_ms += _inc_cset_predicted_elapsed_time_ms; ergo_verbose3(ErgoCSetConstruction | ErgoHigh, @@ -1917,8 +1955,8 @@ if (!gcs_are_young()) { CollectionSetChooser* cset_chooser = _collectionSetChooser; cset_chooser->verify(); - const uint min_old_cset_length = cset_chooser->calc_min_old_cset_length(); - const uint max_old_cset_length = cset_chooser->calc_max_old_cset_length(); + const uint min_old_cset_length = calc_min_old_cset_length(); + const uint max_old_cset_length = calc_max_old_cset_length(); uint expensive_region_num = 0; bool check_time_remaining = adaptive_young_list_length(); @@ -1936,6 +1974,30 @@ break; } + + // Stop adding regions if the remaining reclaimable space is + // not above G1HeapWastePercent. + size_t reclaimable_bytes = cset_chooser->remaining_reclaimable_bytes(); + double reclaimable_perc = reclaimable_bytes_perc(reclaimable_bytes); + double threshold = (double) G1HeapWastePercent; + if (reclaimable_perc <= threshold) { + // We've added enough old regions that the amount of uncollected + // reclaimable space is at or below the waste threshold. Stop + // adding old regions to the CSet. + ergo_verbose5(ErgoCSetConstruction, + "finish adding old regions to CSet", + ergo_format_reason("reclaimable percentage not over threshold") + ergo_format_region("old") + ergo_format_region("max") + ergo_format_byte_perc("reclaimable") + ergo_format_perc("threshold"), + old_cset_region_length(), + max_old_cset_length, + reclaimable_bytes, + reclaimable_perc, threshold); + break; + } + double predicted_time_ms = predict_region_elapsed_time_ms(hr, gcs_are_young()); if (check_time_remaining) { if (predicted_time_ms > time_remaining_ms) { @@ -1975,7 +2037,7 @@ } // We will add this region to the CSet. - time_remaining_ms -= predicted_time_ms; + time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0); predicted_pause_time_ms += predicted_time_ms; cset_chooser->remove_and_move_to_next(hr); _g1->old_set_remove(hr); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -619,6 +619,18 @@ bool predict_will_fit(uint young_length, double base_time_ms, uint base_free_regions, double target_pause_time_ms); + // Calculate the minimum number of old regions we'll add to the CSet + // during a mixed GC. + uint calc_min_old_cset_length(); + + // Calculate the maximum number of old regions we'll add to the CSet + // during a mixed GC. + uint calc_max_old_cset_length(); + + // Returns the given amount of uncollected reclaimable space + // as a percentage of the current heap capacity. + double reclaimable_bytes_perc(size_t reclaimable_bytes); + public: G1CollectorPolicy(); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/g1/ptrQueue.cpp --- a/src/share/vm/gc_implementation/g1/ptrQueue.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp --- a/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -373,6 +373,8 @@ " does not exceed used.end() = " PTR_FORMAT "," " yet last_chunk_index_to_check " INTPTR_FORMAT " exceeds last_chunk_index " INTPTR_FORMAT, + last_block, last_block + last_block_size, + used.end(), last_chunk_index_to_check, last_chunk_index)); assert(sp->used_region().end() > used.end(), err_msg("Expansion did not happen: " diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -173,6 +173,12 @@ void reset_counters(); #endif // #ifndef PRODUCT + void print_on_error(outputStream* st) const { + st->print_cr("Marking Bits: (ParMarkBitMap*) " PTR_FORMAT, this); + _beg_bits.print_on_error(st, " Begin Bits: "); + _end_bits.print_on_error(st, " End Bits: "); + } + #ifdef ASSERT void verify_clear() const; inline void verify_bit(idx_t bit) const; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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) { @@ -409,7 +415,7 @@ // heap remains parsable. const bool limit_exceeded = size_policy()->gc_overhead_limit_exceeded(); const bool softrefs_clear = collector_policy()->all_soft_refs_clear(); - assert(!limit_exceeded || softrefs_clear, "Should have been cleared"); + if (limit_exceeded && softrefs_clear) { *gc_overhead_limit_was_exceeded = true; size_policy()->set_gc_overhead_limit_exceeded(false); @@ -642,6 +648,15 @@ MetaspaceAux::print_on(st); } +void ParallelScavengeHeap::print_on_error(outputStream* st) const { + this->CollectedHeap::print_on_error(st); + + if (UseParallelOldGC) { + st->cr(); + PSParallelCompact::print_on_error(st); + } +} + void ParallelScavengeHeap::gc_threads_do(ThreadClosure* tc) const { PSScavenge::gc_task_manager()->threads_do(tc); } @@ -656,7 +671,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -220,6 +220,7 @@ void prepare_for_verify(); virtual void print_on(outputStream* st) const; + virtual void print_on_error(outputStream* st) const; virtual void print_gc_threads_on(outputStream* st) const; virtual void gc_threads_do(ThreadClosure* tc) const; virtual void print_tracing_info() const; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/parallelScavenge/psOldGen.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -165,6 +165,10 @@ #endif // #ifdef ASSERT +void PSParallelCompact::print_on_error(outputStream* st) { + _mark_bitmap.print_on_error(st); +} + #ifndef PRODUCT const char* PSParallelCompact::space_names[] = { "old ", "eden", "from", "to " diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1163,6 +1163,8 @@ // Time since last full gc (in milliseconds). static jlong millis_since_last_gc(); + static void print_on_error(outputStream* st); + #ifndef PRODUCT // Debugging support. static const char* space_names[last_space_id]; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp --- a/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -948,6 +948,8 @@ break; } if (e != scan_end) { + assert(e < scan_end, err_msg("e: " PTR_FORMAT " scan_end: " PTR_FORMAT, e, scan_end)); + if ((page_expected.size != page_size || page_expected.lgrp_id != lgrp_id()) && page_expected.size != 0) { os::free_memory(s, pointer_delta(e, s, sizeof(char)), page_size); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/gc_interface/collectedHeap.hpp --- a/src/share/vm/gc_interface/collectedHeap.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/gc_interface/collectedHeap.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -567,6 +567,14 @@ print_on(st); } + virtual void print_on_error(outputStream* st) const { + st->print_cr("Heap:"); + print_extended_on(st); + st->cr(); + + _barrier_set->print_on(st); + } + // Print all GC threads (other than the VM thread) // used by this heap. virtual void print_gc_threads_on(outputStream* st) const = 0; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -236,7 +236,7 @@ for (jint i = 0; i < values->length(); i++) { ScopeValue* cur_second = NULL; ScopeValue* value = get_hotspot_value(((oop*) values->base(T_OBJECT))[i], total_frame_size, objects, cur_second, oop_recorder); - + if (isLongArray && cur_second == NULL) { // we're trying to put ints into a long array... this isn't really valid, but it's used for some optimizations. // add an int 0 constant @@ -294,10 +294,14 @@ if (!assumption.is_null()) { if (assumption->klass() == Assumptions_MethodContents::klass()) { assumption_MethodContents(assumption); + } else if (assumption->klass() == Assumptions_NoFinalizableSubclass::klass()) { + assumption_NoFinalizableSubclass(assumption); } else if (assumption->klass() == Assumptions_ConcreteSubtype::klass()) { assumption_ConcreteSubtype(assumption); } else if (assumption->klass() == Assumptions_ConcreteMethod::klass()) { assumption_ConcreteMethod(assumption); + } else if (assumption->klass() == Assumptions_CallSiteTargetValue::klass()) { + assumption_CallSiteTargetValue(assumption); } else { assumption->print(); fatal("unexpected Assumption subclass"); @@ -350,7 +354,7 @@ // constructor used to create a stub CodeInstaller::CodeInstaller(Handle& target_method, BufferBlob*& blob, jlong& id) { No_Safepoint_Verifier no_safepoint; - + _oop_recorder = new OopRecorder(&_arena); initialize_fields(target_method(), NULL); assert(_name != NULL, "installMethod needs NON-NULL name"); @@ -398,7 +402,7 @@ _debug_recorder = new DebugInformationRecorder(_oop_recorder); _debug_recorder->set_oopmaps(new OopMapSet()); - + buffer.initialize_oop_recorder(_oop_recorder); _instructions = buffer.insts(); @@ -416,9 +420,17 @@ if (site->is_a(CompilationResult_Call::klass())) { TRACE_graal_4("call at %i", pc_offset); site_Call(buffer, pc_offset, site); - } else if (site->is_a(CompilationResult_Safepoint::klass())) { - TRACE_graal_4("safepoint at %i", pc_offset); - site_Safepoint(buffer, pc_offset, site); + } else if (site->is_a(CompilationResult_Infopoint::klass())) { + // three reasons for infopoints denote actual safepoints + oop reason = CompilationResult_Infopoint::reason(site); + if (InfopointReason::SAFEPOINT() == reason || InfopointReason::CALL() == reason || InfopointReason::IMPLICIT_EXCEPTION() == reason) { + TRACE_graal_4("safepoint at %i", pc_offset); + site_Safepoint(buffer, pc_offset, site); + } else { + // if the infopoint is not an actual safepoint, it must have one of the other reasons + // (safeguard against new safepoint types that require handling above) + assert(InfopointReason::METHOD_START() == reason || InfopointReason::METHOD_END() == reason || InfopointReason::LINE_NUMBER() == reason, ""); + } } else if (site->is_a(CompilationResult_DataPatch::klass())) { TRACE_graal_4("datapatch at %i", pc_offset); site_DataPatch(buffer, pc_offset, site); @@ -437,6 +449,12 @@ _dependencies->assert_evol_method(method()); } +void CodeInstaller::assumption_NoFinalizableSubclass(Handle assumption) { + Handle receiverType_handle = Assumptions_NoFinalizableSubclass::receiverType(assumption()); + Klass* receiverType = asKlass(HotSpotResolvedObjectType::metaspaceKlass(receiverType_handle)); + _dependencies->assert_has_no_finalizable_subclasses(receiverType); +} + void CodeInstaller::assumption_ConcreteSubtype(Handle assumption) { Handle context_handle = Assumptions_ConcreteSubtype::context(assumption()); Handle subtype_handle = Assumptions_ConcreteSubtype::subtype(assumption()); @@ -460,6 +478,13 @@ _dependencies->assert_unique_concrete_method(context, impl()); } +void CodeInstaller::assumption_CallSiteTargetValue(Handle assumption) { + Handle callSite = Assumptions_CallSiteTargetValue::callSite(assumption()); + Handle methodHandle = Assumptions_CallSiteTargetValue::methodHandle(assumption()); + + _dependencies->assert_call_site_target_value(callSite(), methodHandle()); +} + void CodeInstaller::process_exception_handlers() { // allocate some arrays for use by the collection code. const int num_handlers = 5; @@ -578,7 +603,7 @@ } void CodeInstaller::site_Safepoint(CodeBuffer& buffer, jint pc_offset, oop site) { - oop debug_info = CompilationResult_Safepoint::debugInfo(site); + oop debug_info = CompilationResult_Infopoint::debugInfo(site); assert(debug_info != NULL, "debug info expected"); // address instruction = _instructions->start() + pc_offset; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/graal/graalCodeInstaller.hpp --- a/src/share/vm/graal/graalCodeInstaller.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/graal/graalCodeInstaller.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -93,8 +93,10 @@ void initialize_buffer(CodeBuffer& buffer); void assumption_MethodContents(Handle assumption); + void assumption_NoFinalizableSubclass(Handle assumption); void assumption_ConcreteSubtype(Handle assumption); void assumption_ConcreteMethod(Handle assumption); + void assumption_CallSiteTargetValue(Handle assumption); void site_Safepoint(CodeBuffer& buffer, jint pc_offset, oop site); void site_Call(CodeBuffer& buffer, jint pc_offset, oop site); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/graal/graalCompiler.cpp --- a/src/share/vm/graal/graalCompiler.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/graal/graalCompiler.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -91,6 +91,10 @@ VMToCompiler::startCompiler(); _initialized = true; if (BootstrapGraal) { + // We turn off CompileTheWorld and complete the VM startup so that + // Graal can be compiled by C1/C2 when we do a CTW. + NOT_PRODUCT(CompileTheWorld = false); + CompilationPolicy::completed_vm_startup(); VMToCompiler::bootstrap(); } } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/graal/graalCompiler.hpp --- a/src/share/vm/graal/graalCompiler.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/graal/graalCompiler.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -68,7 +68,7 @@ // Print compilation timers and statistics virtual void print_timers(); - + static Handle get_JavaTypeFromSignature(Symbol* signature, KlassHandle accessor, TRAPS); static Handle get_JavaType(constantPoolHandle cp, int index, KlassHandle accessor, TRAPS); static Handle get_JavaType(Symbol* klass_name, TRAPS); @@ -93,6 +93,26 @@ return ((index & 0xFF) << 8) | (index >> 8); } + static int to_index_u4(int index) { + // Swap. + return ((index & 0xFF) << 24) | ((index & 0xFF00) << 8) | ((index & 0xFF0000) >> 8) | ((index & 0xFF000000) >> 24); + } + + static int to_cp_index(int raw_index, Bytecodes::Code bc) { + int cp_index; + if (bc == Bytecodes::_invokedynamic) { + cp_index = to_index_u4(raw_index); + assert(ConstantPool::is_invokedynamic_index(cp_index), "not an invokedynamic constant pool index"); + } else { + assert(bc == Bytecodes::_getfield || bc == Bytecodes::_putfield || + bc == Bytecodes::_getstatic || bc == Bytecodes::_putstatic || + bc == Bytecodes::_invokeinterface || bc == Bytecodes::_invokevirtual || + bc == Bytecodes::_invokespecial || bc == Bytecodes::_invokestatic, err_msg("unexpected invoke opcode: %d %s", bc, Bytecodes::name(bc))); + cp_index = to_cp_index_u2(raw_index); + } + return cp_index; + } + static void initialize_buffer_blob(); }; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -62,7 +62,7 @@ C2V_ENTRY(jbyteArray, initializeBytecode, (JNIEnv *env, jobject, jlong metaspace_method, jbyteArray result)) methodHandle method = asMethod(metaspace_method); ResourceMark rm; - + int code_size = method->code_size(); jbyte* reconstituted_code = NULL; @@ -320,6 +320,11 @@ return code == NULL ? 0 : code->insts_size(); C2V_END +C2V_VMENTRY(jint, constantPoolLength, (JNIEnv *env, jobject, jobject type)) + ConstantPool* cp = InstanceKlass::cast(java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(type)))->constants(); + return cp->length(); +C2V_END + C2V_VMENTRY(jobject, lookupType, (JNIEnv *env, jobject, jstring jname, jobject accessingClass, jboolean eagerResolve)) ResourceMark rm; @@ -416,12 +421,22 @@ return JNIHandles::make_local(THREAD, result); C2V_END +C2V_VMENTRY(jobject, lookupAppendixInPool, (JNIEnv *env, jobject, jobject type, jint index, jbyte opcode)) + Bytecodes::Code bc = (Bytecodes::Code) (((int) opcode) & 0xFF); + index = GraalCompiler::to_cp_index(index, bc); + constantPoolHandle cpool(InstanceKlass::cast(java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(type)))->constants()); + oop appendix_oop = ConstantPool::appendix_at_if_loaded(cpool, index); + + return JNIHandles::make_local(THREAD, appendix_oop); +C2V_END + C2V_VMENTRY(jobject, lookupMethodInPool, (JNIEnv *env, jobject, jobject type, jint index, jbyte opcode)) - index = GraalCompiler::to_cp_index_u2(index); constantPoolHandle cp = InstanceKlass::cast(java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(type)))->constants(); instanceKlassHandle pool_holder(cp->pool_holder()); Bytecodes::Code bc = (Bytecodes::Code) (((int) opcode) & 0xFF); + index = GraalCompiler::to_cp_index(index, bc); + methodHandle method = GraalEnv::get_method_by_index(cp, index, bc, pool_holder); if (!method.is_null()) { Handle holder = GraalCompiler::get_JavaType(method->method_holder(), CHECK_NULL); @@ -430,8 +445,13 @@ // Get the method's name and signature. Handle name = java_lang_String::create_from_symbol(cp->name_ref_at(index), CHECK_NULL); Handle signature = java_lang_String::create_from_symbol(cp->signature_ref_at(index), CHECK_NULL); - int holder_index = cp->klass_ref_index_at(index); - Handle type = GraalCompiler::get_JavaType(cp, holder_index, cp->pool_holder(), CHECK_NULL); + Handle type; + if (bc != Bytecodes::_invokedynamic) { + int holder_index = cp->klass_ref_index_at(index); + type = GraalCompiler::get_JavaType(cp, holder_index, cp->pool_holder(), CHECK_NULL); + } else { + type = Handle(SystemDictionary::MethodHandle_klass()->java_mirror()); + } return JNIHandles::make_local(THREAD, VMToCompiler::createUnresolvedJavaMethod(name, signature, type, THREAD)); } C2V_END @@ -445,11 +465,11 @@ C2V_VMENTRY(void, lookupReferencedTypeInPool, (JNIEnv *env, jobject, jobject type, jint index, jbyte op)) ConstantPool* cp = InstanceKlass::cast(java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(type)))->constants(); - int opcode = (op & 0xFF); - if (opcode != Bytecodes::_checkcast && opcode != Bytecodes::_instanceof && opcode != Bytecodes::_new && opcode != Bytecodes::_anewarray - && opcode != Bytecodes::_multianewarray && opcode != Bytecodes::_ldc && opcode != Bytecodes::_ldc_w && opcode != Bytecodes::_ldc2_w) + Bytecodes::Code bc = (Bytecodes::Code) (((int) op) & 0xFF); + if (bc != Bytecodes::_checkcast && bc != Bytecodes::_instanceof && bc != Bytecodes::_new && bc != Bytecodes::_anewarray + && bc != Bytecodes::_multianewarray && bc != Bytecodes::_ldc && bc != Bytecodes::_ldc_w && bc != Bytecodes::_ldc2_w) { - index = cp->remap_instruction_operand_from_cache(GraalCompiler::to_cp_index_u2(index)); + index = cp->remap_instruction_operand_from_cache(GraalCompiler::to_cp_index(index, bc)); } constantTag tag = cp->tag_at(index); if (tag.is_field_or_method()) { @@ -479,7 +499,7 @@ int holder_index = cp->klass_ref_index_at(index); Handle holder = GraalCompiler::get_JavaType(cp, holder_index, cp->pool_holder(), CHECK_NULL); instanceKlassHandle holder_klass; - + Bytecodes::Code code = (Bytecodes::Code)(((int) opcode) & 0xFF); int offset = -1; AccessFlags flags; @@ -499,7 +519,7 @@ holder = GraalCompiler::get_JavaType(holder_klass, CHECK_NULL); } } - + Handle type = GraalCompiler::get_JavaTypeFromSignature(signature, cp->pool_holder(), CHECK_NULL); Handle field_handle = GraalCompiler::get_JavaField(offset, flags.as_int(), name, holder, type, THREAD); @@ -606,6 +626,11 @@ #endif set_boolean("verifyOops", VerifyOops); set_boolean("ciTime", CITime); + set_boolean("compileTheWorld", CompileTheWorld); + set_int("compileTheWorldStartAt", CompileTheWorldStartAt); + set_int("compileTheWorldStopAt", CompileTheWorldStopAt); + set_boolean("printCompilation", PrintCompilation); + set_boolean("printInlining", PrintInlining); set_boolean("useFastLocking", GraalUseFastLocking); set_boolean("useBiasedLocking", UseBiasedLocking); set_boolean("usePopCountInstruction", UsePopCountInstruction); @@ -640,6 +665,7 @@ set_int("constMethodMaxStackOffset", in_bytes(ConstMethod::max_stack_offset())); set_int("extraStackEntries", Method::extra_stack_entries()); set_int("methodAccessFlagsOffset", in_bytes(Method::access_flags_offset())); + set_int("methodIntrinsicIdOffset", Method::intrinsic_id_offset_in_bytes()); set_int("klassHasFinalizerFlag", JVM_ACC_HAS_FINALIZER); set_int("threadExceptionOopOffset", in_bytes(JavaThread::exception_oop_offset())); set_int("threadExceptionPcOffset", in_bytes(JavaThread::exception_pc_offset())); @@ -663,7 +689,7 @@ set_int("arrayKlassLayoutHelperIdentifier", 0x80000000); assert((Klass::_lh_array_tag_obj_value & Klass::_lh_array_tag_type_value & 0x80000000) != 0, "obj_array and type_array must have first bit set"); set_int("arrayKlassComponentMirrorOffset", in_bytes(ArrayKlass::component_mirror_offset())); - + set_int("pendingDeoptimizationOffset", in_bytes(ThreadShadow::pending_deoptimization_offset())); @@ -763,6 +789,13 @@ set_int("deoptActionReinterpret", Deoptimization::Action_reinterpret); set_int("deoptActionMakeNotEntrant", Deoptimization::Action_make_not_entrant); set_int("deoptActionMakeNotCompilable", Deoptimization::Action_make_not_compilable); + + set_int("vmIntrinsicInvokeBasic", vmIntrinsics::_invokeBasic); + set_int("vmIntrinsicLinkToVirtual", vmIntrinsics::_linkToVirtual); + set_int("vmIntrinsicLinkToStatic", vmIntrinsics::_linkToStatic); + set_int("vmIntrinsicLinkToSpecial", vmIntrinsics::_linkToSpecial); + set_int("vmIntrinsicLinkToInterface", vmIntrinsics::_linkToInterface); + set_int("g1CardQueueIndexOffset", in_bytes(JavaThread::dirty_card_queue_offset() + PtrQueue::byte_offset_of_index())); set_int("g1CardQueueBufferOffset", in_bytes(JavaThread::dirty_card_queue_offset() + PtrQueue::byte_offset_of_buf())); set_int("logOfHRGrainBytes", HeapRegion::LogOfHRGrainBytes); @@ -882,23 +915,17 @@ return JNIHandles::make_local(element); C2V_END -C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv *env, jobject, jlong metaspace_method, jlong metaspace_nmethod, jobject args)) +C2V_VMENTRY(jobject, executeCompiledMethodVarargs, (JNIEnv *env, jobject, jobject args, jlong nativeMethod)) ResourceMark rm; HandleMark hm; - assert(metaspace_method != 0, "just checking"); - methodHandle mh = asMethod(metaspace_method); + nmethod* nm = (nmethod*) (address) nativeMethod; + methodHandle mh = nm->method(); Symbol* signature = mh->signature(); JavaCallArguments jca(mh->size_of_parameters()); JavaArgumentUnboxer jap(signature, &jca, (arrayOop) JNIHandles::resolve(args), mh->is_static()); JavaValue result(jap.get_ret_type()); - - nmethod* nm = (nmethod*) (address) metaspace_nmethod; - if (nm == NULL || !nm->is_alive()) { - THROW_0(vmSymbols::MethodInvalidatedException()); - } - jca.set_alternative_target(nm); JavaCalls::call(&result, mh, &jca, CHECK_NULL); @@ -912,29 +939,6 @@ } C2V_END -C2V_VMENTRY(jobject, executeCompiledMethod, (JNIEnv *env, jobject, jlong metaspace_method, jlong metaspace_nmethod, jobject arg1, jobject arg2, jobject arg3)) - ResourceMark rm; - HandleMark hm; - - methodHandle method = asMethod(metaspace_method); - assert(!method.is_null(), "just checking"); - JavaValue result(T_OBJECT); - JavaCallArguments args; - args.push_oop(JNIHandles::resolve(arg1)); - args.push_oop(JNIHandles::resolve(arg2)); - args.push_oop(JNIHandles::resolve(arg3)); - - nmethod* nm = (nmethod*) (address) metaspace_nmethod; - if (nm == NULL || !nm->is_alive()) { - THROW_0(vmSymbols::MethodInvalidatedException()); - } - - args.set_alternative_target(nm); - JavaCalls::call(&result, method, &args, CHECK_NULL); - - return JNIHandles::make_local((oop) result.get_jobject()); -C2V_END - C2V_VMENTRY(jint, getVtableEntryOffset, (JNIEnv *, jobject, jlong metaspace_method)) Method* method = asMethod(metaspace_method); @@ -1005,10 +1009,10 @@ u2 typeCPIdx = table[i].descriptor_cp_index; u2 slot = table[i].slot; - char* name = method->constants()->string_at_noresolve(nameCPIdx); + char* name = method->constants()->symbol_at(nameCPIdx)->as_C_string(); Handle nameHandle = java_lang_String::create_from_str(name, CHECK_NULL); - char* typeInfo = method->constants()->string_at_noresolve(typeCPIdx); + char* typeInfo = method->constants()->symbol_at(typeCPIdx)->as_C_string(); Handle typeHandle = java_lang_String::create_from_str(typeInfo, CHECK_NULL); Handle holderHandle = GraalCompiler::createHotSpotResolvedObjectType(method, CHECK_0); @@ -1053,6 +1057,20 @@ C2V_END +C2V_VMENTRY(void, invalidateInstalledCode, (JNIEnv *env, jobject, jlong nativeMethod)) + nmethod* m = (nmethod*)nativeMethod; + if (!m->is_not_entrant()) { + m->mark_for_deoptimization(); + VM_Deoptimize op; + VMThread::execute(&op); + } +C2V_END + + +C2V_VMENTRY(jboolean, isInstalledCodeValid, (JNIEnv *env, jobject, jlong nativeMethod)) + nmethod* m = (nmethod*)nativeMethod; + return m->is_alive() && !m->is_not_entrant(); +C2V_END #define CC (char*) /*cast a literal from (const char*)*/ #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f)) @@ -1102,8 +1120,10 @@ {CC"getInvocationCount", CC"("METASPACE_METHOD")I", FN_PTR(getInvocationCount)}, {CC"getCompiledCodeSize", CC"("METASPACE_METHOD")I", FN_PTR(getCompiledCodeSize)}, {CC"getVtableEntryOffset", CC"("METASPACE_METHOD")I", FN_PTR(getVtableEntryOffset)}, + {CC"constantPoolLength", CC"("HS_RESOLVED_TYPE")I", FN_PTR(constantPoolLength)}, {CC"lookupType", CC"("STRING HS_RESOLVED_TYPE"Z)"TYPE, FN_PTR(lookupType)}, {CC"lookupConstantInPool", CC"("HS_RESOLVED_TYPE"I)"OBJECT, FN_PTR(lookupConstantInPool)}, + {CC"lookupAppendixInPool", CC"("HS_RESOLVED_TYPE"IB)"OBJECT, FN_PTR(lookupAppendixInPool)}, {CC"lookupMethodInPool", CC"("HS_RESOLVED_TYPE"IB)"METHOD, FN_PTR(lookupMethodInPool)}, {CC"lookupTypeInPool", CC"("HS_RESOLVED_TYPE"I)"TYPE, FN_PTR(lookupTypeInPool)}, {CC"lookupReferencedTypeInPool", CC"("HS_RESOLVED_TYPE"IB)V", FN_PTR(lookupReferencedTypeInPool)}, @@ -1121,14 +1141,15 @@ {CC"installCode0", CC"("HS_COMP_RESULT HS_INSTALLED_CODE"[Z)I", FN_PTR(installCode0)}, {CC"getCode", CC"(J)[B", FN_PTR(getCode)}, {CC"disassembleNMethod", CC"(J)"STRING, FN_PTR(disassembleNMethod)}, - {CC"executeCompiledMethod", CC"("METASPACE_METHOD NMETHOD OBJECT OBJECT OBJECT")"OBJECT, FN_PTR(executeCompiledMethod)}, - {CC"executeCompiledMethodVarargs", CC"("METASPACE_METHOD NMETHOD "["OBJECT")"OBJECT, FN_PTR(executeCompiledMethodVarargs)}, + {CC"executeCompiledMethodVarargs", CC"(["OBJECT NMETHOD")"OBJECT, FN_PTR(executeCompiledMethodVarargs)}, {CC"getDeoptedLeafGraphIds", CC"()[J", FN_PTR(getDeoptedLeafGraphIds)}, {CC"getLineNumberTable", CC"("HS_RESOLVED_METHOD")[J", FN_PTR(getLineNumberTable)}, {CC"getLocalVariableTable", CC"("HS_RESOLVED_METHOD")["LOCAL, FN_PTR(getLocalVariableTable)}, {CC"getFileName", CC"("HS_RESOLVED_JAVA_TYPE")"STRING, FN_PTR(getFileName)}, {CC"clearQueuedForCompilation", CC"("HS_RESOLVED_METHOD")V", FN_PTR(clearQueuedForCompilation)}, {CC"reprofile", CC"("METASPACE_METHOD")V", FN_PTR(reprofile)}, + {CC"invalidateInstalledCode", CC"(J)V", FN_PTR(invalidateInstalledCode)}, + {CC"isInstalledCodeValid", CC"(J)Z", FN_PTR(isInstalledCodeValid)}, }; int CompilerToVM_methods_count() { diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/graal/graalEnv.cpp --- a/src/share/vm/graal/graalEnv.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/graal/graalEnv.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -319,6 +319,19 @@ methodHandle GraalEnv::get_method_by_index_impl(constantPoolHandle& cpool, int index, Bytecodes::Code bc, instanceKlassHandle& accessor) { + if (bc == Bytecodes::_invokedynamic) { + ConstantPoolCacheEntry* cpce = cpool->invokedynamic_cp_cache_entry_at(index); + bool is_resolved = !cpce->is_f1_null(); + if (is_resolved) { + // Get the invoker Method* from the constant pool. + // (The appendix argument, if any, will be noted in the method's signature.) + Method* adapter = cpce->f1_as_method(); + return methodHandle(adapter); + } + + return NULL; + } + int holder_index = cpool->klass_ref_index_at(index); bool holder_is_accessible; KlassHandle holder = get_klass_by_index_impl(cpool, holder_index, holder_is_accessible, accessor); @@ -327,6 +340,27 @@ Symbol* name_sym = cpool->name_ref_at(index); Symbol* sig_sym = cpool->signature_ref_at(index); + if (cpool->has_preresolution() + || (holder() == SystemDictionary::MethodHandle_klass() && + MethodHandles::is_signature_polymorphic_name(holder(), name_sym))) { + // Short-circuit lookups for JSR 292-related call sites. + // That is, do not rely only on name-based lookups, because they may fail + // if the names are not resolvable in the boot class loader (7056328). + switch (bc) { + case Bytecodes::_invokevirtual: + case Bytecodes::_invokeinterface: + case Bytecodes::_invokespecial: + case Bytecodes::_invokestatic: + { + Method* m = ConstantPool::method_at_if_loaded(cpool, index); + if (m != NULL) { + return m; + } + } + break; + } + } + if (holder_is_accessible) { // Our declared holder is loaded. instanceKlassHandle lookup = get_instance_klass_for_declared_method_holder(holder); methodHandle m = lookup_method(accessor, lookup, name_sym, sig_sym, bc); @@ -369,7 +403,6 @@ int index, Bytecodes::Code bc, instanceKlassHandle& accessor) { ResourceMark rm; - assert(bc != Bytecodes::_invokedynamic, "invokedynamic not yet supported"); return get_method_by_index_impl(cpool, index, bc, accessor); } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/graal/graalJavaAccess.hpp --- a/src/share/vm/graal/graalJavaAccess.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/graal/graalJavaAccess.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -110,6 +110,9 @@ start_class(Assumptions_MethodContents) \ oop_field(Assumptions_MethodContents, method, "Lcom/oracle/graal/api/meta/ResolvedJavaMethod;") \ end_class \ + start_class(Assumptions_NoFinalizableSubclass) \ + oop_field(Assumptions_NoFinalizableSubclass, receiverType, "Lcom/oracle/graal/api/meta/ResolvedJavaType;") \ + end_class \ start_class(Assumptions_ConcreteSubtype) \ oop_field(Assumptions_ConcreteSubtype, context, "Lcom/oracle/graal/api/meta/ResolvedJavaType;") \ oop_field(Assumptions_ConcreteSubtype, subtype, "Lcom/oracle/graal/api/meta/ResolvedJavaType;") \ @@ -119,6 +122,10 @@ oop_field(Assumptions_ConcreteMethod, context, "Lcom/oracle/graal/api/meta/ResolvedJavaType;") \ oop_field(Assumptions_ConcreteMethod, impl, "Lcom/oracle/graal/api/meta/ResolvedJavaMethod;") \ end_class \ + start_class(Assumptions_CallSiteTargetValue) \ + oop_field(Assumptions_CallSiteTargetValue, callSite, "Ljava/lang/invoke/CallSite;") \ + oop_field(Assumptions_CallSiteTargetValue, methodHandle, "Ljava/lang/invoke/MethodHandle;") \ + end_class \ start_class(CompilationResult_Site) \ int_field(CompilationResult_Site, pcOffset) \ end_class \ @@ -131,8 +138,18 @@ int_field(CompilationResult_DataPatch, alignment) \ boolean_field(CompilationResult_DataPatch, inlined) \ end_class \ - start_class(CompilationResult_Safepoint) \ - oop_field(CompilationResult_Safepoint, debugInfo, "Lcom/oracle/graal/api/code/DebugInfo;") \ + start_class(InfopointReason) \ + static_oop_field(InfopointReason, UNKNOWN, "Lcom/oracle/graal/api/code/InfopointReason;") \ + static_oop_field(InfopointReason, SAFEPOINT, "Lcom/oracle/graal/api/code/InfopointReason;") \ + static_oop_field(InfopointReason, CALL, "Lcom/oracle/graal/api/code/InfopointReason;") \ + static_oop_field(InfopointReason, IMPLICIT_EXCEPTION, "Lcom/oracle/graal/api/code/InfopointReason;") \ + static_oop_field(InfopointReason, METHOD_START, "Lcom/oracle/graal/api/code/InfopointReason;") \ + static_oop_field(InfopointReason, METHOD_END, "Lcom/oracle/graal/api/code/InfopointReason;") \ + static_oop_field(InfopointReason, LINE_NUMBER, "Lcom/oracle/graal/api/code/InfopointReason;") \ + end_class \ + start_class(CompilationResult_Infopoint) \ + oop_field(CompilationResult_Infopoint, debugInfo, "Lcom/oracle/graal/api/code/DebugInfo;") \ + oop_field(CompilationResult_Infopoint, reason, "Lcom/oracle/graal/api/code/InfopointReason;") \ end_class \ start_class(CompilationResult_ExceptionHandler) \ int_field(CompilationResult_ExceptionHandler, handlerPos) \ diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/interpreter/abstractInterpreter.hpp --- a/src/share/vm/interpreter/abstractInterpreter.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/interpreter/abstractInterpreter.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -85,6 +85,9 @@ zerolocals_synchronized, // method needs locals initialization & is synchronized native, // native method native_synchronized, // native method & is synchronized +#ifdef GRAAL + execute_compiled_method, // direct call to compiled method address +#endif empty, // empty method (code: _return) accessor, // accessor method (code: _aload_0, _getfield, _(a|i)return) abstract, // abstract method (throws an AbstractMethodException) @@ -186,7 +189,8 @@ int caller_actual_parameters, int callee_params, int callee_locals, - bool is_top_frame) { + bool is_top_frame, + bool is_bottom_frame) { return layout_activation(method, temps, popframe_args, @@ -196,7 +200,8 @@ callee_locals, (frame*)NULL, (frame*)NULL, - is_top_frame); + is_top_frame, + is_bottom_frame); } static int layout_activation(Method* method, @@ -208,7 +213,8 @@ int callee_locals, frame* caller, frame* interpreter_frame, - bool is_top_frame); + bool is_top_frame, + bool is_bottom_frame); // Runtime support static bool is_not_reached( methodHandle method, int bci); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/interpreter/interpreter.cpp --- a/src/share/vm/interpreter/interpreter.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/interpreter/interpreter.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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())); } } @@ -188,6 +188,13 @@ // Method handle primitive? if (m->is_method_handle_intrinsic()) { vmIntrinsics::ID id = m->intrinsic_id(); +#ifdef GRAAL + if (id == vmIntrinsics::_CompilerToVMImpl_executeCompiledMethod) { + // Special method kind for directly executing the verified entry point + // of a given nmethod. + return AbstractInterpreter::execute_compiled_method; + } +#endif assert(MethodHandles::is_signature_polymorphic(id), "must match an intrinsic"); MethodKind kind = (MethodKind)( method_handle_invoke_FIRST + ((int)id - vmIntrinsics::FIRST_MH_SIG_POLY) ); @@ -287,6 +294,9 @@ case zerolocals_synchronized: tty->print("zerolocals_synchronized"); break; case native : tty->print("native" ); break; case native_synchronized : tty->print("native_synchronized" ); break; +#ifdef GRAAL + case execute_compiled_method: tty->print("execute_compiled_method"); break; +#endif case empty : tty->print("empty" ); break; case accessor : tty->print("accessor" ); break; case abstract : tty->print("abstract" ); break; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/interpreter/interpreter.hpp --- a/src/share/vm/interpreter/interpreter.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/interpreter/interpreter.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/interpreter/interpreterRuntime.cpp --- a/src/share/vm/interpreter/interpreterRuntime.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/interpreter/interpreterRuntime.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -568,11 +568,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/interpreter/linkResolver.cpp --- a/src/share/vm/interpreter/linkResolver.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/interpreter/linkResolver.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -217,6 +217,7 @@ TRAPS) { vmIntrinsics::ID iid = MethodHandles::signature_polymorphic_name_id(name); if (TraceMethodHandles) { + ResourceMark rm(THREAD); tty->print_cr("lookup_polymorphic_method iid=%s %s.%s%s", vmIntrinsics::name_at(iid), klass->external_name(), name->as_C_string(), full_signature->as_C_string()); @@ -231,6 +232,7 @@ TempNewSymbol basic_signature = MethodHandles::lookup_basic_type_signature(full_signature, keep_last_arg, CHECK); if (TraceMethodHandles) { + ResourceMark rm(THREAD); tty->print_cr("lookup_polymorphic_method %s %s => basic %s", name->as_C_string(), full_signature->as_C_string(), @@ -283,6 +285,8 @@ } if (result.not_null()) { #ifdef ASSERT + ResourceMark rm(THREAD); + TempNewSymbol basic_signature = MethodHandles::lookup_basic_type_signature(full_signature, CHECK); int actual_size_of_params = result->size_of_parameters(); @@ -458,25 +462,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 +526,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 +650,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 +664,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); @@ -803,7 +812,7 @@ if (!direct_calling_default_method && check_access && // a) check if ACC_SUPER flag is set for the current class - current_klass->is_super() && + (current_klass->is_super() || !AllowNonVirtualCalls) && // b) check if the method class is a superclass of the current class (superclass relation is not reflexive!) current_klass->is_subtype_of(method_klass()) && current_klass() != method_klass() && @@ -1217,8 +1226,10 @@ Symbol* method_signature = NULL; KlassHandle current_klass; resolve_pool(resolved_klass, method_name, method_signature, current_klass, pool, index, CHECK); - if (TraceMethodHandles) + if (TraceMethodHandles) { + ResourceMark rm(THREAD); tty->print_cr("resolve_invokehandle %s %s", method_name->as_C_string(), method_signature->as_C_string()); + } resolve_handle_call(result, resolved_klass, method_name, method_signature, current_klass, CHECK); } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/interpreter/rewriter.cpp --- a/src/share/vm/interpreter/rewriter.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/interpreter/rewriter.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -84,15 +84,13 @@ const int length = _cp_cache_map.length(); ClassLoaderData* loader_data = _pool->pool_holder()->class_loader_data(); ConstantPoolCache* cache = - ConstantPoolCache::allocate(loader_data, length, CHECK); + ConstantPoolCache::allocate(loader_data, length, _cp_cache_map, + _invokedynamic_references_map, CHECK); // initialize object cache in constant pool _pool->initialize_resolved_references(loader_data, _resolved_references_map, _resolved_reference_limit, CHECK); - - No_Safepoint_Verifier nsv; - cache->initialize(_cp_cache_map, _invokedynamic_references_map); _pool->set_cache(cache); cache->set_constant_pool(_pool()); } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/interpreter/templateInterpreter.cpp --- a/src/share/vm/interpreter/templateInterpreter.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/interpreter/templateInterpreter.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -360,6 +360,9 @@ method_entry(zerolocals) method_entry(zerolocals_synchronized) method_entry(empty) +#ifdef GRAAL + method_entry(execute_compiled_method) +#endif method_entry(accessor) method_entry(abstract) method_entry(java_lang_math_sin ) diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/allocation.hpp --- a/src/share/vm/memory/allocation.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/allocation.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -611,4 +611,23 @@ void check() PRODUCT_RETURN; }; +// Helper class to allocate arrays that may become large. +// Uses the OS malloc for allocations smaller than ArrayAllocatorMallocLimit +// and uses mapped memory for larger allocations. +// Most OS mallocs do something similar but Solaris malloc does not revert +// to mapped memory for large allocations. By default ArrayAllocatorMallocLimit +// is set so that we always use malloc except for Solaris where we set the +// limit to get mapped memory. +template +class ArrayAllocator : StackObj { + char* _addr; + bool _use_malloc; + size_t _size; + public: + ArrayAllocator() : _addr(NULL), _use_malloc(false), _size(0) { } + ~ArrayAllocator() { free(); } + E* allocate(size_t length); + void free(); +}; + #endif // SHARE_VM_MEMORY_ALLOCATION_HPP diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/allocation.inline.hpp --- a/src/share/vm/memory/allocation.inline.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/allocation.inline.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 @@ -25,6 +25,7 @@ #ifndef SHARE_VM_MEMORY_ALLOCATION_INLINE_HPP #define SHARE_VM_MEMORY_ALLOCATION_INLINE_HPP +#include "runtime/atomic.inline.hpp" #include "runtime/os.hpp" // Explicit C-heap memory management @@ -107,5 +108,49 @@ FreeHeap(p, F); } +template +E* ArrayAllocator::allocate(size_t length) { + assert(_addr == NULL, "Already in use"); + + _size = sizeof(E) * length; + _use_malloc = _size < ArrayAllocatorMallocLimit; + + if (_use_malloc) { + _addr = AllocateHeap(_size, F); + if (_addr == NULL && _size >= (size_t)os::vm_allocation_granularity()) { + // malloc failed let's try with mmap instead + _use_malloc = false; + } else { + return (E*)_addr; + } + } + + int alignment = os::vm_allocation_granularity(); + _size = align_size_up(_size, alignment); + + _addr = os::reserve_memory(_size, NULL, alignment); + if (_addr == NULL) { + vm_exit_out_of_memory(_size, "Allocator (reserve)"); + } + + bool success = os::commit_memory(_addr, _size, false /* executable */); + if (!success) { + vm_exit_out_of_memory(_size, "Allocator (commit)"); + } + + return (E*)_addr; +} + +template +void ArrayAllocator::free() { + if (_addr != NULL) { + if (_use_malloc) { + FreeHeap(_addr, F); + } else { + os::release_memory(_addr, _size); + } + _addr = NULL; + } +} #endif // SHARE_VM_MEMORY_ALLOCATION_INLINE_HPP diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/cardTableModRefBS.cpp --- a/src/share/vm/memory/cardTableModRefBS.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/cardTableModRefBS.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -694,7 +694,7 @@ if (failed) { if (!failures) { tty->cr(); - tty->print_cr("== CT verification failed: ["PTR_FORMAT","PTR_FORMAT"]"); + tty->print_cr("== CT verification failed: ["PTR_FORMAT","PTR_FORMAT"]", start, end); tty->print_cr("== %sexpecting value: %d", (val_equals) ? "" : "not ", val); failures = true; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/cardTableRS.cpp --- a/src/share/vm/memory/cardTableRS.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/cardTableRS.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -353,7 +353,7 @@ assert(jp >= _begin && jp < _end, err_msg("Error: jp " PTR_FORMAT " should be within " "[_begin, _end) = [" PTR_FORMAT "," PTR_FORMAT ")", - _begin, _end)); + jp, _begin, _end)); oop obj = oopDesc::load_decode_heap_oop(p); guarantee(obj == NULL || (HeapWord*)obj >= _boundary, err_msg("pointer " PTR_FORMAT " at " PTR_FORMAT " on " diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/collectorPolicy.cpp --- a/src/share/vm/memory/collectorPolicy.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/collectorPolicy.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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) { @@ -620,7 +625,7 @@ const bool limit_exceeded = size_policy()->gc_overhead_limit_exceeded(); const bool softrefs_clear = all_soft_refs_clear(); - assert(!limit_exceeded || softrefs_clear, "Should have been cleared"); + if (limit_exceeded && softrefs_clear) { *gc_overhead_limit_was_exceeded = true; size_policy()->set_gc_overhead_limit_exceeded(false); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/filemap.cpp --- a/src/share/vm/memory/filemap.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/filemap.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/filemap.hpp --- a/src/share/vm/memory/filemap.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/filemap.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -112,12 +112,19 @@ char* region_base(int i) { return _header._space[i]._base; } struct FileMapHeader* header() { return &_header; } - static void set_current_info(FileMapInfo* info) { _current_info = info; } - static FileMapInfo* current_info() { return _current_info; } + static void set_current_info(FileMapInfo* info) { + CDS_ONLY(_current_info = info;) + } + + static FileMapInfo* current_info() { + CDS_ONLY(return _current_info;) + NOT_CDS(return NULL;) + } + static void assert_mark(bool check); // File manipulation. - bool initialize(); + bool initialize() NOT_CDS_RETURN_(false); bool open_for_read(); void open_for_write(); void write_header(); @@ -141,7 +148,7 @@ void fail_continue(const char *msg, ...); // Return true if given address is in the mapped shared space. - bool is_in_shared_space(const void* p); + bool is_in_shared_space(const void* p) NOT_CDS_RETURN_(false); }; #endif // SHARE_VM_MEMORY_FILEMAP_HPP diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/genCollectedHeap.cpp --- a/src/share/vm/memory/genCollectedHeap.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/genCollectedHeap.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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(); } @@ -822,12 +819,13 @@ // Returns "TRUE" iff "p" points into the committed areas of the heap. bool GenCollectedHeap::is_in(const void* p) const { #ifndef ASSERT - guarantee(VerifyBeforeGC || - VerifyDuringGC || - VerifyBeforeExit || - PrintAssembly || - tty->count() != 0 || // already printing - VerifyAfterGC || + guarantee(VerifyBeforeGC || + VerifyDuringGC || + VerifyBeforeExit || + VerifyDuringStartup || + PrintAssembly || + tty->count() != 0 || // already printing + VerifyAfterGC || VMError::fatal_error_in_progress(), "too expensive"); #endif @@ -1135,6 +1133,17 @@ #endif // INCLUDE_ALL_GCS } +void GenCollectedHeap::print_on_error(outputStream* st) const { + this->CollectedHeap::print_on_error(st); + +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + st->cr(); + CMSCollector::print_on_error(st); + } +#endif // INCLUDE_ALL_GCS +} + void GenCollectedHeap::print_tracing_info() const { if (TraceGen0Time) { get_gen(0)->print_summary_info(); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/genCollectedHeap.hpp --- a/src/share/vm/memory/genCollectedHeap.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/genCollectedHeap.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -344,6 +344,7 @@ virtual void print_gc_threads_on(outputStream* st) const; virtual void gc_threads_do(ThreadClosure* tc) const; virtual void print_tracing_info() const; + virtual void print_on_error(outputStream* st) const; // PrintGC, PrintGCDetails support void print_heap_change(size_t prev_used) const; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/generation.cpp --- a/src/share/vm/memory/generation.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/generation.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -382,7 +382,9 @@ CardGeneration::CardGeneration(ReservedSpace rs, size_t initial_byte_size, int level, GenRemSet* remset) : - Generation(rs, initial_byte_size, level), _rs(remset) + Generation(rs, initial_byte_size, level), _rs(remset), + _shrink_factor(0), _min_heap_delta_bytes(), _capacity_at_prologue(), + _used_at_prologue() { HeapWord* start = (HeapWord*)rs.base(); size_t reserved_byte_size = rs.size(); @@ -406,6 +408,9 @@ // the end if we try. guarantee(_rs->is_aligned(reserved_mr.end()), "generation must be card aligned"); } + _min_heap_delta_bytes = MinHeapDeltaBytes; + _capacity_at_prologue = initial_byte_size; + _used_at_prologue = 0; } bool CardGeneration::expand(size_t bytes, size_t expand_bytes) { @@ -457,6 +462,160 @@ } +void CardGeneration::compute_new_size() { + assert(_shrink_factor <= 100, "invalid shrink factor"); + size_t current_shrink_factor = _shrink_factor; + _shrink_factor = 0; + + // We don't have floating point command-line arguments + // Note: argument processing ensures that MinHeapFreeRatio < 100. + const double minimum_free_percentage = MinHeapFreeRatio / 100.0; + const double maximum_used_percentage = 1.0 - minimum_free_percentage; + + // Compute some numbers about the state of the heap. + const size_t used_after_gc = used(); + const size_t capacity_after_gc = capacity(); + + const double min_tmp = used_after_gc / maximum_used_percentage; + size_t minimum_desired_capacity = (size_t)MIN2(min_tmp, double(max_uintx)); + // Don't shrink less than the initial generation size + minimum_desired_capacity = MAX2(minimum_desired_capacity, + spec()->init_size()); + assert(used_after_gc <= minimum_desired_capacity, "sanity check"); + + if (PrintGC && Verbose) { + const size_t free_after_gc = free(); + const double free_percentage = ((double)free_after_gc) / capacity_after_gc; + gclog_or_tty->print_cr("TenuredGeneration::compute_new_size: "); + gclog_or_tty->print_cr(" " + " minimum_free_percentage: %6.2f" + " maximum_used_percentage: %6.2f", + minimum_free_percentage, + maximum_used_percentage); + gclog_or_tty->print_cr(" " + " free_after_gc : %6.1fK" + " used_after_gc : %6.1fK" + " capacity_after_gc : %6.1fK", + free_after_gc / (double) K, + used_after_gc / (double) K, + capacity_after_gc / (double) K); + gclog_or_tty->print_cr(" " + " free_percentage: %6.2f", + free_percentage); + } + + if (capacity_after_gc < minimum_desired_capacity) { + // If we have less free space than we want then expand + size_t expand_bytes = minimum_desired_capacity - capacity_after_gc; + // Don't expand unless it's significant + if (expand_bytes >= _min_heap_delta_bytes) { + expand(expand_bytes, 0); // safe if expansion fails + } + if (PrintGC && Verbose) { + gclog_or_tty->print_cr(" expanding:" + " minimum_desired_capacity: %6.1fK" + " expand_bytes: %6.1fK" + " _min_heap_delta_bytes: %6.1fK", + minimum_desired_capacity / (double) K, + expand_bytes / (double) K, + _min_heap_delta_bytes / (double) K); + } + return; + } + + // No expansion, now see if we want to shrink + size_t shrink_bytes = 0; + // We would never want to shrink more than this + size_t max_shrink_bytes = capacity_after_gc - minimum_desired_capacity; + + if (MaxHeapFreeRatio < 100) { + const double maximum_free_percentage = MaxHeapFreeRatio / 100.0; + const double minimum_used_percentage = 1.0 - maximum_free_percentage; + const double max_tmp = used_after_gc / minimum_used_percentage; + size_t maximum_desired_capacity = (size_t)MIN2(max_tmp, double(max_uintx)); + maximum_desired_capacity = MAX2(maximum_desired_capacity, + spec()->init_size()); + if (PrintGC && Verbose) { + gclog_or_tty->print_cr(" " + " maximum_free_percentage: %6.2f" + " minimum_used_percentage: %6.2f", + maximum_free_percentage, + minimum_used_percentage); + gclog_or_tty->print_cr(" " + " _capacity_at_prologue: %6.1fK" + " minimum_desired_capacity: %6.1fK" + " maximum_desired_capacity: %6.1fK", + _capacity_at_prologue / (double) K, + minimum_desired_capacity / (double) K, + maximum_desired_capacity / (double) K); + } + assert(minimum_desired_capacity <= maximum_desired_capacity, + "sanity check"); + + if (capacity_after_gc > maximum_desired_capacity) { + // Capacity too large, compute shrinking size + shrink_bytes = capacity_after_gc - maximum_desired_capacity; + // We don't want shrink all the way back to initSize if people call + // System.gc(), because some programs do that between "phases" and then + // we'd just have to grow the heap up again for the next phase. So we + // damp the shrinking: 0% on the first call, 10% on the second call, 40% + // on the third call, and 100% by the fourth call. But if we recompute + // size without shrinking, it goes back to 0%. + shrink_bytes = shrink_bytes / 100 * current_shrink_factor; + assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size"); + if (current_shrink_factor == 0) { + _shrink_factor = 10; + } else { + _shrink_factor = MIN2(current_shrink_factor * 4, (size_t) 100); + } + if (PrintGC && Verbose) { + gclog_or_tty->print_cr(" " + " shrinking:" + " initSize: %.1fK" + " maximum_desired_capacity: %.1fK", + spec()->init_size() / (double) K, + maximum_desired_capacity / (double) K); + gclog_or_tty->print_cr(" " + " shrink_bytes: %.1fK" + " current_shrink_factor: %d" + " new shrink factor: %d" + " _min_heap_delta_bytes: %.1fK", + shrink_bytes / (double) K, + current_shrink_factor, + _shrink_factor, + _min_heap_delta_bytes / (double) K); + } + } + } + + if (capacity_after_gc > _capacity_at_prologue) { + // We might have expanded for promotions, in which case we might want to + // take back that expansion if there's room after GC. That keeps us from + // stretching the heap with promotions when there's plenty of room. + size_t expansion_for_promotion = capacity_after_gc - _capacity_at_prologue; + expansion_for_promotion = MIN2(expansion_for_promotion, max_shrink_bytes); + // We have two shrinking computations, take the largest + shrink_bytes = MAX2(shrink_bytes, expansion_for_promotion); + assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size"); + if (PrintGC && Verbose) { + gclog_or_tty->print_cr(" " + " aggressive shrinking:" + " _capacity_at_prologue: %.1fK" + " capacity_after_gc: %.1fK" + " expansion_for_promotion: %.1fK" + " shrink_bytes: %.1fK", + capacity_after_gc / (double) K, + _capacity_at_prologue / (double) K, + expansion_for_promotion / (double) K, + shrink_bytes / (double) K); + } + } + // Don't shrink unless it's significant + if (shrink_bytes >= _min_heap_delta_bytes) { + shrink(shrink_bytes); + } +} + // Currently nothing to do. void CardGeneration::prepare_for_verify() {} diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/generation.hpp --- a/src/share/vm/memory/generation.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/generation.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -634,6 +634,17 @@ // This is local to this generation. BlockOffsetSharedArray* _bts; + // current shrinking effect: this damps shrinking when the heap gets empty. + size_t _shrink_factor; + + size_t _min_heap_delta_bytes; // Minimum amount to expand. + + // Some statistics from before gc started. + // These are gathered in the gc_prologue (and should_collect) + // to control growing/shrinking policy in spite of promotions. + size_t _capacity_at_prologue; + size_t _used_at_prologue; + CardGeneration(ReservedSpace rs, size_t initial_byte_size, int level, GenRemSet* remset); @@ -644,6 +655,11 @@ // necessarily the full "bytes") was done. virtual bool expand(size_t bytes, size_t expand_bytes); + // Shrink generation with specified size (returns false if unable to shrink) + virtual void shrink(size_t bytes) = 0; + + virtual void compute_new_size(); + virtual void clear_remembered_set(); virtual void invalidate_remembered_set(); @@ -667,7 +683,6 @@ friend class VM_PopulateDumpSharedSpace; protected: - size_t _min_heap_delta_bytes; // Minimum amount to expand. ContiguousSpace* _the_space; // actual space holding objects WaterMark _last_gc; // watermark between objects allocated before // and after last GC. @@ -688,11 +703,10 @@ public: OneContigSpaceCardGeneration(ReservedSpace rs, size_t initial_byte_size, - size_t min_heap_delta_bytes, int level, GenRemSet* remset, ContiguousSpace* space) : CardGeneration(rs, initial_byte_size, level, remset), - _the_space(space), _min_heap_delta_bytes(min_heap_delta_bytes) + _the_space(space) {} inline bool is_in(const void* p) const; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/heap.cpp --- a/src/share/vm/memory/heap.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/heap.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/metablock.cpp --- a/src/share/vm/memory/metablock.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/metablock.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/metaspace.cpp --- a/src/share/vm/memory/metaspace.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/metaspace.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -52,7 +52,6 @@ const uint metadata_deallocate_a_lot_block = 10; const uint metadata_deallocate_a_lock_chunk = 3; size_t const allocation_from_dictionary_limit = 64 * K; -const size_t metadata_deallocate = 0xf5f5f5f5; MetaWord* last_allocated = 0; @@ -335,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); @@ -1101,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 @@ -1309,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"); } @@ -1970,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); @@ -1987,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 @@ -2440,7 +2432,8 @@ free_chunks_capacity_bytes / K, used_and_free / K, capacity_bytes / K); - assert(used_and_free == capacity_bytes, "Accounting is wrong"); + // Accounting can only be correct if we got the values during a safepoint + assert(!SafepointSynchronize::is_at_safepoint() || used_and_free == capacity_bytes, "Accounting is wrong"); } // Print total fragmentation for class and data metaspaces separately diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/metaspace.hpp diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/metaspaceCounters.cpp --- a/src/share/vm/memory/metaspaceCounters.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/metaspaceCounters.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -25,12 +25,14 @@ #include "precompiled.hpp" #include "memory/metaspaceCounters.hpp" #include "memory/resourceArea.hpp" - -#define METASPACE_NAME "perm" +#include "utilities/exceptions.hpp" MetaspaceCounters* MetaspaceCounters::_metaspace_counters = NULL; -MetaspaceCounters::MetaspaceCounters() { +MetaspaceCounters::MetaspaceCounters() : + _capacity(NULL), + _used(NULL), + _max_capacity(NULL) { if (UsePerfData) { size_t min_capacity = MetaspaceAux::min_chunk_size(); size_t max_capacity = MetaspaceAux::reserved_in_bytes(); @@ -41,6 +43,25 @@ } } +static PerfVariable* create_ms_variable(const char *ns, + const char *name, + size_t value, + TRAPS) { + const char *path = PerfDataManager::counter_name(ns, name); + PerfVariable *result = + PerfDataManager::create_variable(SUN_GC, path, PerfData::U_Bytes, value, + CHECK_NULL); + return result; +} + +static void create_ms_constant(const char *ns, + const char *name, + size_t value, + TRAPS) { + const char *path = PerfDataManager::counter_name(ns, name); + PerfDataManager::create_constant(SUN_GC, path, PerfData::U_Bytes, value, CHECK); +} + void MetaspaceCounters::initialize(size_t min_capacity, size_t max_capacity, size_t curr_capacity, @@ -50,93 +71,32 @@ EXCEPTION_MARK; ResourceMark rm; - // Create a name that will be recognized by jstat tools as - // the perm gen. Change this to a Metaspace name when the - // tools are fixed. - // name to recognize "sun.gc.generation.2.*" - - const char* name = METASPACE_NAME; - const int ordinal = 2; - const int spaces = 1; - - const char* cns = PerfDataManager::name_space("generation", ordinal); - - _name_space = NEW_C_HEAP_ARRAY(char, strlen(cns)+1, mtClass); - strcpy(_name_space, cns); - - const char* cname = PerfDataManager::counter_name(_name_space, "name"); - PerfDataManager::create_string_constant(SUN_GC, cname, name, CHECK); - - // End of perm gen like name creation - - cname = PerfDataManager::counter_name(_name_space, "spaces"); - PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_None, - spaces, CHECK); - - cname = PerfDataManager::counter_name(_name_space, "minCapacity"); - PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_Bytes, - min_capacity, CHECK); - - cname = PerfDataManager::counter_name(_name_space, "maxCapacity"); - PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_Bytes, - max_capacity, CHECK); + const char *ms = "metaspace"; - cname = PerfDataManager::counter_name(_name_space, "capacity"); - _current_size = - PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, - curr_capacity, CHECK); - - // SpaceCounter like counters - // name to recognize "sun.gc.generation.2.space.0.*" - { - const int space_ordinal = 0; - const char* cns = PerfDataManager::name_space(_name_space, "space", - space_ordinal); - - char* space_name_space = NEW_C_HEAP_ARRAY(char, strlen(cns)+1, mtClass); - strcpy(space_name_space, cns); - - const char* cname = PerfDataManager::counter_name(space_name_space, "name"); - PerfDataManager::create_string_constant(SUN_GC, cname, name, CHECK); - - cname = PerfDataManager::counter_name(space_name_space, "maxCapacity"); - _max_capacity = PerfDataManager::create_variable(SUN_GC, cname, - PerfData::U_Bytes, - (jlong)max_capacity, CHECK); - - cname = PerfDataManager::counter_name(space_name_space, "capacity"); - _capacity = PerfDataManager::create_variable(SUN_GC, cname, - PerfData::U_Bytes, - curr_capacity, CHECK); - - cname = PerfDataManager::counter_name(space_name_space, "used"); - _used = PerfDataManager::create_variable(SUN_GC, - cname, - PerfData::U_Bytes, - used, - CHECK); - - cname = PerfDataManager::counter_name(space_name_space, "initCapacity"); - PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_Bytes, - min_capacity, CHECK); - } + create_ms_constant(ms, "minCapacity", min_capacity, CHECK); + _max_capacity = create_ms_variable(ms, "maxCapacity", max_capacity, CHECK); + _capacity = create_ms_variable(ms, "capacity", curr_capacity, CHECK); + _used = create_ms_variable(ms, "used", used, CHECK); } } void MetaspaceCounters::update_capacity() { assert(UsePerfData, "Should not be called unless being used"); + assert(_capacity != NULL, "Should be initialized"); size_t capacity_in_bytes = MetaspaceAux::capacity_in_bytes(); _capacity->set_value(capacity_in_bytes); } void MetaspaceCounters::update_used() { assert(UsePerfData, "Should not be called unless being used"); + assert(_used != NULL, "Should be initialized"); size_t used_in_bytes = MetaspaceAux::used_in_bytes(); _used->set_value(used_in_bytes); } void MetaspaceCounters::update_max_capacity() { assert(UsePerfData, "Should not be called unless being used"); + assert(_max_capacity != NULL, "Should be initialized"); size_t reserved_in_bytes = MetaspaceAux::reserved_in_bytes(); _max_capacity->set_value(reserved_in_bytes); } @@ -146,18 +106,19 @@ update_used(); update_capacity(); update_max_capacity(); - _current_size->set_value(MetaspaceAux::reserved_in_bytes()); } } void MetaspaceCounters::initialize_performance_counters() { if (UsePerfData) { + assert(_metaspace_counters == NULL, "Should only be initialized once"); _metaspace_counters = new MetaspaceCounters(); } } void MetaspaceCounters::update_performance_counters() { if (UsePerfData) { + assert(_metaspace_counters != NULL, "Should be initialized"); _metaspace_counters->update_all(); } } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/metaspaceCounters.hpp --- a/src/share/vm/memory/metaspaceCounters.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/metaspaceCounters.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -29,11 +29,9 @@ class MetaspaceCounters: public CHeapObj { friend class VMStructs; - PerfVariable* _current_size; PerfVariable* _capacity; PerfVariable* _used; PerfVariable* _max_capacity; - char* _name_space; static MetaspaceCounters* _metaspace_counters; void initialize(size_t min_capacity, size_t max_capacity, diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/sharedHeap.cpp --- a/src/share/vm/memory/sharedHeap.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/sharedHeap.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/tenuredGeneration.cpp --- a/src/share/vm/memory/tenuredGeneration.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/tenuredGeneration.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -39,7 +39,7 @@ size_t initial_byte_size, int level, GenRemSet* remset) : OneContigSpaceCardGeneration(rs, initial_byte_size, - MinHeapDeltaBytes, level, remset, NULL) + level, remset, NULL) { HeapWord* bottom = (HeapWord*) _virtual_space.low(); HeapWord* end = (HeapWord*) _virtual_space.high(); @@ -86,162 +86,6 @@ return "tenured generation"; } -void TenuredGeneration::compute_new_size() { - assert(_shrink_factor <= 100, "invalid shrink factor"); - size_t current_shrink_factor = _shrink_factor; - _shrink_factor = 0; - - // We don't have floating point command-line arguments - // Note: argument processing ensures that MinHeapFreeRatio < 100. - const double minimum_free_percentage = MinHeapFreeRatio / 100.0; - const double maximum_used_percentage = 1.0 - minimum_free_percentage; - - // Compute some numbers about the state of the heap. - const size_t used_after_gc = used(); - const size_t capacity_after_gc = capacity(); - - const double min_tmp = used_after_gc / maximum_used_percentage; - size_t minimum_desired_capacity = (size_t)MIN2(min_tmp, double(max_uintx)); - // Don't shrink less than the initial generation size - minimum_desired_capacity = MAX2(minimum_desired_capacity, - spec()->init_size()); - assert(used_after_gc <= minimum_desired_capacity, "sanity check"); - - if (PrintGC && Verbose) { - const size_t free_after_gc = free(); - const double free_percentage = ((double)free_after_gc) / capacity_after_gc; - gclog_or_tty->print_cr("TenuredGeneration::compute_new_size: "); - gclog_or_tty->print_cr(" " - " minimum_free_percentage: %6.2f" - " maximum_used_percentage: %6.2f", - minimum_free_percentage, - maximum_used_percentage); - gclog_or_tty->print_cr(" " - " free_after_gc : %6.1fK" - " used_after_gc : %6.1fK" - " capacity_after_gc : %6.1fK", - free_after_gc / (double) K, - used_after_gc / (double) K, - capacity_after_gc / (double) K); - gclog_or_tty->print_cr(" " - " free_percentage: %6.2f", - free_percentage); - } - - if (capacity_after_gc < minimum_desired_capacity) { - // If we have less free space than we want then expand - size_t expand_bytes = minimum_desired_capacity - capacity_after_gc; - // Don't expand unless it's significant - if (expand_bytes >= _min_heap_delta_bytes) { - expand(expand_bytes, 0); // safe if expansion fails - } - if (PrintGC && Verbose) { - gclog_or_tty->print_cr(" expanding:" - " minimum_desired_capacity: %6.1fK" - " expand_bytes: %6.1fK" - " _min_heap_delta_bytes: %6.1fK", - minimum_desired_capacity / (double) K, - expand_bytes / (double) K, - _min_heap_delta_bytes / (double) K); - } - return; - } - - // No expansion, now see if we want to shrink - size_t shrink_bytes = 0; - // We would never want to shrink more than this - size_t max_shrink_bytes = capacity_after_gc - minimum_desired_capacity; - - if (MaxHeapFreeRatio < 100) { - const double maximum_free_percentage = MaxHeapFreeRatio / 100.0; - const double minimum_used_percentage = 1.0 - maximum_free_percentage; - const double max_tmp = used_after_gc / minimum_used_percentage; - size_t maximum_desired_capacity = (size_t)MIN2(max_tmp, double(max_uintx)); - maximum_desired_capacity = MAX2(maximum_desired_capacity, - spec()->init_size()); - if (PrintGC && Verbose) { - gclog_or_tty->print_cr(" " - " maximum_free_percentage: %6.2f" - " minimum_used_percentage: %6.2f", - maximum_free_percentage, - minimum_used_percentage); - gclog_or_tty->print_cr(" " - " _capacity_at_prologue: %6.1fK" - " minimum_desired_capacity: %6.1fK" - " maximum_desired_capacity: %6.1fK", - _capacity_at_prologue / (double) K, - minimum_desired_capacity / (double) K, - maximum_desired_capacity / (double) K); - } - assert(minimum_desired_capacity <= maximum_desired_capacity, - "sanity check"); - - if (capacity_after_gc > maximum_desired_capacity) { - // Capacity too large, compute shrinking size - shrink_bytes = capacity_after_gc - maximum_desired_capacity; - // We don't want shrink all the way back to initSize if people call - // System.gc(), because some programs do that between "phases" and then - // we'd just have to grow the heap up again for the next phase. So we - // damp the shrinking: 0% on the first call, 10% on the second call, 40% - // on the third call, and 100% by the fourth call. But if we recompute - // size without shrinking, it goes back to 0%. - shrink_bytes = shrink_bytes / 100 * current_shrink_factor; - assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size"); - if (current_shrink_factor == 0) { - _shrink_factor = 10; - } else { - _shrink_factor = MIN2(current_shrink_factor * 4, (size_t) 100); - } - if (PrintGC && Verbose) { - gclog_or_tty->print_cr(" " - " shrinking:" - " initSize: %.1fK" - " maximum_desired_capacity: %.1fK", - spec()->init_size() / (double) K, - maximum_desired_capacity / (double) K); - gclog_or_tty->print_cr(" " - " shrink_bytes: %.1fK" - " current_shrink_factor: %d" - " new shrink factor: %d" - " _min_heap_delta_bytes: %.1fK", - shrink_bytes / (double) K, - current_shrink_factor, - _shrink_factor, - _min_heap_delta_bytes / (double) K); - } - } - } - - if (capacity_after_gc > _capacity_at_prologue) { - // We might have expanded for promotions, in which case we might want to - // take back that expansion if there's room after GC. That keeps us from - // stretching the heap with promotions when there's plenty of room. - size_t expansion_for_promotion = capacity_after_gc - _capacity_at_prologue; - expansion_for_promotion = MIN2(expansion_for_promotion, max_shrink_bytes); - // We have two shrinking computations, take the largest - shrink_bytes = MAX2(shrink_bytes, expansion_for_promotion); - assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size"); - if (PrintGC && Verbose) { - gclog_or_tty->print_cr(" " - " aggressive shrinking:" - " _capacity_at_prologue: %.1fK" - " capacity_after_gc: %.1fK" - " expansion_for_promotion: %.1fK" - " shrink_bytes: %.1fK", - capacity_after_gc / (double) K, - _capacity_at_prologue / (double) K, - expansion_for_promotion / (double) K, - shrink_bytes / (double) K); - } - } - // Don't shrink unless it's significant - if (shrink_bytes >= _min_heap_delta_bytes) { - shrink(shrink_bytes); - } - assert(used() == used_after_gc && used_after_gc <= capacity(), - "sanity check"); -} - void TenuredGeneration::gc_prologue(bool full) { _capacity_at_prologue = capacity(); _used_at_prologue = used(); @@ -312,6 +156,19 @@ size, is_tlab); } +void TenuredGeneration::compute_new_size() { + assert_locked_or_safepoint(Heap_lock); + + // Compute some numbers about the state of the heap. + const size_t used_after_gc = used(); + const size_t capacity_after_gc = capacity(); + + CardGeneration::compute_new_size(); + + assert(used() == used_after_gc && used_after_gc <= capacity(), + err_msg("used: " SIZE_FORMAT " used_after_gc: " SIZE_FORMAT + " capacity: " SIZE_FORMAT, used(), used_after_gc, capacity())); +} void TenuredGeneration::update_gc_stats(int current_level, bool full) { // If the next lower level(s) has been collected, gather any statistics diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/tenuredGeneration.hpp --- a/src/share/vm/memory/tenuredGeneration.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/tenuredGeneration.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -38,13 +38,6 @@ class TenuredGeneration: public OneContigSpaceCardGeneration { friend class VMStructs; protected: - // current shrinking effect: this damps shrinking when the heap gets empty. - size_t _shrink_factor; - // Some statistics from before gc started. - // These are gathered in the gc_prologue (and should_collect) - // to control growing/shrinking policy in spite of promotions. - size_t _capacity_at_prologue; - size_t _used_at_prologue; #if INCLUDE_ALL_GCS // To support parallel promotion: an array of parallel allocation @@ -80,9 +73,6 @@ return !CollectGen0First; } - // Mark sweep support - void compute_new_size(); - virtual void gc_prologue(bool full); virtual void gc_epilogue(bool full); bool should_collect(bool full, @@ -93,6 +83,7 @@ bool clear_all_soft_refs, size_t size, bool is_tlab); + virtual void compute_new_size(); #if INCLUDE_ALL_GCS // Overrides. diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/memory/universe.cpp --- a/src/share/vm/memory/universe.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/memory/universe.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -885,6 +885,8 @@ // the actual alignment depends on its size. Universe::set_class_metaspace_size(align_size_up(ClassMetaspaceSize, alignment)); size_t total_reserved = align_size_up(heap_size + Universe::class_metaspace_size(), alignment); + assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())), + "heap size is too big for compressed oops"); char* addr = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); ReservedHeapSpace total_rs(total_reserved, alignment, UseLargePages, addr); @@ -951,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 - } } @@ -1333,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) { @@ -1367,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/constMethod.cpp --- a/src/share/vm/oops/constMethod.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/constMethod.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -55,11 +55,24 @@ set_stackmap_data(NULL); set_code_size(byte_code_size); set_constMethod_size(size); - set_inlined_tables_length(sizes); + set_inlined_tables_length(sizes); // sets _flags set_method_type(method_type); assert(this->size() == size, "wrong size for object"); + set_name_index(0); + set_signature_index(0); + set_constants(NULL); + set_max_stack(0); + set_max_locals(0); + set_method_idnum(0); + set_size_of_parameters(0); } +// Accessor that copies to metadata. +void ConstMethod::copy_stackmap_data(ClassLoaderData* loader_data, + u1* sd, int length, TRAPS) { + _stackmap_data = MetadataFactory::new_array(loader_data, length, CHECK); + memcpy((void*)_stackmap_data->adr_at(0), (void*)sd, length); +} // Deallocate metadata fields associated with ConstMethod* void ConstMethod::deallocate_contents(ClassLoaderData* loader_data) { @@ -350,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/constMethod.hpp --- a/src/share/vm/oops/constMethod.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/constMethod.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -280,6 +280,7 @@ // stackmap table data Array* stackmap_data() const { return _stackmap_data; } void set_stackmap_data(Array* sd) { _stackmap_data = sd; } + void copy_stackmap_data(ClassLoaderData* loader_data, u1* sd, int length, TRAPS); bool has_stackmap_table() const { return _stackmap_data != NULL; } void init_fingerprint() { @@ -440,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/constantPool.cpp --- a/src/share/vm/oops/constantPool.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/constantPool.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/cpCache.cpp --- a/src/share/vm/oops/cpCache.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/cpCache.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -44,6 +44,8 @@ void ConstantPoolCacheEntry::initialize_entry(int index) { assert(0 < index && index < 0x10000, "sanity check"); _indices = index; + _f1 = NULL; + _f2 = _flags = 0; assert(constant_pool_index() == index, ""); } @@ -533,13 +535,17 @@ // Implementation of ConstantPoolCache -ConstantPoolCache* ConstantPoolCache::allocate(ClassLoaderData* loader_data, int length, TRAPS) { +ConstantPoolCache* ConstantPoolCache::allocate(ClassLoaderData* loader_data, + int length, + const intStack& index_map, + const intStack& invokedynamic_map, TRAPS) { int size = ConstantPoolCache::size(length); - return new (loader_data, size, false, THREAD) ConstantPoolCache(length); + return new (loader_data, size, false, THREAD) ConstantPoolCache(length, index_map, invokedynamic_map); } -void ConstantPoolCache::initialize(intArray& inverse_index_map, intArray& invokedynamic_references_map) { +void ConstantPoolCache::initialize(const intArray& inverse_index_map, + const intArray& invokedynamic_references_map) { assert(inverse_index_map.length() == length(), "inverse index map must have same length as cache"); for (int i = 0; i < length(); i++) { ConstantPoolCacheEntry* e = entry_at(i); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/cpCache.hpp --- a/src/share/vm/oops/cpCache.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/cpCache.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -377,14 +377,21 @@ debug_only(friend class ClassVerifier;) // Constructor - ConstantPoolCache(int length) : _length(length), _constant_pool(NULL) { + ConstantPoolCache(int length, const intStack& inverse_index_map, + const intStack& invokedynamic_references_map) : + _length(length), _constant_pool(NULL) { + initialize(inverse_index_map, invokedynamic_references_map); for (int i = 0; i < length; i++) { assert(entry_at(i)->is_f1_null(), "Failed to clear?"); } } + // Initialization + void initialize(const intArray& inverse_index_map, const intArray& invokedynamic_references_map); public: - static ConstantPoolCache* allocate(ClassLoaderData* loader_data, int length, TRAPS); + static ConstantPoolCache* allocate(ClassLoaderData* loader_data, int length, + const intStack& inverse_index_map, + const intStack& invokedynamic_references_map, TRAPS); bool is_constantPoolCache() const { return true; } int length() const { return _length; } @@ -405,9 +412,6 @@ friend class ConstantPoolCacheEntry; public: - // Initialization - void initialize(intArray& inverse_index_map, intArray& invokedynamic_references_map); - // Accessors void set_constant_pool(ConstantPool* pool) { _constant_pool = pool; } ConstantPool* constant_pool() const { return _constant_pool; } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/fieldInfo.hpp --- a/src/share/vm/oops/fieldInfo.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/fieldInfo.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/generateOopMap.cpp --- a/src/share/vm/oops/generateOopMap.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/generateOopMap.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/instanceKlass.cpp --- a/src/share/vm/oops/instanceKlass.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/instanceKlass.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -165,7 +165,8 @@ volatile int InstanceKlass::_total_instanceKlass_count = 0; -Klass* InstanceKlass::allocate_instance_klass(ClassLoaderData* loader_data, +InstanceKlass* InstanceKlass::allocate_instance_klass( + ClassLoaderData* loader_data, int vtable_len, int itable_len, int static_field_size, @@ -207,10 +208,35 @@ access_flags, is_anonymous); } + // Check for pending exception before adding to the loader data and incrementing + // class count. Can get OOM here. + if (HAS_PENDING_EXCEPTION) { + return NULL; + } + + // Add all classes to our internal class loader list here, + // including classes in the bootstrap (NULL) class loader. + loader_data->add_class(ik); + Atomic::inc(&_total_instanceKlass_count); return ik; } + +// copy method ordering from resource area to Metaspace +void InstanceKlass::copy_method_ordering(intArray* m, TRAPS) { + if (m != NULL) { + // allocate a new array and copy contents (memcpy?) + _method_ordering = MetadataFactory::new_array(class_loader_data(), m->length(), CHECK); + for (int i = 0; i < m->length(); i++) { + _method_ordering->at_put(i, m->at(i)); + } + } else { + _method_ordering = Universe::the_empty_int_array(); + } +} + + InstanceKlass::InstanceKlass(int vtable_len, int itable_len, int static_field_size, @@ -220,72 +246,116 @@ bool is_anonymous) { No_Safepoint_Verifier no_safepoint; // until k becomes parsable - int size = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size, - access_flags.is_interface(), is_anonymous); - - // The sizes of these these three variables are used for determining the - // size of the instanceKlassOop. It is critical that these are set to the right - // sizes before the first GC, i.e., when we allocate the mirror. - this->set_vtable_length(vtable_len); - this->set_itable_length(itable_len); - this->set_static_field_size(static_field_size); - this->set_nonstatic_oop_map_size(nonstatic_oop_map_size); - this->set_access_flags(access_flags); - this->set_is_anonymous(is_anonymous); - assert(this->size() == size, "wrong size for object"); - - this->set_array_klasses(NULL); - this->set_methods(NULL); - this->set_method_ordering(NULL); - this->set_local_interfaces(NULL); - this->set_transitive_interfaces(NULL); - this->init_implementor(); - this->set_fields(NULL, 0); - this->set_constants(NULL); - this->set_class_loader_data(NULL); - this->set_protection_domain(NULL); - this->set_signers(NULL); - this->set_source_file_name(NULL); - this->set_source_debug_extension(NULL, 0); - this->set_array_name(NULL); - this->set_inner_classes(NULL); - this->set_static_oop_field_count(0); - this->set_nonstatic_field_size(0); - this->set_is_marked_dependent(false); - this->set_init_state(InstanceKlass::allocated); - this->set_init_thread(NULL); - this->set_init_lock(NULL); - this->set_reference_type(rt); - this->set_oop_map_cache(NULL); - this->set_jni_ids(NULL); - this->set_osr_nmethods_head(NULL); - this->set_breakpoints(NULL); - this->init_previous_versions(); - this->set_generic_signature(NULL); - this->release_set_methods_jmethod_ids(NULL); - this->release_set_methods_cached_itable_indices(NULL); - this->set_annotations(NULL); - this->set_jvmti_cached_class_field_map(NULL); - this->set_initial_method_idnum(0); + int iksize = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size, + access_flags.is_interface(), is_anonymous); + + set_vtable_length(vtable_len); + set_itable_length(itable_len); + set_static_field_size(static_field_size); + set_nonstatic_oop_map_size(nonstatic_oop_map_size); + set_access_flags(access_flags); + _misc_flags = 0; // initialize to zero + set_is_anonymous(is_anonymous); + assert(size() == iksize, "wrong size for object"); + + set_array_klasses(NULL); + set_methods(NULL); + set_method_ordering(NULL); + set_local_interfaces(NULL); + set_transitive_interfaces(NULL); + init_implementor(); + set_fields(NULL, 0); + set_constants(NULL); + set_class_loader_data(NULL); + set_protection_domain(NULL); + set_signers(NULL); + set_source_file_name(NULL); + set_source_debug_extension(NULL, 0); + set_array_name(NULL); + set_inner_classes(NULL); + set_static_oop_field_count(0); + set_nonstatic_field_size(0); + set_is_marked_dependent(false); + set_init_state(InstanceKlass::allocated); + set_init_thread(NULL); + set_init_lock(NULL); + set_reference_type(rt); + set_oop_map_cache(NULL); + set_jni_ids(NULL); + set_osr_nmethods_head(NULL); + set_breakpoints(NULL); + init_previous_versions(); + set_generic_signature(NULL); + release_set_methods_jmethod_ids(NULL); + release_set_methods_cached_itable_indices(NULL); + set_annotations(NULL); + set_jvmti_cached_class_field_map(NULL); + set_initial_method_idnum(0); + _dependencies = NULL; + set_jvmti_cached_class_field_map(NULL); + set_cached_class_file(NULL, 0); + set_initial_method_idnum(0); + set_minor_version(0); + set_major_version(0); + NOT_PRODUCT(_verify_count = 0;) // initialize the non-header words to zero intptr_t* p = (intptr_t*)this; - for (int index = InstanceKlass::header_size(); index < size; index++) { + for (int index = InstanceKlass::header_size(); index < iksize; index++) { p[index] = NULL_WORD; } // Set temporary value until parseClassFile updates it with the real instance // size. - this->set_layout_helper(Klass::instance_layout_helper(0, true)); + set_layout_helper(Klass::instance_layout_helper(0, true)); +} + + +void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data, + Array* methods) { + if (methods != NULL && methods != Universe::the_empty_method_array()) { + for (int i = 0; i < methods->length(); i++) { + Method* method = methods->at(i); + if (method == NULL) continue; // maybe null if error processing + // Only want to delete methods that are not executing for RedefineClasses. + // The previous version will point to them so they're not totally dangling + assert (!method->on_stack(), "shouldn't be called with methods on stack"); + MetadataFactory::free_metadata(loader_data, method); + } + MetadataFactory::free_array(loader_data, methods); + } } +void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data, + Klass* super_klass, + Array* local_interfaces, + Array* transitive_interfaces) { + // Only deallocate transitive interfaces if not empty, same as super class + // or same as local interfaces. See code in parseClassFile. + Array* ti = transitive_interfaces; + if (ti != Universe::the_empty_klass_array() && ti != local_interfaces) { + // check that the interfaces don't come from super class + Array* sti = (super_klass == NULL) ? NULL : + InstanceKlass::cast(super_klass)->transitive_interfaces(); + if (ti != sti) { + MetadataFactory::free_array(loader_data, ti); + } + } + + // local interfaces can be empty + if (local_interfaces != Universe::the_empty_klass_array()) { + MetadataFactory::free_array(loader_data, local_interfaces); + } +} // This function deallocates the metadata and C heap pointers that the // InstanceKlass points to. void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { // Orphan the mirror first, CMS thinks it's still live. - java_lang_Class::set_klass(java_mirror(), NULL); + if (java_mirror() != NULL) { + java_lang_Class::set_klass(java_mirror(), NULL); + } // Need to take this class off the class loader data list. loader_data->remove_class(this); @@ -300,17 +370,7 @@ // reference counting symbol names. release_C_heap_structures(); - Array* ms = methods(); - if (ms != Universe::the_empty_method_array()) { - for (int i = 0; i <= methods()->length() -1 ; i++) { - Method* method = methods()->at(i); - // Only want to delete methods that are not executing for RedefineClasses. - // The previous version will point to them so they're not totally dangling - assert (!method->on_stack(), "shouldn't be called with methods on stack"); - MetadataFactory::free_metadata(loader_data, method); - } - MetadataFactory::free_array(loader_data, methods()); - } + deallocate_methods(loader_data, methods()); set_methods(NULL); if (method_ordering() != Universe::the_empty_int_array()) { @@ -327,24 +387,8 @@ } set_secondary_supers(NULL); - // Only deallocate transitive interfaces if not empty, same as super class - // or same as local interfaces. See code in parseClassFile. - Array* ti = transitive_interfaces(); - if (ti != Universe::the_empty_klass_array() && ti != local_interfaces()) { - // check that the interfaces don't come from super class - Array* sti = (super() == NULL) ? NULL : - InstanceKlass::cast(super())->transitive_interfaces(); - if (ti != sti) { - MetadataFactory::free_array(loader_data, ti); - } - } + deallocate_interfaces(loader_data, super(), local_interfaces(), transitive_interfaces()); set_transitive_interfaces(NULL); - - // local interfaces can be empty - Array* li = local_interfaces(); - if (li != Universe::the_empty_klass_array()) { - MetadataFactory::free_array(loader_data, li); - } set_local_interfaces(NULL); MetadataFactory::free_array(loader_data, fields()); @@ -352,9 +396,11 @@ // If a method from a redefined class is using this constant pool, don't // delete it, yet. The new class's previous version will point to this. - assert (!constants()->on_stack(), "shouldn't be called if anything is onstack"); - MetadataFactory::free_metadata(loader_data, constants()); - set_constants(NULL); + if (constants() != NULL) { + assert (!constants()->on_stack(), "shouldn't be called if anything is onstack"); + MetadataFactory::free_metadata(loader_data, constants()); + set_constants(NULL); + } if (inner_classes() != Universe::the_empty_short_array()) { MetadataFactory::free_array(loader_data, inner_classes()); @@ -2170,7 +2216,11 @@ if (impl != NULL) { if (!impl->is_loader_alive(is_alive)) { // remove this guy - *adr_implementor() = NULL; + Klass** klass = adr_implementor(); + assert(klass != NULL, "null klass"); + if (klass != NULL) { + *klass = NULL; + } } } } @@ -2178,8 +2228,6 @@ } void InstanceKlass::clean_method_data(BoolObjectClosure* is_alive) { -#if defined(COMPILER2) || defined(GRAAL) - // Currently only used by C2 and Graal for (int m = 0; m < methods()->length(); m++) { MethodData* mdo = methods()->at(m)->method_data(); if (mdo != NULL) { @@ -2190,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 } @@ -2781,7 +2820,7 @@ st->print(BULLET"protection domain: "); ((InstanceKlass*)this)->protection_domain()->print_value_on(st); st->cr(); st->print(BULLET"host class: "); host_klass()->print_value_on_maybe_null(st); st->cr(); st->print(BULLET"signers: "); signers()->print_value_on(st); st->cr(); - st->print(BULLET"init_lock: "); ((oop)init_lock())->print_value_on(st); st->cr(); + st->print(BULLET"init_lock: "); ((oop)_init_lock)->print_value_on(st); st->cr(); if (source_file_name() != NULL) { st->print(BULLET"source file: "); source_file_name()->print_value_on(st); @@ -2911,7 +2950,7 @@ } } -#endif +#endif //PRODUCT void InstanceKlass::oop_print_value_on(oop obj, outputStream* st) { st->print("a "); @@ -3118,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/instanceKlass.hpp --- a/src/share/vm/oops/instanceKlass.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/instanceKlass.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -147,7 +147,8 @@ AccessFlags access_flags, bool is_anonymous); public: - static Klass* allocate_instance_klass(ClassLoaderData* loader_data, + static InstanceKlass* allocate_instance_klass( + ClassLoaderData* loader_data, int vtable_len, int itable_len, int static_field_size, @@ -266,8 +267,9 @@ u1 _init_state; // state of class u1 _reference_type; // reference type + JvmtiCachedClassFieldMap* _jvmti_cached_class_field_map; // JVMTI: used during heap iteration - JvmtiCachedClassFieldMap* _jvmti_cached_class_field_map; // JVMTI: used during heap iteration + NOT_PRODUCT(int _verify_count;) // to avoid redundant verifies // Method array. Array* _methods; @@ -356,16 +358,19 @@ // method ordering Array* method_ordering() const { return _method_ordering; } void set_method_ordering(Array* m) { _method_ordering = m; } + void copy_method_ordering(intArray* m, TRAPS); // interfaces Array* local_interfaces() const { return _local_interfaces; } void set_local_interfaces(Array* a) { guarantee(_local_interfaces == NULL || a == NULL, "Just checking"); _local_interfaces = a; } + Array* transitive_interfaces() const { return _transitive_interfaces; } void set_transitive_interfaces(Array* a) { guarantee(_transitive_interfaces == NULL || a == NULL, "Just checking"); - _transitive_interfaces = a; } + _transitive_interfaces = a; + } private: friend class fieldDescriptor; @@ -381,10 +386,9 @@ int java_fields_count() const { return (int)_java_fields_count; } Array* fields() const { return _fields; } - void set_fields(Array* f, u2 java_fields_count) { guarantee(_fields == NULL || f == NULL, "Just checking"); - _fields = f; + _fields = f; _java_fields_count = java_fields_count; } @@ -536,7 +540,9 @@ assert(is_anonymous(), "not anonymous"); Klass** addr = (Klass**)adr_host_klass(); assert(addr != NULL, "no reversed space"); - *addr = host; + if (addr != NULL) { + *addr = host; + } } bool is_anonymous() const { return (_misc_flags & _misc_is_anonymous) != 0; @@ -586,7 +592,7 @@ // symbol unloading support (refcount already added) Symbol* array_name() { return _array_name; } - void set_array_name(Symbol* name) { assert(_array_name == NULL, "name already created"); _array_name = name; } + void set_array_name(Symbol* name) { assert(_array_name == NULL || name == NULL, "name already created"); _array_name = name; } // nonstatic oop-map blocks static int nonstatic_oop_map_size(unsigned int oop_map_count) { @@ -758,7 +764,10 @@ void set_implementor(Klass* k) { assert(is_interface(), "not interface"); Klass** addr = adr_implementor(); - *addr = k; + assert(addr != NULL, "null addr"); + if (addr != NULL) { + *addr = k; + } } int nof_implementors() const { @@ -909,8 +918,15 @@ void clean_method_data(BoolObjectClosure* is_alive); // Explicit metaspace deallocation of fields - // For RedefineClasses, we need to deallocate instanceKlasses + // For RedefineClasses and class file parsing errors, we need to deallocate + // instanceKlasses and the metadata they point to. void deallocate_contents(ClassLoaderData* loader_data); + static void deallocate_methods(ClassLoaderData* loader_data, + Array* methods); + void static deallocate_interfaces(ClassLoaderData* loader_data, + Klass* super_klass, + Array* local_interfaces, + Array* transitive_interfaces); // The constant pool is on stack if any of the methods are executing or // referenced by handles. diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/klass.cpp --- a/src/share/vm/oops/klass.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/klass.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -146,16 +146,16 @@ Klass::Klass() { Klass* k = this; - { // Preinitialize supertype information. - // A later call to initialize_supers() may update these settings: - set_super(NULL); - for (juint i = 0; i < Klass::primary_super_limit(); i++) { - _primary_supers[i] = NULL; - } - set_secondary_supers(NULL); - _primary_supers[0] = k; - set_super_check_offset(in_bytes(primary_supers_offset())); + // Preinitialize supertype information. + // A later call to initialize_supers() may update these settings: + set_super(NULL); + for (juint i = 0; i < Klass::primary_super_limit(); i++) { + _primary_supers[i] = NULL; } + set_secondary_supers(NULL); + set_secondary_super_cache(NULL); + _primary_supers[0] = k; + set_super_check_offset(in_bytes(primary_supers_offset())); set_java_mirror(NULL); set_modifier_flags(0); @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/klass.hpp --- a/src/share/vm/oops/klass.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/klass.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -79,7 +79,6 @@ // [last_biased_lock_bulk_revocation_time] (64 bits) // [prototype_header] // [biased_lock_revocation_count] -// [verify_count ] - not in product // [alloc_count ] // [_modified_oops] // [_accumulated_modified_oops] @@ -176,10 +175,6 @@ markOop _prototype_header; // Used when biased locking is both enabled and disabled for this type jint _biased_lock_revocation_count; -#ifndef PRODUCT - int _verify_count; // to avoid redundant verifies -#endif - juint _alloc_count; // allocation profiling support TRACE_DEFINE_KLASS_TRACE_ID; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/klassVtable.cpp --- a/src/share/vm/oops/klassVtable.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/klassVtable.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/method.cpp --- a/src/share/vm/oops/method.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/method.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -77,22 +77,19 @@ return new (loader_data, size, false, THREAD) Method(cm, access_flags, size); } -Method::Method(ConstMethod* xconst, - AccessFlags access_flags, int size) { +Method::Method(ConstMethod* xconst, AccessFlags access_flags, int size) { No_Safepoint_Verifier no_safepoint; set_constMethod(xconst); set_access_flags(access_flags); set_method_size(size); - set_name_index(0); - set_signature_index(0); #ifdef CC_INTERP set_result_index(T_VOID); #endif - set_constants(NULL); - set_max_stack(0); - set_max_locals(0); set_intrinsic_id(vmIntrinsics::_none); set_jfr_towrite(false); + set_force_inline(false); + set_hidden(false); + set_dont_inline(false); set_method_data(NULL); set_interpreter_throwout_count(0); set_vtable_index(Method::garbage_vtable_index); @@ -725,7 +722,7 @@ if (number_of_breakpoints() > 0) return true; if (is_method_handle_intrinsic()) - return !is_synthetic(); // the generated adapters must be compiled + return !is_synthetic() && intrinsic_id() != vmIntrinsics::_CompilerToVMImpl_executeCompiledMethod; // the generated adapters must be compiled if (comp_level == CompLevel_any) return is_not_c1_compilable() || is_not_c2_compilable(); if (is_c1_compile(comp_level)) @@ -806,7 +803,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); @@ -846,6 +851,14 @@ // ONLY USE the h_method now as make_adapter may have blocked +#ifdef GRAAL + // Check for special intrinsic that executes a compiled method. + if (h_method->intrinsic_id() == vmIntrinsics::_CompilerToVMImpl_executeCompiledMethod) { + // Actively install the stub for calling the intrinsic from compiled code. + CompileBroker::compile_method(h_method, InvocationEntryBci, CompLevel_highest_tier, + methodHandle(), CompileThreshold, "executeCompiledMethod", CHECK); + } +#endif } address Method::make_adapters(methodHandle mh, TRAPS) { @@ -967,6 +980,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. @@ -983,8 +1022,8 @@ // Test if this method is an internal MH primitive method. bool Method::is_method_handle_intrinsic() const { vmIntrinsics::ID iid = intrinsic_id(); - return (MethodHandles::is_signature_polymorphic(iid) && - MethodHandles::is_signature_polymorphic_intrinsic(iid)); + return ((MethodHandles::is_signature_polymorphic(iid) && + MethodHandles::is_signature_polymorphic_intrinsic(iid))) || iid == vmIntrinsics::_CompilerToVMImpl_executeCompiledMethod; } bool Method::has_member_arg() const { @@ -1170,6 +1209,8 @@ newm->set_stackmap_data(stackmap_data); } + // copy annotations over to new method + newcm->copy_annotations_from(cm); return newm; } @@ -1178,13 +1219,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/method.hpp --- a/src/share/vm/oops/method.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/method.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 @@ -636,6 +637,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 @@ -723,15 +727,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(); } @@ -771,15 +776,19 @@ void print_made_not_compilable(int comp_level, bool is_osr, bool report, const char* reason); public: - bool is_not_c1_compilable() const { return access_flags().is_not_c1_compilable(); } - void set_not_c1_compilable() { _access_flags.set_not_c1_compilable(); } - bool is_not_c2_compilable() const { return access_flags().is_not_c2_compilable(); } - void set_not_c2_compilable() { _access_flags.set_not_c2_compilable(); } + bool is_not_c1_compilable() const { return access_flags().is_not_c1_compilable(); } + void set_not_c1_compilable() { _access_flags.set_not_c1_compilable(); } + void clear_not_c1_compilable() { _access_flags.clear_not_c1_compilable(); } + bool is_not_c2_compilable() const { return access_flags().is_not_c2_compilable(); } + void set_not_c2_compilable() { _access_flags.set_not_c2_compilable(); } + void clear_not_c2_compilable() { _access_flags.clear_not_c2_compilable(); } - bool is_not_c1_osr_compilable() const { return is_not_c1_compilable(); } // don't waste an accessFlags bit - void set_not_c1_osr_compilable() { set_not_c1_compilable(); } // don't waste an accessFlags bit - bool is_not_c2_osr_compilable() const { return access_flags().is_not_c2_osr_compilable(); } - void set_not_c2_osr_compilable() { _access_flags.set_not_c2_osr_compilable(); } + bool is_not_c1_osr_compilable() const { return is_not_c1_compilable(); } // don't waste an accessFlags bit + void set_not_c1_osr_compilable() { set_not_c1_compilable(); } // don't waste an accessFlags bit + void clear_not_c1_osr_compilable() { clear_not_c1_compilable(); } // don't waste an accessFlags bit + bool is_not_c2_osr_compilable() const { return access_flags().is_not_c2_osr_compilable(); } + void set_not_c2_osr_compilable() { _access_flags.set_not_c2_osr_compilable(); } + void clear_not_c2_osr_compilable() { _access_flags.clear_not_c2_osr_compilable(); } // Background compilation support bool queued_for_compilation() const { return access_flags().queued_for_compilation(); } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/methodData.cpp --- a/src/share/vm/oops/methodData.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/methodData.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -392,6 +392,9 @@ } int MethodData::bytecode_cell_count(Bytecodes::Code code) { +#if defined(COMPILER1) && !(defined(COMPILER2) || defined(GRAAL)) + 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 @@ -521,6 +525,9 @@ // the segment in bytes. int MethodData::initialize_data(BytecodeStream* stream, int data_index) { +#if defined(COMPILER1) && !(defined(COMPILER2) || defined(GRAAL)) + return 0; +#else int cell_count = -1; int tag = DataLayout::no_tag; DataLayout* data_layout = data_layout_at(data_index); @@ -599,6 +606,7 @@ assert(!bytecode_has_profile(c), "agree w/ !BHP"); return 0; } +#endif } // Get the data at an arbitrary (sort of) data index. @@ -668,31 +676,14 @@ No_Safepoint_Verifier no_safepoint; // init function atomic wrt GC ResourceMark rm; - if (TieredCompilation) { - _invocation_counter.init(); - _backedge_counter.init(); - _invocation_counter_start = 0; - _backedge_counter_start = 0; - _num_loops = 0; - _num_blocks = 0; - _highest_comp_level = 0; - _highest_osr_comp_level = 0; - _would_profile = true; - } + init(); set_creation_mileage(mileage_of(method())); - // Initialize flags and trap history. - _nof_decompiles = 0; - _nof_overflow_recompiles = 0; - _nof_overflow_traps = 0; - assert(sizeof(_trap_hist) % sizeof(HeapWord) == 0, "align"); - Copy::zero_to_words((HeapWord*) &_trap_hist, - sizeof(_trap_hist) / sizeof(HeapWord)); - // Go through the bytecodes and allocate and initialize the // corresponding data cells. int data_size = 0; int empty_bc_count = 0; // number of bytecodes lacking data + _data[0] = 0; // apparently not set below. BytecodeStream stream(method()); Bytecodes::Code c; while ((c = stream.next()) >= 0) { @@ -734,6 +725,27 @@ set_size(object_size); } +void MethodData::init() { + _invocation_counter.init(); + _backedge_counter.init(); + _invocation_counter_start = 0; + _backedge_counter_start = 0; + _num_loops = 0; + _num_blocks = 0; + _highest_comp_level = 0; + _highest_osr_comp_level = 0; + _would_profile = true; + + // Initialize flags and trap history. + _nof_decompiles = 0; + _nof_overflow_recompiles = 0; + _nof_overflow_traps = 0; + clear_escape_info(); + assert(sizeof(_trap_hist) % sizeof(HeapWord) == 0, "align"); + Copy::zero_to_words((HeapWord*) &_trap_hist, + sizeof(_trap_hist) / sizeof(HeapWord)); +} + bool MethodData::is_empty_data(int size_in_bytes, Bytecodes::Code code) { #ifdef GRAAL return size_in_bytes == 0 && Bytecodes::can_trap(code); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/methodData.hpp --- a/src/share/vm/oops/methodData.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/methodData.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -1304,7 +1304,10 @@ static bool bytecode_has_profile(Bytecodes::Code code) { return bytecode_cell_count(code) != no_profile_data; } - + + // reset into original state + void init(); + // My size int size_in_bytes() const { return _size; } int size() const { return align_object_size(align_size_up(_size, BytesPerWord)/BytesPerWord); } @@ -1384,6 +1387,7 @@ intx arg_stack() { return _arg_stack; } intx arg_returned() { return _arg_returned; } uint arg_modified(int a) { ArgInfoData *aid = arg_info(); + assert(aid != NULL, "arg_info must be not null"); assert(a >= 0 && a < aid->number_of_args(), "valid argument number"); return aid->arg_modified(a); } @@ -1392,8 +1396,8 @@ void set_arg_stack(intx v) { _arg_stack = v; } void set_arg_returned(intx v) { _arg_returned = v; } void set_arg_modified(int a, uint v) { ArgInfoData *aid = arg_info(); + assert(aid != NULL, "arg_info must be not null"); assert(a >= 0 && a < aid->number_of_args(), "valid argument number"); - aid->set_arg_modified(a, v); } void clear_escape_info() { _eflags = _arg_local = _arg_stack = _arg_returned = 0; } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/symbol.cpp --- a/src/share/vm/oops/symbol.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/symbol.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 @@ -27,6 +27,7 @@ #include "classfile/altHashing.hpp" #include "classfile/classLoaderData.hpp" #include "oops/symbol.hpp" +#include "runtime/atomic.inline.hpp" #include "runtime/os.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" @@ -161,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; } @@ -210,6 +211,28 @@ return AltHashing::murmur3_32(seed, (const jbyte*)as_C_string(), utf8_length()); } +void Symbol::increment_refcount() { + // Only increment the refcount if positive. If negative either + // overflow has occurred or it is a permanent symbol in a read only + // shared archive. + if (_refcount >= 0) { + Atomic::inc(&_refcount); + NOT_PRODUCT(Atomic::inc(&_total_count);) + } +} + +void Symbol::decrement_refcount() { + if (_refcount >= 0) { + Atomic::dec(&_refcount); +#ifdef ASSERT + if (_refcount < 0) { + print(); + assert(false, "reference count underflow for symbol"); + } +#endif + } +} + void Symbol::print_on(outputStream* st) const { if (this == NULL) { st->print_cr("NULL"); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/oops/symbol.hpp --- a/src/share/vm/oops/symbol.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/oops/symbol.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 @@ -27,7 +27,6 @@ #include "utilities/utf8.hpp" #include "memory/allocation.hpp" -#include "runtime/atomic.hpp" // A Symbol is a canonicalized string. // All Symbols reside in global SymbolTable and are reference counted. @@ -150,8 +149,8 @@ // Reference counting. See comments above this class for when to use. int refcount() const { return _refcount; } - inline void increment_refcount(); - inline void decrement_refcount(); + void increment_refcount(); + void decrement_refcount(); int byte_at(int index) const { assert(index >=0 && index < _length, "symbol index overflow"); @@ -232,26 +231,4 @@ return (((uintptr_t)this < (uintptr_t)other) ? -1 : ((uintptr_t)this == (uintptr_t) other) ? 0 : 1); } - -inline void Symbol::increment_refcount() { - // Only increment the refcount if positive. If negative either - // overflow has occurred or it is a permanent symbol in a read only - // shared archive. - if (_refcount >= 0) { - Atomic::inc(&_refcount); - NOT_PRODUCT(Atomic::inc(&_total_count);) - } -} - -inline void Symbol::decrement_refcount() { - if (_refcount >= 0) { - Atomic::dec(&_refcount); -#ifdef ASSERT - if (_refcount < 0) { - print(); - assert(false, "reference count underflow for symbol"); - } -#endif - } -} #endif // SHARE_VM_OOPS_SYMBOL_HPP diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/block.cpp --- a/src/share/vm/opto/block.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/block.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/bytecodeInfo.cpp --- a/src/share/vm/opto/bytecodeInfo.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/bytecodeInfo.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/c2_globals.hpp --- a/src/share/vm/opto/c2_globals.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/c2_globals.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -54,6 +54,12 @@ #define C2_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct) \ \ + develop(bool, StressLCM, false, \ + "Randomize instruction scheduling in LCM") \ + \ + develop(bool, StressGCM, false, \ + "Randomize instruction scheduling in GCM") \ + \ notproduct(intx, CompileZapFirst, 0, \ "If +ZapDeadCompiledLocals, " \ "skip this many before compiling in zap calls") \ diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/chaitin.hpp --- a/src/share/vm/opto/chaitin.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/chaitin.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -187,31 +187,6 @@ #endif }; -//------------------------------LRG_List--------------------------------------- -// Map Node indices to Live RanGe indices. -// Array lookup in the optimized case. -class LRG_List : public ResourceObj { - friend class VMStructs; - uint _cnt, _max; - uint* _lidxs; - ReallocMark _nesting; // assertion check for reallocations -public: - LRG_List( uint max ); - - uint lookup( uint nidx ) const { - return _lidxs[nidx]; - } - uint operator[] (uint nidx) const { return lookup(nidx); } - - void map( uint nidx, uint lidx ) { - assert( nidx < _cnt, "oob" ); - _lidxs[nidx] = lidx; - } - void extend( uint nidx, uint lidx ); - - uint Size() const { return _cnt; } -}; - //------------------------------IFG-------------------------------------------- // InterFerence Graph // An undirected graph implementation. Created with a fixed number of diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/compile.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -892,7 +892,7 @@ : Phase(Compiler), _env(ci_env), _log(ci_env->log()), - _compile_id(-1), + _compile_id(0), _save_argument_registers(save_arg_registers), _method(NULL), _stub_name(stub_name), @@ -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. @@ -2899,6 +2901,13 @@ } } break; + case Op_MemBarStoreStore: + // Break the link with AllocateNode: it is no longer useful and + // confuses register allocation. + if (n->req() > MemBarNode::Precedent) { + n->set_req(MemBarNode::Precedent, top()); + } + break; default: assert( !n->is_Call(), "" ); assert( !n->is_Mem(), "" ); @@ -3669,3 +3678,38 @@ n->set_req(0, NULL); } } + +// Auxiliary method to support randomized stressing/fuzzing. +// +// This method can be called the arbitrary number of times, with current count +// as the argument. The logic allows selecting a single candidate from the +// running list of candidates as follows: +// int count = 0; +// Cand* selected = null; +// while(cand = cand->next()) { +// if (randomized_select(++count)) { +// selected = cand; +// } +// } +// +// Including count equalizes the chances any candidate is "selected". +// This is useful when we don't have the complete list of candidates to choose +// from uniformly. In this case, we need to adjust the randomicity of the +// selection, or else we will end up biasing the selection towards the latter +// candidates. +// +// Quick back-envelope calculation shows that for the list of n candidates +// the equal probability for the candidate to persist as "best" can be +// achieved by replacing it with "next" k-th candidate with the probability +// of 1/k. It can be easily shown that by the end of the run, the +// probability for any candidate is converged to 1/n, thus giving the +// uniform distribution among all the candidates. +// +// We don't care about the domain size as long as (RANDOMIZED_DOMAIN / count) is large. +#define RANDOMIZED_DOMAIN_POW 29 +#define RANDOMIZED_DOMAIN (1 << RANDOMIZED_DOMAIN_POW) +#define RANDOMIZED_DOMAIN_MASK ((1 << (RANDOMIZED_DOMAIN_POW + 1)) - 1) +bool Compile::randomized_select(int count) { + assert(count > 0, "only positive"); + return (os::random() & RANDOMIZED_DOMAIN_MASK) < (RANDOMIZED_DOMAIN / count); +} diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/compile.hpp --- a/src/share/vm/opto/compile.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/compile.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -678,6 +678,7 @@ void record_dead_node(uint idx) { if (_dead_node_list.test_set(idx)) return; _dead_node_count++; } + bool is_dead_node(uint idx) { return _dead_node_list.test(idx) != 0; } uint dead_node_count() { return _dead_node_count; } void reset_dead_node_list() { _dead_node_list.Reset(); _dead_node_count = 0; @@ -1086,6 +1087,9 @@ // Definitions of pd methods static void pd_compiler2_init(); + + // Auxiliary method for randomized fuzzing/stressing + static bool randomized_select(int count); }; #endif // SHARE_VM_OPTO_COMPILE_HPP diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/connode.cpp --- a/src/share/vm/opto/connode.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/connode.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/gcm.cpp --- a/src/share/vm/opto/gcm.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/gcm.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -1046,6 +1046,8 @@ } #endif + int cand_cnt = 0; // number of candidates tried + // Walk up the dominator tree from LCA (Lowest common ancestor) to // the earliest legal location. Capture the least execution frequency. while (LCA != early) { @@ -1071,8 +1073,11 @@ LCA->_pre_order, LCA->_nodes[0]->_idx, start_lat, end_idx, end_lat, LCA_freq); } #endif + cand_cnt++; if (LCA_freq < least_freq || // Better Frequency - ( !in_latency && // No block containing latency + (StressGCM && Compile::randomized_select(cand_cnt)) || // Should be randomly accepted in stress mode + (!StressGCM && // Otherwise, choose with latency + !in_latency && // No block containing latency LCA_freq < least_freq * delta && // No worse frequency target >= end_lat && // within latency range !self->is_iteratively_computed() ) // But don't hoist IV increments @@ -1210,7 +1215,8 @@ } // If there is no opportunity to hoist, then we're done. - bool try_to_hoist = (LCA != early); + // In stress mode, try to hoist even the single operations. + bool try_to_hoist = StressGCM || (LCA != early); // Must clone guys stay next to use; no hoisting allowed. // Also cannot hoist guys that alter memory or are otherwise not diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/graphKit.cpp --- a/src/share/vm/opto/graphKit.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/graphKit.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -3445,7 +3445,6 @@ void GraphKit::final_sync(IdealKit& ideal) { // Final sync IdealKit and graphKit. - __ drain_delay_transform(); sync_kit(ideal); } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/idealKit.cpp --- a/src/share/vm/opto/idealKit.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/idealKit.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/idealKit.hpp --- a/src/share/vm/opto/idealKit.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/idealKit.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/ifg.cpp --- a/src/share/vm/opto/ifg.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/ifg.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/lcm.cpp --- a/src/share/vm/opto/lcm.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/lcm.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -421,6 +421,7 @@ uint latency = 0; // Bigger is scheduled first uint score = 0; // Bigger is better int idx = -1; // Index in worklist + int cand_cnt = 0; // Candidate count for( uint i=0; ireq(); // Many inputs get high score to break ties // Keep best latency found - if( choice < n_choice || - ( choice == n_choice && - ( latency < n_latency || - ( latency == n_latency && - ( score < n_score ))))) { + cand_cnt++; + if (choice < n_choice || + (choice == n_choice && + ((StressLCM && Compile::randomized_select(cand_cnt)) || + (!StressLCM && + (latency < n_latency || + (latency == n_latency && + (score < n_score))))))) { choice = n_choice; latency = n_latency; score = n_score; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/library_call.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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,95 +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; - } - } - } - else 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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/live.hpp --- a/src/share/vm/opto/live.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/live.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -33,11 +33,35 @@ #include "opto/regmask.hpp" class Block; -class LRG_List; class PhaseCFG; class VectorSet; class IndexSet; +//------------------------------LRG_List--------------------------------------- +// Map Node indices to Live RanGe indices. +// Array lookup in the optimized case. +class LRG_List : public ResourceObj { + friend class VMStructs; + uint _cnt, _max; + uint* _lidxs; + ReallocMark _nesting; // assertion check for reallocations +public: + LRG_List( uint max ); + + uint lookup( uint nidx ) const { + return _lidxs[nidx]; + } + uint operator[] (uint nidx) const { return lookup(nidx); } + + void map( uint nidx, uint lidx ) { + assert( nidx < _cnt, "oob" ); + _lidxs[nidx] = lidx; + } + void extend( uint nidx, uint lidx ); + + uint Size() const { return _cnt; } +}; + //------------------------------PhaseLive-------------------------------------- // Compute live-in/live-out class PhaseLive : public Phase { diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/loopTransform.cpp --- a/src/share/vm/opto/loopTransform.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/loopTransform.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/loopnode.cpp --- a/src/share/vm/opto/loopnode.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/loopnode.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/loopnode.hpp --- a/src/share/vm/opto/loopnode.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/loopnode.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/loopopts.cpp --- a/src/share/vm/opto/loopopts.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/loopopts.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/macro.cpp --- a/src/share/vm/opto/macro.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/macro.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -1101,12 +1101,6 @@ Node* klass_node = alloc->in(AllocateNode::KlassNode); Node* initial_slow_test = alloc->in(AllocateNode::InitialTest); - Node* storestore = alloc->storestore(); - if (storestore != NULL) { - // Break this link that is no longer useful and confuses register allocation - storestore->set_req(MemBarNode::Precedent, top()); - } - assert(ctrl != NULL, "must have control"); // We need a Region and corresponding Phi's to merge the slow-path and fast-path results. // they will not be used if "always_slow" is set @@ -1324,7 +1318,7 @@ // No InitializeNode or no stores captured by zeroing // elimination. Simply add the MemBarStoreStore after object // initialization. - MemBarNode* mb = MemBarNode::make(C, Op_MemBarStoreStore, Compile::AliasIdxBot, fast_oop_rawmem); + MemBarNode* mb = MemBarNode::make(C, Op_MemBarStoreStore, Compile::AliasIdxBot); transform_later(mb); mb->init_req(TypeFunc::Memory, fast_oop_rawmem); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/memnode.cpp --- a/src/share/vm/opto/memnode.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/memnode.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -238,7 +238,7 @@ return this; ctl = in(MemNode::Control); // Don't bother trying to transform a dead node - if( ctl && ctl->is_top() ) return NodeSentinel; + if (ctl && ctl->is_top()) return NodeSentinel; PhaseIterGVN *igvn = phase->is_IterGVN(); // Wait if control on the worklist. @@ -262,8 +262,8 @@ } // Ignore if memory is dead, or self-loop Node *mem = in(MemNode::Memory); - if( phase->type( mem ) == Type::TOP ) return NodeSentinel; // caller will return NULL - assert( mem != this, "dead loop in MemNode::Ideal" ); + if (phase->type( mem ) == Type::TOP) return NodeSentinel; // caller will return NULL + assert(mem != this, "dead loop in MemNode::Ideal"); if (can_reshape && igvn != NULL && igvn->_worklist.member(mem)) { // This memory slice may be dead. @@ -273,12 +273,12 @@ } Node *address = in(MemNode::Address); - const Type *t_adr = phase->type( address ); - if( t_adr == Type::TOP ) return NodeSentinel; // caller will return NULL - - if( can_reshape && igvn != NULL && + const Type *t_adr = phase->type(address); + if (t_adr == Type::TOP) return NodeSentinel; // caller will return NULL + + if (can_reshape && igvn != NULL && (igvn->_worklist.member(address) || - igvn->_worklist.size() > 0 && (phase->type(address) != adr_type())) ) { + igvn->_worklist.size() > 0 && (t_adr != adr_type())) ) { // The address's base and type may change when the address is processed. // Delay this mem node transformation until the address is processed. phase->is_IterGVN()->_worklist.push(this); @@ -288,7 +288,7 @@ // Do NOT remove or optimize the next lines: ensure a new alias index // is allocated for an oop pointer type before Escape Analysis. // Note: C++ will not remove it since the call has side effect. - if ( t_adr->isa_oopptr() ) { + if (t_adr->isa_oopptr()) { int alias_idx = phase->C->get_alias_index(t_adr->is_ptr()); } @@ -296,6 +296,26 @@ Node* base = NULL; if (address->is_AddP()) base = address->in(AddPNode::Base); + if (base != NULL && phase->type(base)->higher_equal(TypePtr::NULL_PTR) && + !t_adr->isa_rawptr()) { + // Note: raw address has TOP base and top->higher_equal(TypePtr::NULL_PTR) is true. + Compile* C = phase->C; + tty->cr(); + tty->print_cr("===== NULL+offs not RAW address ====="); + if (C->is_dead_node(this->_idx)) tty->print_cr("'this' is dead"); + if ((ctl != NULL) && C->is_dead_node(ctl->_idx)) tty->print_cr("'ctl' is dead"); + if (C->is_dead_node(mem->_idx)) tty->print_cr("'mem' is dead"); + if (C->is_dead_node(address->_idx)) tty->print_cr("'address' is dead"); + if (C->is_dead_node(base->_idx)) tty->print_cr("'base' is dead"); + tty->cr(); + base->dump(1); + tty->cr(); + this->dump(2); + tty->print("this->adr_type(): "); adr_type()->dump(); tty->cr(); + tty->print("phase->type(address): "); t_adr->dump(); tty->cr(); + tty->print("phase->type(base): "); phase->type(address)->dump(); tty->cr(); + tty->cr(); + } assert(base == NULL || t_adr->isa_rawptr() || !phase->type(base)->higher_equal(TypePtr::NULL_PTR), "NULL+offs not RAW address?"); #endif diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/output.cpp --- a/src/share/vm/opto/output.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/output.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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; } } @@ -1196,8 +1207,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); @@ -1231,8 +1240,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(); @@ -1253,14 +1260,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; @@ -1560,8 +1559,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. @@ -1575,16 +1572,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; @@ -2521,6 +2515,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/parse2.cpp --- a/src/share/vm/opto/parse2.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/parse2.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/phaseX.cpp --- a/src/share/vm/opto/phaseX.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/phaseX.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/subnode.cpp --- a/src/share/vm/opto/subnode.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/subnode.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/opto/type.cpp --- a/src/share/vm/opto/type.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/opto/type.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/prims/jni.cpp --- a/src/share/vm/prims/jni.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/prims/jni.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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. * @@ -95,7 +95,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 @@ -1292,32 +1292,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) { @@ -5056,6 +5030,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/prims/jni.h --- a/src/share/vm/prims/jni.h Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/prims/jni.h Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/prims/jniCheck.hpp --- a/src/share/vm/prims/jniCheck.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/prims/jniCheck.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/prims/jvm.cpp --- a/src/share/vm/prims/jvm.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/prims/jvm.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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" @@ -667,8 +668,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 @@ -1459,7 +1503,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)); @@ -1472,20 +1516,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); @@ -1493,16 +1532,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 @@ -1527,12 +1579,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 } @@ -1541,6 +1589,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 @@ -1551,6 +1603,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 @@ -1561,6 +1617,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 @@ -1585,6 +1645,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"); @@ -1724,7 +1816,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; } @@ -1738,7 +1830,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); @@ -3162,11 +3254,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/prims/jvm.h --- a/src/share/vm/prims/jvm.h Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/prims/jvm.h Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/prims/jvmtiEnter.xsl --- a/src/share/vm/prims/jvmtiEnter.xsl Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/prims/jvmtiEnter.xsl Mon Apr 15 08:51:19 2013 +0200 @@ -773,7 +773,7 @@ JVMTI_ERROR_INVALID_THREAD - - jthread resolved to NULL - jthread = %0x%x + - jthread resolved to NULL - jthread = 0x%x , @@ -782,7 +782,7 @@ JVMTI_ERROR_INVALID_THREAD - - oop is not a thread - jthread = %0x%x + - oop is not a thread - jthread = 0x%x , @@ -794,7 +794,7 @@ JVMTI_ERROR_THREAD_NOT_ALIVE - - not a Java thread - jthread = %0x%x + - not a Java thread - jthread = 0x%x , @@ -838,7 +838,7 @@ JVMTI_ERROR_ILLEGAL_ARGUMENT - - negative depth - jthread = %0x%x + - negative depth - jthread = 0x%x , diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/prims/jvmtiEnvBase.cpp --- a/src/share/vm/prims/jvmtiEnvBase.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/prims/jvmtiEnvBase.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -997,13 +997,19 @@ // move our object at this point. However, our owner value is safe // since it is either the Lock word on a stack or a JavaThread *. owning_thread = Threads::owning_thread_from_monitor_owner(owner, !at_safepoint); - assert(owning_thread != NULL, "sanity check"); - if (owning_thread != NULL) { // robustness + // Cannot assume (owning_thread != NULL) here because this function + // may not have been called at a safepoint and the owning_thread + // might not be suspended. + if (owning_thread != NULL) { // The monitor's owner either has to be the current thread, at safepoint // or it has to be suspended. Any of these conditions will prevent both // contending and waiting threads from modifying the state of // the monitor. if (!at_safepoint && !JvmtiEnv::is_thread_fully_suspended(owning_thread, true, &debug_bits)) { + // Don't worry! This return of JVMTI_ERROR_THREAD_NOT_SUSPENDED + // will not make it back to the JVM/TI agent. The error code will + // get intercepted in JvmtiEnv::GetObjectMonitorUsage() which + // will retry the call via a VM_GetObjectMonitorUsage VM op. return JVMTI_ERROR_THREAD_NOT_SUSPENDED; } HandleMark hm; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/prims/jvmtiEventController.cpp --- a/src/share/vm/prims/jvmtiEventController.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/prims/jvmtiEventController.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/prims/jvmtiImpl.cpp --- a/src/share/vm/prims/jvmtiImpl.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/prims/jvmtiImpl.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -890,7 +890,7 @@ tty->print("Suspended Threads: ["); for (JavaThread *thread = Threads::first(); thread != NULL; thread = thread->next()) { -#if JVMTI_TRACE +#ifdef JVMTI_TRACE const char *name = JvmtiTrace::safe_get_thread_name(thread); #else const char *name = ""; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/prims/jvmtiRedefineClassesTrace.hpp --- a/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/prims/jvmtiTrace.hpp --- a/src/share/vm/prims/jvmtiTrace.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/prims/jvmtiTrace.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -43,10 +43,10 @@ // Support tracing except in product build on the client compiler #ifndef PRODUCT -#define JVMTI_TRACE 1 +#define JVMTI_TRACE #else #ifdef COMPILER2 -#define JVMTI_TRACE 1 +#define JVMTI_TRACE #endif #endif diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/prims/methodHandles.cpp --- a/src/share/vm/prims/methodHandles.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/prims/methodHandles.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/prims/unsafe.cpp --- a/src/share/vm/prims/unsafe.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/prims/unsafe.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -116,7 +116,11 @@ inline void* index_oop_from_field_offset_long(oop p, jlong field_offset) { jlong byte_offset = field_offset_to_byte_offset(field_offset); // Don't allow unsafe to be used to read or write the header word of oops + // unless running GRAAL which wants to read the misc word for example when + // interpreting computeHashCode(). +#ifndef GRAAL assert(p == NULL || field_offset >= oopDesc::header_size(), "offset must be outside of header"); +#endif #ifdef ASSERT if (p != NULL) { assert(byte_offset >= 0 && byte_offset <= (jlong)MAX_OBJECT_SIZE, "sane offset"); @@ -868,7 +872,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 +943,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 +962,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 +1327,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 +1356,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 +1383,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 +1394,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 +1428,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 +1440,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 +1448,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 +1478,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 +1490,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 +1503,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 +1589,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 +1600,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 +1612,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 +1627,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 +1645,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 +1663,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 +1698,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/prims/whitebox.cpp --- a/src/share/vm/prims/whitebox.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/prims/whitebox.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -49,6 +49,7 @@ #endif // INCLUDE_NMT #include "compiler/compileBroker.hpp" +#include "runtime/compilationPolicy.hpp" bool WhiteBox::_used = false; @@ -118,45 +119,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 @@ -213,11 +215,11 @@ return (code->is_alive() && !code->is_marked_for_deoptimization()); WB_END -WB_ENTRY(jboolean, WB_IsMethodCompilable(JNIEnv* env, jobject o, jobject method)) +WB_ENTRY(jboolean, WB_IsMethodCompilable(JNIEnv* env, jobject o, jobject method, jint comp_level)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); MutexLockerEx mu(Compile_lock); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - return !mh->is_not_compilable(); + return CompilationPolicy::can_be_compiled(mh, comp_level); WB_END WB_ENTRY(jboolean, WB_IsMethodQueuedForCompilation(JNIEnv* env, jobject o, jobject method)) @@ -241,7 +243,7 @@ mh->set_not_compilable(); WB_END -WB_ENTRY(jboolean, WB_SetDontInlineMethod(JNIEnv* env, jobject o, jobject method, jboolean value)) +WB_ENTRY(jboolean, WB_TestSetDontInlineMethod(JNIEnv* env, jobject o, jobject method, jboolean value)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); bool result = mh->dont_inline(); @@ -254,6 +256,71 @@ CompileBroker::queue_size(CompLevel_full_profile) /* C1 */; WB_END + +WB_ENTRY(jboolean, WB_TestSetForceInlineMethod(JNIEnv* env, jobject o, jobject method, jboolean value)) + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + bool result = mh->force_inline(); + mh->set_force_inline(value == JNI_TRUE); + return result; +WB_END + +WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobject method, jint comp_level)) + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + nmethod* nm = CompileBroker::compile_method(mh, InvocationEntryBci, comp_level, mh, mh->invocation_count(), "WhiteBox", THREAD); + MutexLockerEx mu(Compile_lock); + return (mh->queued_for_compilation() || nm != NULL); +WB_END + +WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method)) + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + MutexLockerEx mu(Compile_lock); + MethodData* mdo = mh->method_data(); + + if (mdo != NULL) { + mdo->init(); + ResourceMark rm; + int arg_count = mdo->method()->size_of_parameters(); + for (int i = 0; i < arg_count; i++) { + mdo->set_arg_modified(i, 0); + } + } + + mh->backedge_counter()->init(); + mh->invocation_counter()->init(); + mh->set_interpreter_invocation_count(0); + mh->set_interpreter_throwout_count(0); + mh->clear_not_c1_compilable(); + mh->clear_not_c2_compilable(); + mh->clear_not_c2_osr_compilable(); + NOT_PRODUCT(mh->set_compiled_invocation_count(0)); + +#ifdef TIERED + mh->set_rate(0.0F); + mh->set_prev_event_count(0); + mh->set_prev_time(0); +#endif +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,27 +389,39 @@ {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", (void*)&WB_DeoptimizeMethod }, {CC"isMethodCompiled", CC"(Ljava/lang/reflect/Method;)Z", (void*)&WB_IsMethodCompiled }, - {CC"isMethodCompilable", CC"(Ljava/lang/reflect/Method;)Z", + {CC"isMethodCompilable", CC"(Ljava/lang/reflect/Method;I)Z", (void*)&WB_IsMethodCompilable}, {CC"isMethodQueuedForCompilation", CC"(Ljava/lang/reflect/Method;)Z", (void*)&WB_IsMethodQueuedForCompilation}, {CC"makeMethodNotCompilable", CC"(Ljava/lang/reflect/Method;)V", (void*)&WB_MakeMethodNotCompilable}, - {CC"setDontInlineMethod", - CC"(Ljava/lang/reflect/Method;Z)Z", (void*)&WB_SetDontInlineMethod}, + {CC"testSetDontInlineMethod", + CC"(Ljava/lang/reflect/Method;Z)Z", (void*)&WB_TestSetDontInlineMethod}, {CC"getMethodCompilationLevel", CC"(Ljava/lang/reflect/Method;)I", (void*)&WB_GetMethodCompilationLevel}, {CC"getCompileQueuesSize", CC"()I", (void*)&WB_GetCompileQueuesSize}, + {CC"testSetForceInlineMethod", + CC"(Ljava/lang/reflect/Method;Z)Z", (void*)&WB_TestSetForceInlineMethod}, + {CC"enqueueMethodForCompilation", + CC"(Ljava/lang/reflect/Method;I)Z", (void*)&WB_EnqueueMethodForCompilation}, + {CC"clearMethodState", + CC"(Ljava/lang/reflect/Method;)V", (void*)&WB_ClearMethodState}, + {CC"isInStringTable", CC"(Ljava/lang/String;)Z", (void*)&WB_IsInStringTable }, + {CC"fullGC", CC"()V", (void*)&WB_FullGC }, }; #undef CC diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/arguments.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -264,6 +264,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) }, @@ -1178,7 +1179,6 @@ set_parnew_gc_flags(); } - // MaxHeapSize is aligned down in collectorPolicy size_t max_heap = align_size_down(MaxHeapSize, CardTableRS::ct_max_alignment_constraint()); @@ -1216,10 +1216,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 @@ -1390,6 +1386,40 @@ return false; } +void Arguments::set_use_compressed_oops() { +#ifndef ZERO +#ifdef _LP64 + // MaxHeapSize is not set up properly at this point, but + // the only value that can override MaxHeapSize if we are + // to use UseCompressedOops is InitialHeapSize. + size_t max_heap_size = MAX2(MaxHeapSize, InitialHeapSize); + + if (max_heap_size <= max_heap_for_compressed_oops()) { +#if !defined(COMPILER1) || defined(TIERED) + if (FLAG_IS_DEFAULT(UseCompressedOops)) { + FLAG_SET_ERGO(bool, UseCompressedOops, true); + } +#endif +#ifdef _WIN64 + if (UseLargePages && UseCompressedOops) { + // Cannot allocate guard pages for implicit checks in indexed addressing + // mode, when large pages are specified on windows. + // This flag could be switched ON if narrow oop base address is set to 0, + // see code in Universe::initialize_heap(). + Universe::set_narrow_oop_use_implicit_null_checks(false); + } +#endif // _WIN64 + } else { + if (UseCompressedOops && !FLAG_IS_DEFAULT(UseCompressedOops)) { + warning("Max heap size too large for Compressed Oops"); + FLAG_SET_DEFAULT(UseCompressedOops, false); + FLAG_SET_DEFAULT(UseCompressedKlassPointers, false); + } + } +#endif // _LP64 +#endif // ZERO +} + void Arguments::set_ergonomics_flags() { if (os::is_server_class_machine()) { @@ -1419,30 +1449,7 @@ #ifndef ZERO #ifdef _LP64 - // Check that UseCompressedOops can be set with the max heap size allocated - // by ergonomics. - if (MaxHeapSize <= max_heap_for_compressed_oops()) { -#if !defined(COMPILER1) || defined(TIERED) - if (FLAG_IS_DEFAULT(UseCompressedOops)) { - FLAG_SET_ERGO(bool, UseCompressedOops, true); - } -#endif -#ifdef _WIN64 - if (UseLargePages && UseCompressedOops) { - // Cannot allocate guard pages for implicit checks in indexed addressing - // mode, when large pages are specified on windows. - // This flag could be switched ON if narrow oop base address is set to 0, - // see code in Universe::initialize_heap(). - Universe::set_narrow_oop_use_implicit_null_checks(false); - } -#endif // _WIN64 - } else { - if (UseCompressedOops && !FLAG_IS_DEFAULT(UseCompressedOops)) { - warning("Max heap size too large for Compressed Oops"); - FLAG_SET_DEFAULT(UseCompressedOops, false); - FLAG_SET_DEFAULT(UseCompressedKlassPointers, false); - } - } + set_use_compressed_oops(); // UseCompressedOops must be on for UseCompressedKlassPointers to be on. if (!UseCompressedOops) { if (UseCompressedKlassPointers) { @@ -1555,6 +1562,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 @@ -1593,12 +1609,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); } @@ -1618,14 +1634,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. @@ -1747,11 +1763,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, @@ -1822,6 +1842,13 @@ } } +void Arguments::check_deprecated_gc_flags() { + if (FLAG_IS_CMDLINE(MaxGCMinorPauseMillis)) { + warning("Using MaxGCMinorPauseMillis as minor pause goal is deprecated" + "and will likely be removed in future release"); + } +} + // Check stack pages settings bool Arguments::check_stack_pages() { @@ -1992,11 +2019,12 @@ // than just disable the lock verification. This will be fixed under // bug 4788986. if (UseConcMarkSweepGC && FLSVerifyAllHeapReferences) { - if (VerifyGCStartAt == 0) { + if (VerifyDuringStartup) { warning("Heap verification at start-up disabled " "(due to current incompatibility with FLSVerifyAllHeapReferences)"); - VerifyGCStartAt = 1; // Disable verification at start-up + VerifyDuringStartup = false; // Disable verification at start-up } + if (VerifyBeforeExit) { warning("Heap verification at shutdown disabled " "(due to current incompatibility with FLSVerifyAllHeapReferences)"); @@ -2328,10 +2356,12 @@ } #if !INCLUDE_JVMTI if ((strcmp(name, "hprof") == 0) || (strcmp(name, "jdwp") == 0)) { - warning("profiling and debugging agents are not supported in this VM"); - } else + jio_fprintf(defaultStream::error_stream(), + "Profiling and debugging agents are not supported in this VM\n"); + return JNI_ERR; + } #endif // !INCLUDE_JVMTI - add_init_library(name, options); + add_init_library(name, options); } // -agentlib and -agentpath } else if (match_option(option, "-agentlib:", &tail) || @@ -2348,16 +2378,19 @@ } #if !INCLUDE_JVMTI if ((strcmp(name, "hprof") == 0) || (strcmp(name, "jdwp") == 0)) { - warning("profiling and debugging agents are not supported in this VM"); - } else + jio_fprintf(defaultStream::error_stream(), + "Profiling and debugging agents are not supported in this VM\n"); + return JNI_ERR; + } #endif // !INCLUDE_JVMTI add_init_agent(name, options, is_absolute_path); - } // -javaagent } else if (match_option(option, "-javaagent:", &tail)) { #if !INCLUDE_JVMTI - warning("Instrumentation agents are not supported in this VM"); + jio_fprintf(defaultStream::error_stream(), + "Instrumentation agents are not supported in this VM\n"); + return JNI_ERR; #else if(tail != NULL) { char *options = strcpy(NEW_C_HEAP_ARRAY(char, strlen(tail) + 1, mtInternal), tail); @@ -2498,8 +2531,9 @@ #if INCLUDE_FPROF _has_profile = true; #else // INCLUDE_FPROF - // do we have to exit? - warning("Flat profiling is not supported in this VM."); + jio_fprintf(defaultStream::error_stream(), + "Flat profiling is not supported in this VM.\n"); + return JNI_ERR; #endif // INCLUDE_FPROF // -Xaprof } else if (match_option(option, "-Xaprof", &tail)) { @@ -2533,8 +2567,9 @@ #if INCLUDE_MANAGEMENT FLAG_SET_CMDLINE(bool, ManagementServer, true); #else - vm_exit_during_initialization( - "-Dcom.sun.management is not supported in this VM.", NULL); + jio_fprintf(defaultStream::output_stream(), + "-Dcom.sun.management is not supported in this VM.\n"); + return JNI_ERR; #endif } // -Xint @@ -2547,16 +2582,10 @@ } else if (match_option(option, "-Xcomp", &tail)) { // for testing the compiler; turn off all flags that inhibit compilation set_mode_flags(_comp); - // -Xshare:dump } else if (match_option(option, "-Xshare:dump", &tail)) { -#if !INCLUDE_CDS - vm_exit_during_initialization( - "Dumping a shared archive is not supported in this VM.", NULL); -#else FLAG_SET_CMDLINE(bool, DumpSharedSpaces, true); set_mode_flags(_int); // Prevent compilation, which creates objects -#endif // -Xshare:on } else if (match_option(option, "-Xshare:on", &tail)) { FLAG_SET_CMDLINE(bool, UseSharedSpaces, true); @@ -2569,7 +2598,6 @@ } else if (match_option(option, "-Xshare:off", &tail)) { FLAG_SET_CMDLINE(bool, UseSharedSpaces, false); FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false); - // -Xverify } else if (match_option(option, "-Xverify", &tail)) { if (strcmp(tail, ":all") == 0 || strcmp(tail, "") == 0) { @@ -2650,9 +2678,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); @@ -2883,8 +2909,9 @@ FLAG_SET_CMDLINE(bool, UseVMInterruptibleIO, true); #if !INCLUDE_MANAGEMENT } else if (match_option(option, "-XX:+ManagementServer", &tail)) { - vm_exit_during_initialization( - "ManagementServer is not supported in this VM.", NULL); + jio_fprintf(defaultStream::error_stream(), + "ManagementServer is not supported in this VM.\n"); + return JNI_ERR; #endif // INCLUDE_MANAGEMENT } else if (match_option(option, "-XX:", &tail)) { // -XX:xxxx // Skip -XX:Flags= since that case has already been handled @@ -3136,6 +3163,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 @@ -3145,6 +3173,7 @@ UNSUPPORTED_GC_OPTION(UseConcMarkSweepGC); UNSUPPORTED_GC_OPTION(UseParNewGC); } +#endif // INCLUDE_ALL_GCS // Parse entry point called from JNI_CreateJavaVM @@ -3201,7 +3230,9 @@ #if INCLUDE_NMT MemTracker::init_tracking_options(tail); #else - warning("Native Memory Tracking is not supported in this VM"); + jio_fprintf(defaultStream::error_stream(), + "Native Memory Tracking is not supported in this VM\n"); + return JNI_ERR; #endif } @@ -3320,6 +3351,16 @@ force_serial_gc(); #endif // INCLUDE_ALL_GCS #if !INCLUDE_CDS + if (DumpSharedSpaces || RequireSharedSpaces) { + jio_fprintf(defaultStream::error_stream(), + "Shared spaces are not supported in this VM\n"); + return JNI_ERR; + } + if ((UseSharedSpaces && FLAG_IS_CMDLINE(UseSharedSpaces)) || PrintSharedSpaces) { + warning("Shared spaces are not supported in this VM"); + FLAG_SET_DEFAULT(UseSharedSpaces, false); + FLAG_SET_DEFAULT(PrintSharedSpaces, false); + } no_shared_spaces(); #endif // INCLUDE_CDS @@ -3358,6 +3399,14 @@ set_g1_gc_flags(); } 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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/arguments.hpp --- a/src/share/vm/runtime/arguments.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/arguments.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -314,8 +314,12 @@ // Garbage-First (UseG1GC) static void set_g1_gc_flags(); // GC ergonomics + 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 @@ -422,6 +426,7 @@ // Check for consistency in the selection of the garbage collector. static bool check_gc_consistency(); static void check_deprecated_gcs(); + static void check_deprecated_gc_flags(); // Check consistecy or otherwise of VM argument settings static bool check_vm_args_consistency(); // Check stack pages settings diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/compilationPolicy.cpp --- a/src/share/vm/runtime/compilationPolicy.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/compilationPolicy.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -130,9 +130,10 @@ } if (comp_level == CompLevel_all) { return !m->is_not_compilable(CompLevel_simple) && !m->is_not_compilable(CompLevel_full_optimization); - } else { + } else if (is_compile(comp_level)) { return !m->is_not_compilable(comp_level); } + return false; } bool CompilationPolicy::is_compilation_enabled() { diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/compilationPolicy.hpp --- a/src/share/vm/runtime/compilationPolicy.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/compilationPolicy.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -96,7 +96,7 @@ void reset_counter_for_back_branch_event(methodHandle method); public: NonTieredCompPolicy() : _compiler_count(0) { } - virtual CompLevel initial_compile_level() { return CompLevel_initial_compile; } + virtual CompLevel initial_compile_level() { return CompLevel_highest_tier; } virtual int compiler_count(CompLevel comp_level); virtual void do_safepoint_work(); virtual void reprofile(ScopeDesc* trap_scope, bool is_osr); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/deoptimization.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -457,6 +457,7 @@ callee_parameters, callee_locals, index == 0, + index == array->frames() - 1, popframe_extra_args); // This pc doesn't have to be perfect just good enough to identify the frame // as interpreted so the skeleton frame will be walkable diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/frame.cpp --- a/src/share/vm/runtime/frame.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/frame.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -1070,7 +1070,12 @@ // First consult the ADLC on where it puts parameter 0 for this signature. VMReg reg = SharedRuntime::name_for_receiver(); - oop r = *caller.oopmapreg_to_location(reg, reg_map); + oop* oop_adr = caller.oopmapreg_to_location(reg, reg_map); + if (oop_adr == NULL) { + guarantee(oop_adr != NULL, "bad register save location"); + return NULL; + } + oop r = *oop_adr; assert(Universe::heap()->is_in_or_null(r), err_msg("bad receiver: " INTPTR_FORMAT " (" INTX_FORMAT ")", (intptr_t) r, (intptr_t) r)); return r; } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/globals.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -471,6 +471,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) */ \ @@ -693,9 +696,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") \ \ @@ -883,6 +883,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") \ \ @@ -1419,6 +1424,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") \ \ @@ -1768,6 +1777,10 @@ manageable(intx, CMSWaitDuration, 2000, \ "Time in milliseconds that CMS thread waits for young GC") \ \ + develop(uintx, CMSCheckInterval, 1000, \ + "Interval in milliseconds that CMS thread checks if it " \ + "should start a collection cycle") \ + \ product(bool, CMSYield, true, \ "Yield between steps of concurrent mark & sweep") \ \ @@ -1971,6 +1984,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") \ \ @@ -2123,6 +2140,10 @@ product(intx, PrefetchFieldsAhead, -1, \ "How many fields ahead to prefetch in oop scan (<= 0 means off)") \ \ + diagnostic(bool, VerifyDuringStartup, false, \ + "Verify memory system before executing any Java code " \ + "during VM initialization") \ + \ diagnostic(bool, VerifyBeforeExit, trueInDebug, \ "Verify system before exiting") \ \ @@ -2528,7 +2549,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") \ @@ -2921,6 +2942,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_pd(intx, TypeProfileWidth, \ "number of receiver types to record in call/cast profile") \ \ @@ -3312,10 +3337,10 @@ "ConcurrentMarkSweep thread runs at critical scheduling priority")\ \ /* compiler debugging */ \ - notproduct(intx, CompileTheWorldStartAt, 1, \ + develop(intx, CompileTheWorldStartAt, 1, \ "First class to consider when using +CompileTheWorld") \ \ - notproduct(intx, CompileTheWorldStopAt, max_jint, \ + develop(intx, CompileTheWorldStopAt, max_jint, \ "Last class to consider when using +CompileTheWorld") \ \ develop(intx, NewCodeParameter, 0, \ @@ -3585,8 +3610,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, " \ @@ -3660,7 +3686,15 @@ "Enable internal testing APIs") \ \ product(bool, PrintGCCause, true, \ - "Include GC cause in GC logging") + "Include GC cause in GC logging") \ + \ + product(bool , AllowNonVirtualCalls, false, \ + "Obey the ACC_SUPER flag and allow invokenonvirtual calls") \ + \ + experimental(uintx, ArrayAllocatorMallocLimit, \ + SOLARIS_ONLY(64*K) NOT_SOLARIS(max_uintx), \ + "Allocation less than this value will be allocated " \ + "using malloc. Larger allocations will use mmap.") /* * Macros for factoring of globals diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/init.cpp --- a/src/share/vm/runtime/init.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/init.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/javaCalls.cpp --- a/src/share/vm/runtime/javaCalls.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/javaCalls.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -412,7 +412,7 @@ ((JavaThread*) THREAD)->set_graal_alternate_call_target(nm->verified_entry_point()); entry_point = method->adapter()->get_i2c_entry(); } else { - THROW(vmSymbols::MethodInvalidatedException()); + THROW(vmSymbols::com_oracle_graal_api_code_InvalidInstalledCodeException()); } } #endif diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/os.cpp --- a/src/share/vm/runtime/os.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/os.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/os.hpp --- a/src/share/vm/runtime/os.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/os.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/safepoint.cpp --- a/src/share/vm/runtime/safepoint.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/safepoint.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/sharedRuntime.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -83,6 +83,7 @@ #endif // Shared stub locations +RuntimeStub* SharedRuntime::_deoptimized_installed_code_blob; RuntimeStub* SharedRuntime::_wrong_method_blob; RuntimeStub* SharedRuntime::_ic_miss_blob; RuntimeStub* SharedRuntime::_resolve_opt_virtual_call_blob; @@ -101,6 +102,7 @@ //----------------------------generate_stubs----------------------------------- void SharedRuntime::generate_stubs() { + _deoptimized_installed_code_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_deoptimized_installed_code), "deoptimized_installed_code"); _wrong_method_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method), "wrong_method_stub"); _ic_miss_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method_ic_miss), "ic_miss_stub"); _resolve_opt_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_opt_virtual_call_C), "resolve_opt_virtual_call"); @@ -969,6 +971,11 @@ JRT_ENTRY_NO_ASYNC(void, SharedRuntime::register_finalizer(JavaThread* thread, oopDesc* obj)) +#ifdef GRAAL + if (!obj->klass()->has_finalizer()) { + return; + } +#endif assert(obj->is_oop(), "must be a valid oop"); assert(obj->klass()->has_finalizer(), "shouldn't be here otherwise"); InstanceKlass::register_finalizer(instanceOop(obj), CHECK); @@ -1345,6 +1352,12 @@ return callee_method->verified_code_entry(); JRT_END +// Installed code has been deoptimized +JRT_BLOCK_ENTRY(address, SharedRuntime::handle_deoptimized_installed_code(JavaThread* thread)) + JavaThread* THREAD = thread; + ThreadInVMfromJava tiv(THREAD); + THROW_(vmSymbols::com_oracle_graal_api_code_InvalidInstalledCodeException(), NULL); +JRT_END // Handle call site that has been made non-entrant JRT_BLOCK_ENTRY(address, SharedRuntime::handle_wrong_method(JavaThread* thread)) diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/sharedRuntime.hpp --- a/src/share/vm/runtime/sharedRuntime.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/sharedRuntime.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -55,6 +55,7 @@ // Shared stub locations + static RuntimeStub* _deoptimized_installed_code_blob; static RuntimeStub* _wrong_method_blob; static RuntimeStub* _ic_miss_blob; static RuntimeStub* _resolve_opt_virtual_call_blob; @@ -209,6 +210,11 @@ return _wrong_method_blob->entry_point(); } + static address get_deoptimized_installed_code_stub() { + assert(_deoptimized_installed_code_blob!= NULL, "oops"); + return _deoptimized_installed_code_blob->entry_point(); + } + #ifdef COMPILER2 static void generate_uncommon_trap_blob(void); static UncommonTrapBlob* uncommon_trap_blob() { return _uncommon_trap_blob; } @@ -486,6 +492,9 @@ static address handle_wrong_method(JavaThread* thread); static address handle_wrong_method_ic_miss(JavaThread* thread); + // handle deoptimized installed code + static address handle_deoptimized_installed_code(JavaThread* thread); + #ifndef PRODUCT // Collect and print inline cache miss statistics diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/stubCodeGenerator.cpp --- a/src/share/vm/runtime/stubCodeGenerator.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/stubCodeGenerator.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/synchronizer.cpp --- a/src/share/vm/runtime/synchronizer.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/synchronizer.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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. @@ -813,6 +811,7 @@ } if (owner != NULL) { + // owning_thread_from_monitor_owner() may also return NULL here return Threads::owning_thread_from_monitor_owner(owner, doLock); } @@ -1638,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/synchronizer.hpp --- a/src/share/vm/runtime/synchronizer.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/synchronizer.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/thread.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -3426,12 +3426,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(); @@ -3455,6 +3449,11 @@ } assert (Universe::is_fully_initialized(), "not initialized"); + if (VerifyDuringStartup) { + VM_Verify verify_op(false /* silent */); // make sure we're starting with a clean slate + VMThread::execute(&verify_op); + } + EXCEPTION_MARK; // At this point, the Universe is initialized, but we have not executed @@ -4064,6 +4063,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; } @@ -4288,7 +4288,9 @@ if (owner == (address)p) return p; } } - assert(UseHeavyMonitors == false, "Did not find owning Java thread with UseHeavyMonitors enabled"); + // Cannot assert on lack of success here since this function may be + // used by code that is trying to report useful problem information + // like deadlock detection. if (UseHeavyMonitors) return NULL; // @@ -4306,7 +4308,7 @@ } } } - assert(the_owner != NULL, "Did not find owning Java thread for lock word address"); + // cannot assert on lack of success here; see above comment return the_owner; } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/thread.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 @@ -1312,6 +1312,7 @@ void enable_stack_red_zone(); void disable_stack_red_zone(); + inline bool stack_guard_zone_unused(); inline bool stack_yellow_zone_disabled(); inline bool stack_yellow_zone_enabled(); @@ -1785,6 +1786,10 @@ return (CompilerThread*)this; } +inline bool JavaThread::stack_guard_zone_unused() { + return _stack_guard_state == stack_guard_unused; +} + inline bool JavaThread::stack_yellow_zone_disabled() { return _stack_guard_state == stack_guard_yellow_disabled; } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/vframe.cpp --- a/src/share/vm/runtime/vframe.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/vframe.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/vframe.hpp --- a/src/share/vm/runtime/vframe.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/vframe.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/vframeArray.cpp --- a/src/share/vm/runtime/vframeArray.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/vframeArray.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -160,6 +160,7 @@ int callee_locals, frame* caller, bool is_top_frame, + bool is_bottom_frame, int exec_mode) { JavaThread* thread = (JavaThread*) Thread::current(); @@ -278,7 +279,8 @@ callee_locals, caller, iframe(), - is_top_frame); + is_top_frame, + is_bottom_frame); // Update the pc in the frame object and overwrite the temporary pc // we placed in the skeletal frame now that we finally know the @@ -456,6 +458,7 @@ int callee_parameters, int callee_locals, bool is_top_frame, + bool is_bottom_frame, int popframe_extra_stack_expression_els) const { assert(method()->max_locals() == locals()->size(), "just checking"); int locks = monitors() == NULL ? 0 : monitors()->number_of_monitors(); @@ -467,7 +470,8 @@ caller_actual_parameters, callee_parameters, callee_locals, - is_top_frame); + is_top_frame, + is_bottom_frame); } @@ -558,7 +562,7 @@ // Do the unpacking of interpreter frames; the frame at index 0 represents the top activation, so it has no callee // Unpack the frames from the oldest (frames() -1) to the youngest (0) - frame caller_frame = me; + frame* caller_frame = &me; for (index = frames() - 1; index >= 0 ; index--) { vframeArrayElement* elem = element(index); // caller int callee_parameters, callee_locals; @@ -578,13 +582,14 @@ elem->unpack_on_stack(caller_actual_parameters, callee_parameters, callee_locals, - &caller_frame, + caller_frame, index == 0, + index == frames() - 1, exec_mode); if (index == frames() - 1) { Deoptimization::unwind_callee_save_values(elem->iframe(), this); } - caller_frame = *elem->iframe(); + caller_frame = elem->iframe(); caller_actual_parameters = callee_parameters; } deallocate_monitor_chunks(); diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/vframeArray.hpp --- a/src/share/vm/runtime/vframeArray.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/vframeArray.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -88,6 +88,7 @@ int on_stack_size(int caller_actual_parameters, int callee_parameters, int callee_locals, + bool is_bottom_frame, bool is_top_frame, int popframe_extra_stack_expression_els) const; @@ -97,6 +98,7 @@ int callee_locals, frame* caller, bool is_top_frame, + bool is_bottom_frame, int exec_mode); #ifndef PRODUCT diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/vmStructs.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -336,7 +336,6 @@ nonstatic_field(Klass, _access_flags, AccessFlags) \ nonstatic_field(Klass, _subklass, Klass*) \ nonstatic_field(Klass, _next_sibling, Klass*) \ - nonproduct_nonstatic_field(Klass, _verify_count, int) \ nonstatic_field(Klass, _alloc_count, juint) \ nonstatic_field(MethodData, _size, int) \ nonstatic_field(MethodData, _method, Method*) \ @@ -479,6 +478,9 @@ \ nonstatic_field(CardGeneration, _rs, GenRemSet*) \ nonstatic_field(CardGeneration, _bts, BlockOffsetSharedArray*) \ + nonstatic_field(CardGeneration, _shrink_factor, size_t) \ + nonstatic_field(CardGeneration, _capacity_at_prologue, size_t) \ + nonstatic_field(CardGeneration, _used_at_prologue, size_t) \ \ nonstatic_field(CardTableModRefBS, _whole_heap, const MemRegion) \ nonstatic_field(CardTableModRefBS, _guard_index, const size_t) \ @@ -549,8 +551,6 @@ nonstatic_field(Space, _bottom, HeapWord*) \ nonstatic_field(Space, _end, HeapWord*) \ \ - nonstatic_field(TenuredGeneration, _shrink_factor, size_t) \ - nonstatic_field(TenuredGeneration, _capacity_at_prologue, size_t) \ nonstatic_field(ThreadLocalAllocBuffer, _start, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _top, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _end, HeapWord*) \ diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/vm_operations.cpp --- a/src/share/vm/runtime/vm_operations.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/vm_operations.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -177,7 +177,8 @@ } void VM_Verify::doit() { - Universe::verify(); + Universe::heap()->prepare_for_verify(); + Universe::verify(_silent); } bool VM_PrintThreads::doit_prologue() { diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/vm_operations.hpp --- a/src/share/vm/runtime/vm_operations.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/vm_operations.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -94,6 +94,7 @@ template(ReportJavaOutOfMemory) \ template(JFRCheckpoint) \ template(Exit) \ + template(LinuxDllLoad) \ class VM_Operation: public CHeapObj { public: @@ -300,9 +301,9 @@ class VM_Verify: public VM_Operation { private: - KlassHandle _dependee; + bool _silent; public: - VM_Verify() {} + VM_Verify(bool silent) : _silent(silent) {} VMOp_Type type() const { return VMOp_Verify; } void doit(); }; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/runtime/vm_version.cpp --- a/src/share/vm/runtime/vm_version.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/runtime/vm_version.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -215,6 +215,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/services/memReporter.cpp --- a/src/share/vm/services/memReporter.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/services/memReporter.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -419,7 +419,7 @@ _output->print_cr("[" PTR_FORMAT "] %s+0x%x", pc, buf, offset); _output->print("%28s", " "); } else { - _output->print("[" PTR_FORMAT "]%18s", " "); + _output->print("[" PTR_FORMAT "]%18s", pc, " "); } _output->print_cr("(mmap: reserved=%d%s, committed=%d%s)", @@ -596,7 +596,7 @@ _output->print_cr("[" PTR_FORMAT "] %s+0x%x", pc, buf, offset); _output->print("%28s", " "); } else { - _output->print("[" PTR_FORMAT "]%18s", " "); + _output->print("[" PTR_FORMAT "]%18s", pc, " "); } } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/services/memTracker.cpp --- a/src/share/vm/services/memTracker.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/services/memTracker.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/services/memTracker.hpp --- a/src/share/vm/services/memTracker.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/services/memTracker.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/services/memoryManager.cpp diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/services/memoryManager.hpp diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/services/memoryPool.cpp diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/services/memoryPool.hpp diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/services/memoryService.cpp --- a/src/share/vm/services/memoryService.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/services/memoryService.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/services/memoryService.hpp diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/services/nmtDCmd.cpp --- a/src/share/vm/services/nmtDCmd.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/services/nmtDCmd.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/services/nmtDCmd.hpp --- a/src/share/vm/services/nmtDCmd.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/services/nmtDCmd.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -39,6 +39,7 @@ DCmdArgument _summary_diff; DCmdArgument _detail_diff; DCmdArgument _shutdown; + DCmdArgument _auto_shutdown; #ifndef PRODUCT DCmdArgument _debug; #endif diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/services/threadService.cpp --- a/src/share/vm/services/threadService.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/services/threadService.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 @@ -327,8 +327,28 @@ while (waitingToLockMonitor != NULL || waitingToLockBlocker != NULL) { cycle->add_thread(currentThread); if (waitingToLockMonitor != NULL) { - currentThread = Threads::owning_thread_from_monitor_owner((address)waitingToLockMonitor->owner(), - false /* no locking needed */); + currentThread = Threads::owning_thread_from_monitor_owner( + (address)waitingToLockMonitor->owner(), + false /* no locking needed */); + if (currentThread == NULL) { + // This function is called at a safepoint so the JavaThread + // that owns waitingToLockMonitor should be findable, but + // if it is not findable, then the previous currentThread is + // blocked permanently. We record this as a deadlock. + num_deadlocks++; + + cycle->set_deadlock(true); + + // add this cycle to the deadlocks list + if (deadlocks == NULL) { + deadlocks = cycle; + } else { + last->set_next(cycle); + } + last = cycle; + cycle = new DeadlockCycle(); + break; + } } else { if (concurrent_locks) { if (waitingToLockBlocker->is_a(SystemDictionary::abstract_ownable_synchronizer_klass())) { @@ -841,7 +861,17 @@ owner_desc = " (JVMTI raw monitor),\n which is held by"; } currentThread = Threads::owning_thread_from_monitor_owner( - (address)waitingToLockMonitor->owner(), false /* no locking needed */); + (address)waitingToLockMonitor->owner(), + false /* no locking needed */); + if (currentThread == NULL) { + // The deadlock was detected at a safepoint so the JavaThread + // that owns waitingToLockMonitor should be findable, but + // if it is not findable, then the previous currentThread is + // blocked permanently. + st->print("%s UNKNOWN_owner_addr=" PTR_FORMAT, owner_desc, + (address)waitingToLockMonitor->owner()); + continue; + } } else { st->print(" waiting for ownable synchronizer " INTPTR_FORMAT ", (a %s)", (address)waitingToLockBlocker, diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/utilities/accessFlags.hpp --- a/src/share/vm/utilities/accessFlags.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/utilities/accessFlags.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -194,6 +194,9 @@ void set_is_obsolete() { atomic_set_bits(JVM_ACC_IS_OBSOLETE); } void set_is_prefixed_native() { atomic_set_bits(JVM_ACC_IS_PREFIXED_NATIVE); } + void clear_not_c1_compilable() { atomic_clear_bits(JVM_ACC_NOT_C1_COMPILABLE); } + void clear_not_c2_compilable() { atomic_clear_bits(JVM_ACC_NOT_C2_COMPILABLE); } + void clear_not_c2_osr_compilable() { atomic_clear_bits(JVM_ACC_NOT_C2_OSR_COMPILABLE); } // Klass* flags void set_has_vanilla_constructor() { atomic_set_bits(JVM_ACC_HAS_VANILLA_CONSTRUCTOR); } void set_has_finalizer() { atomic_set_bits(JVM_ACC_HAS_FINALIZER); } diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/utilities/bitMap.cpp --- a/src/share/vm/utilities/bitMap.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/utilities/bitMap.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -516,6 +516,10 @@ return sum; } +void BitMap::print_on_error(outputStream* st, const char* prefix) const { + st->print_cr("%s[" PTR_FORMAT ", " PTR_FORMAT ")", + prefix, map(), (char*)map() + (size() >> LogBitsPerByte)); +} #ifndef PRODUCT diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/utilities/bitMap.hpp --- a/src/share/vm/utilities/bitMap.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/utilities/bitMap.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -262,6 +262,7 @@ bool is_full() const; bool is_empty() const; + void print_on_error(outputStream* st, const char* prefix) const; #ifndef PRODUCT public: diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/utilities/debug.cpp --- a/src/share/vm/utilities/debug.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/utilities/debug.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/utilities/debug.hpp --- a/src/share/vm/utilities/debug.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/utilities/debug.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/utilities/elfFile.cpp --- a/src/share/vm/utilities/elfFile.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/utilities/elfFile.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -197,4 +197,28 @@ return NULL; } +#ifdef LINUX +bool ElfFile::specifies_noexecstack() { + Elf_Phdr phdr; + if (!m_file) return true; + + if (!fseek(m_file, m_elfHdr.e_phoff, SEEK_SET)) { + for (int index = 0; index < m_elfHdr.e_phnum; index ++) { + if (fread((void*)&phdr, sizeof(Elf_Phdr), 1, m_file) != 1) { + m_status = NullDecoder::file_invalid; + return false; + } + if (phdr.p_type == PT_GNU_STACK) { + if (phdr.p_flags == (PF_R | PF_W)) { + return true; + } else { + return false; + } + } + } + } + return false; +} +#endif + #endif // _WINDOWS diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/utilities/elfFile.hpp --- a/src/share/vm/utilities/elfFile.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/utilities/elfFile.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -43,6 +43,7 @@ typedef Elf64_Ehdr Elf_Ehdr; typedef Elf64_Shdr Elf_Shdr; +typedef Elf64_Phdr Elf_Phdr; typedef Elf64_Sym Elf_Sym; #if !defined(_ALLBSD_SOURCE) || defined(__APPLE__) @@ -59,6 +60,7 @@ typedef Elf32_Ehdr Elf_Ehdr; typedef Elf32_Shdr Elf_Shdr; +typedef Elf32_Phdr Elf_Phdr; typedef Elf32_Sym Elf_Sym; #if !defined(_ALLBSD_SOURCE) || defined(__APPLE__) @@ -123,6 +125,14 @@ ElfFile* next() const { return m_next; } void set_next(ElfFile* file) { m_next = file; } + public: + // Returns true if the elf file is marked NOT to require an executable stack, + // or if the file could not be opened. + // Returns false if the elf file requires an executable stack, the stack flag + // is not set at all, or if the file can not be read. + // On systems other than linux it always returns false. + bool specifies_noexecstack() NOT_LINUX({ return false; }); + protected: ElfFile* m_next; diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/utilities/globalDefinitions.cpp --- a/src/share/vm/utilities/globalDefinitions.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/utilities/globalDefinitions.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/utilities/globalDefinitions.hpp --- a/src/share/vm/utilities/globalDefinitions.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/utilities/globalDefinitions.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 @@ -827,6 +845,10 @@ return comp_level == CompLevel_highest_tier; } +inline bool is_compile(int comp_level) { + return is_c1_compile(comp_level) || is_c2_compile(comp_level); +} + //---------------------------------------------------------------------------------------------------- // 'Forward' declarations of frequently used classes // (in order to reduce interface dependencies & reduce @@ -1296,4 +1318,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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/utilities/numberSeq.cpp --- a/src/share/vm/utilities/numberSeq.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/utilities/numberSeq.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -245,7 +245,7 @@ void NumberSeq::dump_on(outputStream* s) { AbsSeq::dump_on(s); - s->print_cr("\t\t _last = %7.3f, _maximum = %7.3f"); + s->print_cr("\t\t _last = %7.3f, _maximum = %7.3f", _last, _maximum); } void TruncatedSeq::dump_on(outputStream* s) { diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/utilities/taskqueue.hpp --- a/src/share/vm/utilities/taskqueue.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/utilities/taskqueue.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -253,6 +253,7 @@ template class GenericTaskQueue: public TaskQueueSuper { + ArrayAllocator _array_allocator; protected: typedef typename TaskQueueSuper::Age Age; typedef typename TaskQueueSuper::idx_t idx_t; @@ -314,7 +315,7 @@ template void GenericTaskQueue::initialize() { - _elems = NEW_C_HEAP_ARRAY(E, N, F); + _elems = _array_allocator.allocate(N); } template diff -r 0298d8a0caf5 -r 79b098d44d20 src/share/vm/utilities/utf8.cpp --- a/src/share/vm/utilities/utf8.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/utilities/utf8.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/utilities/utf8.hpp --- a/src/share/vm/utilities/utf8.hpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/utilities/utf8.hpp Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 src/share/vm/utilities/vmError.cpp --- a/src/share/vm/utilities/vmError.cpp Thu Apr 04 11:57:04 2013 +0200 +++ b/src/share/vm/utilities/vmError.cpp Mon Apr 15 08:51:19 2013 +0200 @@ -685,13 +685,7 @@ STEP(190, "(printing heap information)" ) if (_verbose && Universe::is_fully_initialized()) { - // Print heap information before vm abort. As we'd like as much - // information as possible in the report we ask for the - // extended (i.e., more detailed) version. - Universe::print_on(st, true /* extended */); - st->cr(); - - Universe::heap()->barrier_set()->print_on(st); + Universe::heap()->print_on_error(st); st->cr(); st->print_cr("Polling page: " INTPTR_FORMAT, os::get_polling_page()); diff -r 0298d8a0caf5 -r 79b098d44d20 test/compiler/5091921/Test6890943.sh --- a/test/compiler/5091921/Test6890943.sh Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/5091921/Test6890943.sh Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/compiler/5091921/Test7005594.sh --- a/test/compiler/5091921/Test7005594.sh Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/5091921/Test7005594.sh Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/compiler/6431242/Test.java --- a/test/compiler/6431242/Test.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/6431242/Test.java Mon Apr 15 08:51:19 2013 +0200 @@ -25,7 +25,7 @@ /* * @test * @bug 6431242 - * @run main/othervm -server -XX:+PrintCompilation Test + * @run main Test */ public class Test{ diff -r 0298d8a0caf5 -r 79b098d44d20 test/compiler/6589834/Test_ia32.java --- a/test/compiler/6589834/Test_ia32.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/6589834/Test_ia32.java Mon Apr 15 08:51:19 2013 +0200 @@ -26,7 +26,7 @@ * @bug 6589834 * @summary deoptimization problem with -XX:+DeoptimizeALot * - * @run main/othervm -server Test_ia32 + * @run main Test_ia32 */ /*************************************************************************************** diff -r 0298d8a0caf5 -r 79b098d44d20 test/compiler/6636138/Test1.java --- a/test/compiler/6636138/Test1.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/6636138/Test1.java Mon Apr 15 08:51:19 2013 +0200 @@ -26,7 +26,7 @@ * @bug 6636138 * @summary SuperWord::co_locate_pack(Node_List* p) generates memory graph that leads to memory order violation. * - * @run main/othervm -server -Xbatch -XX:CompileOnly=Test1.init Test1 + * @run main/othervm -Xbatch -XX:CompileOnly=Test1.init Test1 */ public class Test1 { diff -r 0298d8a0caf5 -r 79b098d44d20 test/compiler/6636138/Test2.java --- a/test/compiler/6636138/Test2.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/6636138/Test2.java Mon Apr 15 08:51:19 2013 +0200 @@ -26,7 +26,7 @@ * @bug 6636138 * @summary SuperWord::co_locate_pack(Node_List* p) generates memory graph that leads to memory order violation. * - * @run main/othervm -server -Xbatch -XX:CompileOnly=Test2.shift Test2 + * @run main/othervm -Xbatch -XX:CompileOnly=Test2.shift Test2 */ public class Test2 { diff -r 0298d8a0caf5 -r 79b098d44d20 test/compiler/6795161/Test.java --- a/test/compiler/6795161/Test.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/6795161/Test.java Mon Apr 15 08:51:19 2013 +0200 @@ -26,7 +26,7 @@ * @test * @bug 6795161 * @summary Escape analysis leads to data corruption - * @run main/othervm -server -XX:+IgnoreUnrecognizedVMOptions -Xcomp -XX:CompileOnly=Test -XX:+DoEscapeAnalysis Test + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xcomp -XX:CompileOnly=Test -XX:+DoEscapeAnalysis Test */ class Test_Class_1 { diff -r 0298d8a0caf5 -r 79b098d44d20 test/compiler/6857159/Test6857159.sh --- a/test/compiler/6857159/Test6857159.sh Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/6857159/Test6857159.sh Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/compiler/6863420/Test.java --- a/test/compiler/6863420/Test.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/6863420/Test.java Mon Apr 15 08:51:19 2013 +0200 @@ -27,17 +27,35 @@ * @bug 6863420 * @summary os::javaTimeNanos() go backward on Solaris x86 * - * @run main/othervm Test + * Notice the internal timeout in timeout thread Test.TOT. + * @run main/othervm/timeout=300 Test */ public class Test { + + static final int INTERNAL_TIMEOUT=240; + static class TOT extends Thread { + public void run() { + try { + Thread.sleep(INTERNAL_TIMEOUT*1000); + } catch (InterruptedException ex) { + } + done = true; + } + } + static long value = 0; static boolean got_backward_time = false; + static volatile boolean done = false; public static void main(String args[]) { final int count = 100000; - for (int numThreads = 1; numThreads <= 32; numThreads++) { + TOT tot = new TOT(); + tot.setDaemon(true); + tot.start(); + + for (int numThreads = 1; !done && numThreads <= 32; numThreads++) { final int numRuns = 1; for (int t=1; t <= numRuns; t++) { final int curRun = t; @@ -48,7 +66,7 @@ Runnable thread = new Runnable() { public void run() { - for (long l = 0; l < 100000; l++) { + for (long l = 0; !done && l < 100000; l++) { final long start = System.nanoTime(); if (value == 12345678) { System.out.println("Wow!"); diff -r 0298d8a0caf5 -r 79b098d44d20 test/compiler/6946040/TestCharShortByteSwap.java --- a/test/compiler/6946040/TestCharShortByteSwap.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/6946040/TestCharShortByteSwap.java Mon Apr 15 08:51:19 2013 +0200 @@ -26,7 +26,7 @@ * @test * @bug 6946040 * @summary Tests Character/Short.reverseBytes and their intrinsics implementation in the server compiler - * @run main/othervm -Xbatch -server -XX:CompileOnly=.testChar,.testShort TestCharShortByteSwap + * @run main/othervm -Xbatch -XX:CompileOnly=.testChar,.testShort TestCharShortByteSwap */ // This test must run without any command line arguments. diff -r 0298d8a0caf5 -r 79b098d44d20 test/compiler/7068051/Test7068051.sh --- a/test/compiler/7068051/Test7068051.sh Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/7068051/Test7068051.sh Mon Apr 15 08:51:19 2013 +0200 @@ -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 -showversion -Xbatch ${TESTVMOPTS} Test7068051 foo.jar +${TESTJAVA}/bin/java ${TESTVMOPTS} -showversion -Xbatch Test7068051 foo.jar diff -r 0298d8a0caf5 -r 79b098d44d20 test/compiler/7070134/Test7070134.sh --- a/test/compiler/7070134/Test7070134.sh Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/7070134/Test7070134.sh Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/compiler/7200264/Test7200264.sh --- a/test/compiler/7200264/Test7200264.sh Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/7200264/Test7200264.sh Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/compiler/8000805/Test8000805.java --- a/test/compiler/8000805/Test8000805.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/8000805/Test8000805.java Mon Apr 15 08:51:19 2013 +0200 @@ -26,7 +26,7 @@ * @bug 8000805 * @summary JMM issue: short loads are non-atomic * - * @run main/othervm -server -XX:-TieredCompilation -Xcomp -XX:+PrintCompilation -XX:CompileOnly=Test8000805.loadS2LmaskFF,Test8000805.loadS2Lmask16,Test8000805.loadS2Lmask13,Test8000805.loadUS_signExt,Test8000805.loadB2L_mask8 Test8000805 + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -Xcomp -XX:+PrintCompilation -XX:CompileOnly=Test8000805.loadS2LmaskFF,Test8000805.loadS2Lmask16,Test8000805.loadS2Lmask13,Test8000805.loadUS_signExt,Test8000805.loadB2L_mask8 Test8000805 */ public class Test8000805 { diff -r 0298d8a0caf5 -r 79b098d44d20 test/compiler/8009761/Test8009761.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/8009761/Test8009761.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,255 @@ +/* + * 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 8009761 + * @summary Deoptimization on sparc doesn't set Llast_SP correctly in the interpreter frames it creates + * @run main/othervm -Xmixed -XX:-UseOnStackReplacement -XX:-BackgroundCompilation Test8009761 + * + */ + +public class Test8009761 { + + static class UnloadedClass { + volatile int i; + } + + static Object m1(boolean deopt) { + // When running interpreted, on sparc, the caller's stack is + // extended for the locals and the caller's frame is restored + // on return. + long l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, + l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, + l25, l26, l27, l28, l29, l30, l31, l32, l33, l34, l35, l36, + l37, l38, l39, l40, l41, l42, l43, l44, l45, l46, l47, l48, + l49, l50, l51, l52, l53, l54, l55, l56, l57, l58, l59, l60, + l61, l62, l63, l64, l65, l66, l67, l68, l69, l70, l71, l72, + l73, l74, l75, l76, l77, l78, l79, l80, l81, l82, l83, l84, + l85, l86, l87, l88, l89, l90, l91, l92, l93, l94, l95, l96, + l97, l98, l99, l100, l101, l102, l103, l104, l105, l106, l107, + l108, l109, l110, l111, l112, l113, l114, l115, l116, l117, + l118, l119, l120, l121, l122, l123, l124, l125, l126, l127, + l128, l129, l130, l131, l132, l133, l134, l135, l136, l137, + l138, l139, l140, l141, l142, l143, l144, l145, l146, l147, + l148, l149, l150, l151, l152, l153, l154, l155, l156, l157, + l158, l159, l160, l161, l162, l163, l164, l165, l166, l167, + l168, l169, l170, l171, l172, l173, l174, l175, l176, l177, + l178, l179, l180, l181, l182, l183, l184, l185, l186, l187, + l188, l189, l190, l191, l192, l193, l194, l195, l196, l197, + l198, l199, l200, l201, l202, l203, l204, l205, l206, l207, + l208, l209, l210, l211, l212, l213, l214, l215, l216, l217, + l218, l219, l220, l221, l222, l223, l224, l225, l226, l227, + l228, l229, l230, l231, l232, l233, l234, l235, l236, l237, + l238, l239, l240, l241, l242, l243, l244, l245, l246, l247, + l248, l249, l250, l251, l252, l253, l254, l255, l256, l257, + l258, l259, l260, l261, l262, l263, l264, l265, l266, l267, + l268, l269, l270, l271, l272, l273, l274, l275, l276, l277, + l278, l279, l280, l281, l282, l283, l284, l285, l286, l287, + l288, l289, l290, l291, l292, l293, l294, l295, l296, l297, + l298, l299, l300, l301, l302, l303, l304, l305, l306, l307, + l308, l309, l310, l311, l312, l313, l314, l315, l316, l317, + l318, l319, l320, l321, l322, l323, l324, l325, l326, l327, + l328, l329, l330, l331, l332, l333, l334, l335, l336, l337, + l338, l339, l340, l341, l342, l343, l344, l345, l346, l347, + l348, l349, l350, l351, l352, l353, l354, l355, l356, l357, + l358, l359, l360, l361, l362, l363, l364, l365, l366, l367, + l368, l369, l370, l371, l372, l373, l374, l375, l376, l377, + l378, l379, l380, l381, l382, l383, l384, l385, l386, l387, + l388, l389, l390, l391, l392, l393, l394, l395, l396, l397, + l398, l399, l400, l401, l402, l403, l404, l405, l406, l407, + l408, l409, l410, l411, l412, l413, l414, l415, l416, l417, + l418, l419, l420, l421, l422, l423, l424, l425, l426, l427, + l428, l429, l430, l431, l432, l433, l434, l435, l436, l437, + l438, l439, l440, l441, l442, l443, l444, l445, l446, l447, + l448, l449, l450, l451, l452, l453, l454, l455, l456, l457, + l458, l459, l460, l461, l462, l463, l464, l465, l466, l467, + l468, l469, l470, l471, l472, l473, l474, l475, l476, l477, + l478, l479, l480, l481, l482, l483, l484, l485, l486, l487, + l488, l489, l490, l491, l492, l493, l494, l495, l496, l497, + l498, l499, l500, l501, l502, l503, l504, l505, l506, l507, + l508, l509, l510, l511; + + long ll0, ll1, ll2, ll3, ll4, ll5, ll6, ll7, ll8, ll9, ll10, ll11, ll12, + ll13, ll14, ll15, ll16, ll17, ll18, ll19, ll20, ll21, ll22, ll23, ll24, + ll25, ll26, ll27, ll28, ll29, ll30, ll31, ll32, ll33, ll34, ll35, ll36, + ll37, ll38, ll39, ll40, ll41, ll42, ll43, ll44, ll45, ll46, ll47, ll48, + ll49, ll50, ll51, ll52, ll53, ll54, ll55, ll56, ll57, ll58, ll59, ll60, + ll61, ll62, ll63, ll64, ll65, ll66, ll67, ll68, ll69, ll70, ll71, ll72, + ll73, ll74, ll75, ll76, ll77, ll78, ll79, ll80, ll81, ll82, ll83, ll84, + ll85, ll86, ll87, ll88, ll89, ll90, ll91, ll92, ll93, ll94, ll95, ll96, + ll97, ll98, ll99, ll100, ll101, ll102, ll103, ll104, ll105, ll106, ll107, + ll108, ll109, ll110, ll111, ll112, ll113, ll114, ll115, ll116, ll117, + ll118, ll119, ll120, ll121, ll122, ll123, ll124, ll125, ll126, ll127, + ll128, ll129, ll130, ll131, ll132, ll133, ll134, ll135, ll136, ll137, + ll138, ll139, ll140, ll141, ll142, ll143, ll144, ll145, ll146, ll147, + ll148, ll149, ll150, ll151, ll152, ll153, ll154, ll155, ll156, ll157, + ll158, ll159, ll160, ll161, ll162, ll163, ll164, ll165, ll166, ll167, + ll168, ll169, ll170, ll171, ll172, ll173, ll174, ll175, ll176, ll177, + ll178, ll179, ll180, ll181, ll182, ll183, ll184, ll185, ll186, ll187, + ll188, ll189, ll190, ll191, ll192, ll193, ll194, ll195, ll196, ll197, + ll198, ll199, ll200, ll201, ll202, ll203, ll204, ll205, ll206, ll207, + ll208, ll209, ll210, ll211, ll212, ll213, ll214, ll215, ll216, ll217, + ll218, ll219, ll220, ll221, ll222, ll223, ll224, ll225, ll226, ll227, + ll228, ll229, ll230, ll231, ll232, ll233, ll234, ll235, ll236, ll237, + ll238, ll239, ll240, ll241, ll242, ll243, ll244, ll245, ll246, ll247, + ll248, ll249, ll250, ll251, ll252, ll253, ll254, ll255, ll256, ll257, + ll258, ll259, ll260, ll261, ll262, ll263, ll264, ll265, ll266, ll267, + ll268, ll269, ll270, ll271, ll272, ll273, ll274, ll275, ll276, ll277, + ll278, ll279, ll280, ll281, ll282, ll283, ll284, ll285, ll286, ll287, + ll288, ll289, ll290, ll291, ll292, ll293, ll294, ll295, ll296, ll297, + ll298, ll299, ll300, ll301, ll302, ll303, ll304, ll305, ll306, ll307, + ll308, ll309, ll310, ll311, ll312, ll313, ll314, ll315, ll316, ll317, + ll318, ll319, ll320, ll321, ll322, ll323, ll324, ll325, ll326, ll327, + ll328, ll329, ll330, ll331, ll332, ll333, ll334, ll335, ll336, ll337, + ll338, ll339, ll340, ll341, ll342, ll343, ll344, ll345, ll346, ll347, + ll348, ll349, ll350, ll351, ll352, ll353, ll354, ll355, ll356, ll357, + ll358, ll359, ll360, ll361, ll362, ll363, ll364, ll365, ll366, ll367, + ll368, ll369, ll370, ll371, ll372, ll373, ll374, ll375, ll376, ll377, + ll378, ll379, ll380, ll381, ll382, ll383, ll384, ll385, ll386, ll387, + ll388, ll389, ll390, ll391, ll392, ll393, ll394, ll395, ll396, ll397, + ll398, ll399, ll400, ll401, ll402, ll403, ll404, ll405, ll406, ll407, + ll408, ll409, ll410, ll411, ll412, ll413, ll414, ll415, ll416, ll417, + ll418, ll419, ll420, ll421, ll422, ll423, ll424, ll425, ll426, ll427, + ll428, ll429, ll430, ll431, ll432, ll433, ll434, ll435, ll436, ll437, + ll438, ll439, ll440, ll441, ll442, ll443, ll444, ll445, ll446, ll447, + ll448, ll449, ll450, ll451, ll452, ll453, ll454, ll455, ll456, ll457, + ll458, ll459, ll460, ll461, ll462, ll463, ll464, ll465, ll466, ll467, + ll468, ll469, ll470, ll471, ll472, ll473, ll474, ll475, ll476, ll477, + ll478, ll479, ll480, ll481, ll482, ll483, ll484, ll485, ll486, ll487, + ll488, ll489, ll490, ll491, ll492, ll493, ll494, ll495, ll496, ll497, + ll498, ll499, ll500, ll501, ll502, ll503, ll504, ll505, ll506, ll507, + ll508, ll509, ll510, ll511; + + if (deopt) { + UnloadedClass res = new UnloadedClass(); // sufficient to force deopt with c2 but not c1 + res.i = 0; // forces deopt with c1 + return res; + } + return null; + } + + static int count = 0; + + static void m2() { + // Will be called recursively until a stack overflow + // exception. Makes sure it has a lot of locals so that it's + // not called a sufficient number of times to trigger + // compilation. + + long l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, + l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, + l25, l26, l27, l28, l29, l30, l31, l32, l33, l34, l35, l36, + l37, l38, l39, l40, l41, l42, l43, l44, l45, l46, l47, l48, + l49, l50, l51, l52, l53, l54, l55, l56, l57, l58, l59, l60, + l61, l62, l63, l64, l65, l66, l67, l68, l69, l70, l71, l72, + l73, l74, l75, l76, l77, l78, l79, l80, l81, l82, l83, l84, + l85, l86, l87, l88, l89, l90, l91, l92, l93, l94, l95, l96, + l97, l98, l99, l100, l101, l102, l103, l104, l105, l106, l107, + l108, l109, l110, l111, l112, l113, l114, l115, l116, l117, + l118, l119, l120, l121, l122, l123, l124, l125, l126, l127, + l128, l129, l130, l131, l132, l133, l134, l135, l136, l137, + l138, l139, l140, l141, l142, l143, l144, l145, l146, l147, + l148, l149, l150, l151, l152, l153, l154, l155, l156, l157, + l158, l159, l160, l161, l162, l163, l164, l165, l166, l167, + l168, l169, l170, l171, l172, l173, l174, l175, l176, l177, + l178, l179, l180, l181, l182, l183, l184, l185, l186, l187, + l188, l189, l190, l191, l192, l193, l194, l195, l196, l197, + l198, l199, l200, l201, l202, l203, l204, l205, l206, l207, + l208, l209, l210, l211, l212, l213, l214, l215, l216, l217, + l218, l219, l220, l221, l222, l223, l224, l225, l226, l227, + l228, l229, l230, l231, l232, l233, l234, l235, l236, l237, + l238, l239, l240, l241, l242, l243, l244, l245, l246, l247, + l248, l249, l250, l251, l252, l253, l254, l255, l256, l257, + l258, l259, l260, l261, l262, l263, l264, l265, l266, l267, + l268, l269, l270, l271, l272, l273, l274, l275, l276, l277, + l278, l279, l280, l281, l282, l283, l284, l285, l286, l287, + l288, l289, l290, l291, l292, l293, l294, l295, l296, l297, + l298, l299, l300, l301, l302, l303, l304, l305, l306, l307, + l308, l309, l310, l311, l312, l313, l314, l315, l316, l317, + l318, l319, l320, l321, l322, l323, l324, l325, l326, l327, + l328, l329, l330, l331, l332, l333, l334, l335, l336, l337, + l338, l339, l340, l341, l342, l343, l344, l345, l346, l347, + l348, l349, l350, l351, l352, l353, l354, l355, l356, l357, + l358, l359, l360, l361, l362, l363, l364, l365, l366, l367, + l368, l369, l370, l371, l372, l373, l374, l375, l376, l377, + l378, l379, l380, l381, l382, l383, l384, l385, l386, l387, + l388, l389, l390, l391, l392, l393, l394, l395, l396, l397, + l398, l399, l400, l401, l402, l403, l404, l405, l406, l407, + l408, l409, l410, l411, l412, l413, l414, l415, l416, l417, + l418, l419, l420, l421, l422, l423, l424, l425, l426, l427, + l428, l429, l430, l431, l432, l433, l434, l435, l436, l437, + l438, l439, l440, l441, l442, l443, l444, l445, l446, l447, + l448, l449, l450, l451, l452, l453, l454, l455, l456, l457, + l458, l459, l460, l461, l462, l463, l464, l465, l466, l467, + l468, l469, l470, l471, l472, l473, l474, l475, l476, l477, + l478, l479, l480, l481, l482, l483, l484, l485, l486, l487, + l488, l489, l490, l491, l492, l493, l494, l495, l496, l497, + l498, l499, l500, l501, l502, l503, l504, l505, l506, l507, + l508, l509, l510, l511; + + count++; + m2(); + } + + static Object m3(boolean overflow_stack, boolean deopt) { + if (overflow_stack) { + m2(); + return null; + } + Object o = m1(deopt); + if (deopt) { + m2(); + } + return o; + } + + static public void main(String[] args) { + int c1; + // Call m2 from m3 recursively until stack overflow. Count the number of recursive calls. + try { + m3(true, false); + } catch(StackOverflowError soe) { + } + c1 = count; + // Force the compilation of m3() that will inline m1() + for (int i = 0; i < 20000; i++) { + m3(false, false); + } + count = 0; + // Force deoptimization of m3() in m1(), then return from m1() + // to m3(), call recursively m2(). If deoptimization correctly + // built the interpreter stack for m3()/m1() then we should be + // able to call m2() recursively as many times as before. + try { + m3(false, true); + } catch(StackOverflowError soe) { + } + if (c1 != count) { + System.out.println("Failed: init recursive calls: " + c1 + ". After deopt " + count); + System.exit(97); + } else { + System.out.println("PASSED"); + } + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 test/compiler/8011706/Test8011706.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/8011706/Test8011706.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,65 @@ +/* + * 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 8011706 + * @summary loop invariant code motion may move load before store to the same field + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation Test8011706 + * + */ + +public class Test8011706 { + int[] array; + + void m(boolean test, int[] array1, int[] array2) { + int i = 0; + if (test) { + array = array1; + } else { + array = array2; + } + + while(true) { + int v = array[i]; + i++; + if (i >= 10) return; + } + } + + static public void main(String[] args) { + int[] new_array = new int[10]; + Test8011706 ti = new Test8011706(); + boolean failed = false; + try { + for (int i = 0; i < 10000; i++) { + ti.array = null; + ti.m(true, new_array, new_array); + } + } catch(NullPointerException ex) { + throw new RuntimeException("TEST FAILED", ex); + } + System.out.println("TEST PASSED"); + } + +} diff -r 0298d8a0caf5 -r 79b098d44d20 test/compiler/whitebox/ClearMethodStateTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/whitebox/ClearMethodStateTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,71 @@ +/* + * 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 ClearMethodStateTest + * @library /testlibrary /testlibrary/whitebox + * @build ClearMethodStateTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ClearMethodStateTest + * @author igor.ignatyev@oracle.com + */ +public class ClearMethodStateTest extends CompilerWhiteBoxTest { + public static void main(String[] args) throws Exception { + // to prevent inlining #method into #compile() and #test() + WHITE_BOX.testSetDontInlineMethod(METHOD, true); + new ClearMethodStateTest().runTest(); + } + + protected void test() throws Exception { + checkNotCompiled(METHOD); + compile(); + checkCompiled(METHOD); + WHITE_BOX.clearMethodState(METHOD); + WHITE_BOX.deoptimizeMethod(METHOD); + checkNotCompiled(METHOD); + + + if (!TIERED_COMPILATION) { + WHITE_BOX.clearMethodState(METHOD); + compile(COMPILE_THRESHOLD); + checkCompiled(METHOD); + + WHITE_BOX.deoptimizeMethod(METHOD); + checkNotCompiled(METHOD); + WHITE_BOX.clearMethodState(METHOD); + + if (COMPILE_THRESHOLD > 1) { + compile(COMPILE_THRESHOLD - 1); + checkNotCompiled(METHOD); + } else { + System.err.println("Warning: 'CompileThreshold' <= 1"); + } + + method(); + checkCompiled(METHOD); + } else { + System.err.println( + "Warning: part of test is not applicable in Tiered"); + } + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 test/compiler/whitebox/CompilerWhiteBoxTest.java --- a/test/compiler/whitebox/CompilerWhiteBoxTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/whitebox/CompilerWhiteBoxTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -35,6 +35,10 @@ 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 final boolean TIERED_COMPILATION + = Boolean.valueOf(getVMOption("TieredCompilation", "false")); protected static Method getMethod(String name) { try { @@ -45,11 +49,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 +75,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:"); @@ -73,6 +83,9 @@ } protected static void checkNotCompiled(Method method) { + if (WHITE_BOX.isMethodQueuedForCompilation(method)) { + throw new RuntimeException(method + " must not be in queue"); + } if (WHITE_BOX.isMethodCompiled(method)) { throw new RuntimeException(method + " must be not compiled"); } @@ -100,6 +113,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) { @@ -128,14 +144,18 @@ protected abstract void test() throws Exception; protected final int compile() { + return compile(Math.max(COMPILE_THRESHOLD, 150000)); + } + + protected final int compile(int count) { int result = 0; - for (int i = 0; i < COMPILE_THRESHOLD; ++i) { + 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 0298d8a0caf5 -r 79b098d44d20 test/compiler/whitebox/DeoptimizeAllTest.java --- a/test/compiler/whitebox/DeoptimizeAllTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/whitebox/DeoptimizeAllTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -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.testSetDontInlineMethod(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 0298d8a0caf5 -r 79b098d44d20 test/compiler/whitebox/DeoptimizeMethodTest.java --- a/test/compiler/whitebox/DeoptimizeMethodTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/whitebox/DeoptimizeMethodTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -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.testSetDontInlineMethod(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 0298d8a0caf5 -r 79b098d44d20 test/compiler/whitebox/EnqueueMethodForCompilationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/whitebox/EnqueueMethodForCompilationTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 EnqueueMethodForCompilationTest + * @library /testlibrary /testlibrary/whitebox + * @build EnqueueMethodForCompilationTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI EnqueueMethodForCompilationTest + * @author igor.ignatyev@oracle.com + */ +public class EnqueueMethodForCompilationTest extends CompilerWhiteBoxTest { + public static void main(String[] args) throws Exception { + // to prevent inlining #method into #compile() + WHITE_BOX.testSetDontInlineMethod(METHOD, true); + new EnqueueMethodForCompilationTest().runTest(); + } + + protected void test() throws Exception { + checkNotCompiled(METHOD); + + WHITE_BOX.enqueueMethodForCompilation(METHOD, 0); + if (WHITE_BOX.isMethodCompilable(METHOD, 0)) { + throw new RuntimeException(METHOD + " is compilable at level 0"); + } + checkNotCompiled(METHOD); + + WHITE_BOX.enqueueMethodForCompilation(METHOD, -1); + checkNotCompiled(METHOD); + + WHITE_BOX.enqueueMethodForCompilation(METHOD, 5); + if (!WHITE_BOX.isMethodCompilable(METHOD, 5)) { + checkNotCompiled(METHOD); + compile(); + checkCompiled(METHOD); + } else { + checkCompiled(METHOD); + } + + int compLevel = WHITE_BOX.getMethodCompilationLevel(METHOD); + WHITE_BOX.deoptimizeMethod(METHOD); + checkNotCompiled(METHOD); + + WHITE_BOX.enqueueMethodForCompilation(METHOD, compLevel); + checkCompiled(METHOD); + WHITE_BOX.deoptimizeMethod(METHOD); + checkNotCompiled(METHOD); + + compile(); + checkCompiled(METHOD); + WHITE_BOX.deoptimizeMethod(METHOD); + checkNotCompiled(METHOD); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 test/compiler/whitebox/IsMethodCompilableTest.java --- a/test/compiler/whitebox/IsMethodCompilableTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/whitebox/IsMethodCompilableTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -44,6 +44,8 @@ } public static void main(String[] args) throws Exception { + // to prevent inlining #method into #compile() + WHITE_BOX.testSetDontInlineMethod(METHOD, true); new IsMethodCompilableTest().runTest(); } @@ -58,28 +60,47 @@ "Warning: test is not applicable if PerMethodRecompilationCutoff == Inf"); return; } - // to prevent inlining #method into #compile() - WHITE_BOX.setDontInlineMethod(METHOD, true); - boolean madeNotCompilable = false; + + // deoptimze 'PerMethodRecompilationCutoff' times and clear state + for (long i = 0L, n = PER_METHOD_RECOMPILATION_CUTOFF - 1; i < n; ++i) { + compileAndDeoptimaze(); + } + if (!WHITE_BOX.isMethodCompilable(METHOD)) { + throw new RuntimeException(METHOD + " is not compilable after " + + (PER_METHOD_RECOMPILATION_CUTOFF - 1) + " iterations"); + } + WHITE_BOX.clearMethodState(METHOD); - for (long i = 0; i < PER_METHOD_RECOMPILATION_CUTOFF; ++i) { - compile(); - waitBackgroundCompilation(METHOD); - WHITE_BOX.deoptimizeMethod(METHOD); - if (!WHITE_BOX.isMethodCompilable(METHOD)) { - madeNotCompilable = true; - break; - } + // deoptimze 'PerMethodRecompilationCutoff' + 1 times + long i; + for (i = 0L; i < PER_METHOD_RECOMPILATION_CUTOFF + && WHITE_BOX.isMethodCompilable(METHOD); ++i) { + compileAndDeoptimaze(); } - if (!madeNotCompilable) { + if (i != PER_METHOD_RECOMPILATION_CUTOFF) { + throw new RuntimeException(METHOD + " is not compilable after " + + i + " iterations, but must only after " + + PER_METHOD_RECOMPILATION_CUTOFF); + } + if (WHITE_BOX.isMethodCompilable(METHOD)) { throw new RuntimeException(METHOD + " is still compilable after " + PER_METHOD_RECOMPILATION_CUTOFF + " iterations"); } compile(); - if (WHITE_BOX.isMethodCompiled(METHOD)) { - printInfo(METHOD); - throw new RuntimeException( - METHOD + " is not compilable but compiled"); + checkNotCompiled(METHOD); + + WHITE_BOX.clearMethodState(METHOD); + if (!WHITE_BOX.isMethodCompilable(METHOD)) { + throw new RuntimeException(METHOD + + " is compilable after clearMethodState()"); } + compile(); + checkCompiled(METHOD); + } + + private void compileAndDeoptimaze() throws Exception { + compile(); + waitBackgroundCompilation(METHOD); + WHITE_BOX.deoptimizeMethod(METHOD); } } diff -r 0298d8a0caf5 -r 79b098d44d20 test/compiler/whitebox/MakeMethodNotCompilableTest.java --- a/test/compiler/whitebox/MakeMethodNotCompilableTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/whitebox/MakeMethodNotCompilableTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -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.testSetDontInlineMethod(METHOD, true); new MakeMethodNotCompilableTest().runTest(); } @@ -44,9 +46,6 @@ throw new RuntimeException(METHOD + " must be not compilable"); } compile(); - if (WHITE_BOX.isMethodQueuedForCompilation(METHOD)) { - throw new RuntimeException(METHOD + " must not be in queue"); - } checkNotCompiled(METHOD); if (WHITE_BOX.isMethodCompilable(METHOD)) { throw new RuntimeException(METHOD + " must be not compilable"); diff -r 0298d8a0caf5 -r 79b098d44d20 test/compiler/whitebox/SetDontInlineMethodTest.java --- a/test/compiler/whitebox/SetDontInlineMethodTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/compiler/whitebox/SetDontInlineMethodTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -36,23 +36,23 @@ } protected void test() throws Exception { - if (WHITE_BOX.setDontInlineMethod(METHOD, true)) { + if (WHITE_BOX.testSetDontInlineMethod(METHOD, true)) { throw new RuntimeException("on start " + METHOD + " must be inlineable"); } - if (!WHITE_BOX.setDontInlineMethod(METHOD, true)) { + if (!WHITE_BOX.testSetDontInlineMethod(METHOD, true)) { throw new RuntimeException("after first change to true " + METHOD + " must be not inlineable"); } - if (!WHITE_BOX.setDontInlineMethod(METHOD, false)) { + if (!WHITE_BOX.testSetDontInlineMethod(METHOD, false)) { throw new RuntimeException("after second change to true " + METHOD + " must be still not inlineable"); } - if (WHITE_BOX.setDontInlineMethod(METHOD, false)) { + if (WHITE_BOX.testSetDontInlineMethod(METHOD, false)) { throw new RuntimeException("after first change to false" + METHOD + " must be inlineable"); } - if (WHITE_BOX.setDontInlineMethod(METHOD, false)) { + if (WHITE_BOX.testSetDontInlineMethod(METHOD, false)) { throw new RuntimeException("after second change to false " + METHOD + " must be inlineable"); } diff -r 0298d8a0caf5 -r 79b098d44d20 test/compiler/whitebox/SetForceInlineMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/whitebox/SetForceInlineMethodTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,60 @@ +/* + * 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 SetForceInlineMethodTest + * @library /testlibrary /testlibrary/whitebox + * @build SetForceInlineMethodTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SetForceInlineMethodTest + * @author igor.ignatyev@oracle.com + */ +public class SetForceInlineMethodTest extends CompilerWhiteBoxTest { + + public static void main(String[] args) throws Exception { + new SetForceInlineMethodTest().runTest(); + } + + protected void test() throws Exception { + if (WHITE_BOX.testSetForceInlineMethod(METHOD, true)) { + throw new RuntimeException("on start " + METHOD + + " must be not force inlineable"); + } + if (!WHITE_BOX.testSetForceInlineMethod(METHOD, true)) { + throw new RuntimeException("after first change to true " + METHOD + + " must be force inlineable"); + } + if (!WHITE_BOX.testSetForceInlineMethod(METHOD, false)) { + throw new RuntimeException("after second change to true " + METHOD + + " must be still force inlineable"); + } + if (WHITE_BOX.testSetForceInlineMethod(METHOD, false)) { + throw new RuntimeException("after first change to false" + METHOD + + " must be not force inlineable"); + } + if (WHITE_BOX.testSetForceInlineMethod(METHOD, false)) { + throw new RuntimeException("after second change to false " + METHOD + + " must be not force inlineable"); + } + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 test/gc/6941923/Test6941923.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/6941923/Test6941923.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,121 @@ +/* + * 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. + */ + +/* + * @test Test6941923.java + * @bug 6941923 + * @summary test flags for gc log rotation + * @library /testlibrary + * @run main/othervm/timeout=600 Test6941923 + * + */ +import com.oracle.java.testlibrary.*; +import java.io.File; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.Arrays; + +class GCLoggingGenerator { + + public static void main(String[] args) throws Exception { + + long sizeOfLog = Long.parseLong(args[0]); + long lines = sizeOfLog / 80; + // full.GC generates ad least 1-line which is not shorter then 80 chars + // for some GC 2 shorter lines are generated + for (long i = 0; i < lines; i++) { + System.gc(); + } + } +} + +public class Test6941923 { + + static final File currentDirectory = new File("."); + static final String logFileName = "test.log"; + static final int logFileSizeK = 16; + static FilenameFilter logFilter = new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.startsWith(logFileName); + } + }; + + public static void cleanLogs() { + for (File log : currentDirectory.listFiles(logFilter)) { + if (!log.delete()) { + throw new Error("Unable to delete " + log.getAbsolutePath()); + } + } + } + + public static void runTest(int numberOfFiles) throws Exception { + + ArrayList args = new ArrayList(); + String[] logOpts = new String[]{ + "-cp", System.getProperty("java.class.path"), + "-Xloggc:" + logFileName, + "-XX:-DisableExplicitGC", // to sure that System.gc() works + "-XX:+PrintGC", "-XX:+PrintGCDetails", "-XX:+UseGCLogFileRotation", + "-XX:NumberOfGCLogFiles=" + numberOfFiles, + "-XX:GCLogFileSize=" + logFileSizeK + "K", "-Xmx128M"}; + // System.getProperty("test.java.opts") is '' if no options is set + // need to skip such empty + String[] externalVMopts = System.getProperty("test.java.opts").length() == 0 + ? new String[0] + : System.getProperty("test.java.opts").split(" "); + args.addAll(Arrays.asList(externalVMopts)); + args.addAll(Arrays.asList(logOpts)); + args.add(GCLoggingGenerator.class.getName()); + args.add(String.valueOf(numberOfFiles * logFileSizeK * 1024)); + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args.toArray(new String[0])); + pb.redirectErrorStream(true); + pb.redirectOutput(new File(GCLoggingGenerator.class.getName() + ".log")); + Process process = pb.start(); + int result = process.waitFor(); + if (result != 0) { + throw new Error("Unexpected exit code = " + result); + } + File[] logs = currentDirectory.listFiles(logFilter); + int smallFilesNumber = 0; + for (File log : logs) { + if (log.length() < logFileSizeK * 1024) { + smallFilesNumber++; + } + } + if (logs.length != numberOfFiles) { + throw new Error("There are only " + logs.length + " logs instead " + numberOfFiles); + } + if (smallFilesNumber > 1) { + throw new Error("There should maximum one log with size < " + logFileSizeK + "K"); + } + } + + public static void main(String[] args) throws Exception { + cleanLogs(); + runTest(1); + cleanLogs(); + runTest(3); + cleanLogs(); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 test/gc/6941923/test6941923.sh --- a/test/gc/6941923/test6941923.sh Thu Apr 04 11:57:04 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,179 +0,0 @@ -## -## @test @(#)test6941923.sh -## @bug 6941923 -## @summary test new added flags for gc log rotation -## @author yqi -## @run shell test6941923.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 - rm -rf ${testname}.* -fi - -cat >> ${testname}.java << __EOF__ -import java.util.Vector; - -public class Test implements Runnable -{ - private boolean _should_stop = false; - - public static void main(String[] args) throws Exception { - - long limit = Long.parseLong(args[0]) * 60L * 1000L; // minutes - Test t = new Test(); - t.set_stop(false); - Thread thr = new Thread(t); - thr.start(); - - long time1 = System.currentTimeMillis(); - long time2 = System.currentTimeMillis(); - while (time2 - time1 < limit) { - try { - Thread.sleep(2000); // 2 seconds - } - catch(Exception e) {} - time2 = System.currentTimeMillis(); - System.out.print("\r... " + (time2 - time1)/1000 + " seconds"); - } - System.out.println(); - t.set_stop(true); - } - public void set_stop(boolean value) { _should_stop = value; } - public void run() { - int cap = 20000; - int fix_size = 2048; - int loop = 0; - Vector< byte[] > v = new Vector< byte[] >(cap); - while(!_should_stop) { - byte[] g = new byte[fix_size]; - v.add(g); - loop++; - if (loop > cap) { - v = null; - cap *= 2; - if (cap > 80000) cap = 80000; - v = new Vector< byte[] >(cap); - } - } - } -} -__EOF__ - -msgsuccess="succeeded" -msgfail="failed" -gclogsize="16K" -filesize=$((16*1024)) -$JAVA_HOME/bin/javac ${testname}.java > $NULL 2>&1 - -if [ $? != 0 ]; then - echo "$JAVA_HOME/bin/javac ${testname}.java $fail" - exit -1 -fi - -# test for 2 minutes, it will complete circulation of gc log rotation -tts=2 -logfile="test.log" -hotspotlog="hotspot.log" - -if [ -e $logfile ]; then - rm -rf $logfile -fi - -#also delete $hotspotlog if it exists -if [ -f $hotspotlog ]; then - rm -rf $hotspotlog -fi - -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 -if [ $? != 0 ]; then - echo "$msgfail" - exit -1 -fi - -# rotation file will be $logfile.0 -if [ -f $logfile.0 ]; then - outfilesize=`ls -l $logfile.0 | awk '{print $5 }'` - if [ $((outfilesize)) -ge $((filesize)) ]; then - echo $msgsuccess - else - echo $msgfail - fi -else - echo $msgfail - exit -1 -fi - -# delete log file -rm -rf $logfile.0 -if [ -f $hotspotlog ]; then - rm -rf $hotspotlog -fi - -#multiple log files -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 -if [ $? != 0 ]; then - echo "$msgfail" - exit -1 -fi - -atleast=0 # at least size of numoffile-1 files >= $gclogsize -tk=0 -while [ $(($tk)) -lt $(($numoffiles)) ] -do - if [ -f $logfile.$tk ]; then - outfilesize=`ls -l $logfile.$tk | awk '{ print $5 }'` - if [ $(($outfilesize)) -ge $(($filesize)) ]; then - atleast=$((atleast+1)) - fi - fi - tk=$((tk+1)) -done - -rm -rf $logfile.* -rm -rf $testname.* -rm -rf $hotspotlog - -if [ $(($atleast)) -ge $(($numoffiles-1)) ]; then - echo $msgsuccess -else - echo $msgfail - exit -1 -fi diff -r 0298d8a0caf5 -r 79b098d44d20 test/gc/TestVerifyDuringStartup.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/TestVerifyDuringStartup.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 TestVerifyDuringStartup.java + * @key gc + * @bug 8010463 + * @summary Simple test run with -XX:+VerifyDuringStartup -XX:-UseTLAB to verify 8010463 + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +public class TestVerifyDuringStartup { + public static void main(String args[]) throws Exception { + ProcessBuilder pb = + ProcessTools.createJavaProcessBuilder(System.getProperty("test.vm.opts"), + "-XX:-UseTLAB", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+VerifyDuringStartup", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("[Verifying"); + output.shouldHaveExitValue(0); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 test/gc/metaspace/ClassMetaspaceSizeInJmapHeap.java --- a/test/gc/metaspace/ClassMetaspaceSizeInJmapHeap.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/gc/metaspace/ClassMetaspaceSizeInJmapHeap.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/gc/metaspace/G1AddMetaspaceDependency.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/metaspace/G1AddMetaspaceDependency.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,123 @@ +/* + * 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 G1AddMetaspaceDependency + * @bug 8010196 + * @summary Checks that we don't get locking problems when adding metaspace dependencies with the G1 update buffer monitor + * @run main/othervm -XX:+UseG1GC -XX:G1UpdateBufferSize=1 G1AddMetaspaceDependency + */ + +import java.io.InputStream; + +public class G1AddMetaspaceDependency { + + static byte[] getClassBytes(String name) { + byte[] b = null; + try (InputStream is = ClassLoader.getSystemResourceAsStream(name)) { + byte[] tmp = new byte[is.available()]; + is.read(tmp); + b = tmp; + } finally { + if (b == null) { + throw new RuntimeException("Unable to load class file"); + } + return b; + } + } + + static final String a_name = G1AddMetaspaceDependency.class.getName() + "$A"; + static final String b_name = G1AddMetaspaceDependency.class.getName() + "$B"; + + public static void main(String... args) throws Exception { + final byte[] a_bytes = getClassBytes(a_name + ".class"); + final byte[] b_bytes = getClassBytes(b_name + ".class"); + + for (int i = 0; i < 1000; i += 1) { + runTest(a_bytes, b_bytes); + } + } + + static class Loader extends ClassLoader { + private final String myClass; + private final byte[] myBytes; + private final String friendClass; + private final ClassLoader friendLoader; + + Loader(String myClass, byte[] myBytes, + String friendClass, ClassLoader friendLoader) { + this.myClass = myClass; + this.myBytes = myBytes; + this.friendClass = friendClass; + this.friendLoader = friendLoader; + } + + Loader(String myClass, byte[] myBytes) { + this(myClass, myBytes, null, null); + } + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + Class c = findLoadedClass(name); + if (c != null) { + return c; + } + + if (name.equals(friendClass)) { + return friendLoader.loadClass(name); + } + + if (name.equals(myClass)) { + c = defineClass(name, myBytes, 0, myBytes.length); + resolveClass(c); + return c; + } + + return findSystemClass(name); + } + + } + + private static void runTest(final byte[] a_bytes, final byte[] b_bytes) throws Exception { + Loader a_loader = new Loader(a_name, a_bytes); + Loader b_loader = new Loader(b_name, b_bytes, a_name, a_loader); + Loader c_loader = new Loader(b_name, b_bytes, a_name, a_loader); + Loader d_loader = new Loader(b_name, b_bytes, a_name, a_loader); + Loader e_loader = new Loader(b_name, b_bytes, a_name, a_loader); + Loader f_loader = new Loader(b_name, b_bytes, a_name, a_loader); + Loader g_loader = new Loader(b_name, b_bytes, a_name, a_loader); + + byte[] b = new byte[20 * 2 << 20]; + Class c; + c = b_loader.loadClass(b_name); + c = c_loader.loadClass(b_name); + c = d_loader.loadClass(b_name); + c = e_loader.loadClass(b_name); + c = f_loader.loadClass(b_name); + c = g_loader.loadClass(b_name); + } + public class A { + } + class B extends A { + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 test/runtime/6626217/Test6626217.sh --- a/test/runtime/6626217/Test6626217.sh Thu Apr 04 11:57:04 2013 +0200 +++ b/test/runtime/6626217/Test6626217.sh Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/6878713/Test6878713.sh --- a/test/runtime/6878713/Test6878713.sh Thu Apr 04 11:57:04 2013 +0200 +++ b/test/runtime/6878713/Test6878713.sh Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/6929067/Test6929067.sh --- a/test/runtime/6929067/Test6929067.sh Thu Apr 04 11:57:04 2013 +0200 +++ b/test/runtime/6929067/Test6929067.sh Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/7020373/Test7020373.sh --- a/test/runtime/7020373/Test7020373.sh Thu Apr 04 11:57:04 2013 +0200 +++ b/test/runtime/7020373/Test7020373.sh Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/7051189/Xchecksig.sh --- a/test/runtime/7051189/Xchecksig.sh Thu Apr 04 11:57:04 2013 +0200 +++ b/test/runtime/7051189/Xchecksig.sh Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/7107135/Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/7107135/Test.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2002-2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011 SAP AG. 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. + */ + +class Test { + + static boolean loadLib(String libName){ + try { + System.loadLibrary(libName); + System.out.println("Loaded library "+ libName + "."); + return true; + } catch (SecurityException e) { + System.out.println("loadLibrary(\"" + libName + "\") throws: " + e + "\n"); + } catch (UnsatisfiedLinkError e) { + System.out.println("loadLibrary(\"" + libName + "\") throws: " + e + "\n"); + } + return false; + } + + public static int counter = 1; + + static int Runner() { + counter = counter * -1; + int i = counter; + if(counter < 2) counter += Runner(); + return i; + } + + public static int run() { + try{ + Runner(); + } catch (StackOverflowError e) { + System.out.println("Caught stack overflow error."); + return 0; + } catch (OutOfMemoryError e) { + return 0; + } + return 2; + } + + public static void main(String argv[]) { + loadLib(argv[0]); + System.exit(run()); + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 test/runtime/7107135/Test7107135.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/7107135/Test7107135.sh Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,91 @@ +#!/bin/sh + +# +# Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011 SAP AG. 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 Test7107135.sh +## @bug 7107135 +## @summary Stack guard pages lost after loading library with executable stack. +## @run shell Test7107135.sh +## + +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 + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + Linux) + echo "Testing on Linux" + ;; + *) + NULL=NUL + PS=";" + FS="\\" + echo "Test passed; only valid for Linux" + exit 0; + ;; +esac + +ARCH=`uname -m` + +THIS_DIR=. + +cp ${TESTSRC}${FS}*.java ${THIS_DIR} +${TESTJAVA}${FS}bin${FS}javac *.java + +gcc -fPIC -shared -c -o test.o -I${TESTJAVA}${FS}include -I${TESTJAVA}${FS}include${FS}linux ${TESTSRC}${FS}test.c +ld -shared -z execstack -o libtest-rwx.so test.o +ld -shared -z noexecstack -o libtest-rw.so test.o + + +LD_LIBRARY_PATH=${THIS_DIR} +echo LD_LIBRARY_PATH = ${LD_LIBRARY_PATH} +export LD_LIBRARY_PATH + +# This should not fail. +echo Check testprogram. Expected to pass: +echo ${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} Test test-rw +${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} Test test-rw + +echo +echo Test changing of stack protection: +echo ${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} Test test-rw +${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} Test test-rwx + +if [ "$?" == "0" ] +then + echo + echo ${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} TestMT test-rwx + ${TESTJAVA}${FS}bin${FS}java -cp ${THIS_DIR} TestMT test-rwx +fi + +exit $? diff -r 0298d8a0caf5 -r 79b098d44d20 test/runtime/7107135/TestMT.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/7107135/TestMT.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2002-2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011 SAP AG. 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. + */ + +class TestMT { + + static boolean loadLib(String libName) { + try { + System.loadLibrary(libName); + System.out.println("Loaded library "+ libName + "."); + return true; + } catch (SecurityException e) { + System.out.println("loadLibrary(\"" + libName + "\") throws: " + e + "\n"); + } catch (UnsatisfiedLinkError e) { + System.out.println("loadLibrary(\"" + libName + "\") throws: " + e + "\n"); + } + return false; + } + + public static int counter = 1; + static int Runner() { + counter = counter * -1; + int i = counter; + if (counter < 2) counter += Runner(); + return i; + } + + public static int run(String msg) { + try { + Runner(); + } catch (StackOverflowError e) { + System.out.println(msg + " caught stack overflow error."); + return 0; + } catch (OutOfMemoryError e) { + return 0; + } + return 2; + } + + public static void main(String argv[]) { + try { + for (int i = 0; i < 20; i++) { + Thread t = new DoStackOverflow("SpawnedThread " + i); + t.start(); + } + run("Main thread"); + loadLib("test-rwx"); + run("Main thread"); + } catch (Exception e) { + System.out.println(e); + } + } + + static class DoStackOverflow extends Thread { + public DoStackOverflow(String name) { + super(name); + } + public void run() { + for (int i = 0; i < 10; ++i) { + TestMT.run(getName()); + yield(); + } + } + } +} diff -r 0298d8a0caf5 -r 79b098d44d20 test/runtime/7107135/test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/7107135/test.c Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2002-2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011 SAP AG. 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 +#include +#include +#include "jni.h" +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT jint JNICALL Java_Test_someMethod(JNIEnv *env, jobject mainObject) { + return 3; +} + +#ifdef __cplusplus +} +#endif diff -r 0298d8a0caf5 -r 79b098d44d20 test/runtime/7110720/Test7110720.sh --- a/test/runtime/7110720/Test7110720.sh Thu Apr 04 11:57:04 2013 +0200 +++ b/test/runtime/7110720/Test7110720.sh Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/7116786/Test7116786.java --- a/test/runtime/7116786/Test7116786.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/runtime/7116786/Test7116786.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/7158804/Test7158804.sh --- a/test/runtime/7158804/Test7158804.sh Thu Apr 04 11:57:04 2013 +0200 +++ b/test/runtime/7158804/Test7158804.sh Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/7162488/Test7162488.sh --- a/test/runtime/7162488/Test7162488.sh Thu Apr 04 11:57:04 2013 +0200 +++ b/test/runtime/7162488/Test7162488.sh Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/8003985/Test8003985.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/8003985/Test8003985.java Mon Apr 15 08:51:19 2013 +0200 @@ -0,0 +1,302 @@ +/* + * 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.BufferedReader; +import java.io.InputStreamReader; +import java.lang.Class; +import java.lang.String; +import java.lang.System; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CyclicBarrier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import sun.misc.Unsafe; +import sun.misc.Contended; + +/* + * @test + * @bug 8003985 + * @summary Support Contended Annotation - JEP 142 + * + * @run main/othervm -XX:-RestrictContended Test8003985 + */ +public class Test8003985 { + + private static final Unsafe U; + private static int ADDRESS_SIZE; + private static int HEADER_SIZE; + + static { + // steal Unsafe + try { + Field unsafe = Unsafe.class.getDeclaredField("theUnsafe"); + unsafe.setAccessible(true); + U = (Unsafe) unsafe.get(null); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new IllegalStateException(e); + } + + // When running with CompressedOops on 64-bit platform, the address size + // reported by Unsafe is still 8, while the real reference fields are 4 bytes long. + // Try to guess the reference field size with this naive trick. + try { + long off1 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj1")); + long off2 = U.objectFieldOffset(CompressedOopsClass.class.getField("obj2")); + ADDRESS_SIZE = (int) Math.abs(off2 - off1); + HEADER_SIZE = (int) Math.min(off1, off2); + } catch (NoSuchFieldException e) { + ADDRESS_SIZE = -1; + } + } + + static class CompressedOopsClass { + public Object obj1; + public Object obj2; + } + + public static boolean arePaddedPairwise(Class klass, String field1, String field2) throws Exception { + Field f1 = klass.getDeclaredField(field1); + Field f2 = klass.getDeclaredField(field2); + + if (isStatic(f1) != isStatic(f2)) { + return true; // these guys are in naturally disjoint locations + } + + int diff = offset(f1) - offset(f2); + if (diff < 0) { + // f1 is first + return (offset(f2) - (offset(f1) + getSize(f1))) > 64; + } else { + // f2 is first + return (offset(f1) - (offset(f2) + getSize(f2))) > 64; + } + } + + public static boolean isPadded(Class klass, String field1) throws Exception { + Field f1 = klass.getDeclaredField(field1); + + if (isStatic(f1)) { + return offset(f1) > 128 + 64; + } + + return offset(f1) > 64; + } + + public static boolean sameLayout(Class klass1, Class klass2) throws Exception { + for (Field f1 : klass1.getDeclaredFields()) { + Field f2 = klass2.getDeclaredField(f1.getName()); + if (offset(f1) != offset(f2)) { + return false; + } + } + + for (Field f2 : klass1.getDeclaredFields()) { + Field f1 = klass2.getDeclaredField(f2.getName()); + if (offset(f1) != offset(f2)) { + return false; + } + } + + return true; + } + + public static boolean isStatic(Field field) { + return Modifier.isStatic(field.getModifiers()); + } + + public static int offset(Field field) { + if (isStatic(field)) { + return (int) U.staticFieldOffset(field); + } else { + return (int) U.objectFieldOffset(field); + } + } + + public static int getSize(Field field) { + Class type = field.getType(); + if (type == byte.class) { return 1; } + if (type == boolean.class) { return 1; } + if (type == short.class) { return 2; } + if (type == char.class) { return 2; } + if (type == int.class) { return 4; } + if (type == float.class) { return 4; } + if (type == long.class) { return 8; } + if (type == double.class) { return 8; } + return ADDRESS_SIZE; + } + + public static void main(String[] args) throws Exception { + boolean endResult = true; + + // --------------- INSTANCE FIELDS --------------------- + + if (arePaddedPairwise(Test1.class, "int1", "int2") || + isPadded(Test1.class, "int1") || + isPadded(Test1.class, "int2")) { + System.err.println("Test1 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test2.class, "int1", "int2") || + !isPadded(Test2.class, "int1") || + isPadded(Test2.class, "int2")) { + System.err.println("Test2 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test3.class, "int1", "int2") || + !isPadded(Test3.class, "int1") || + !isPadded(Test3.class, "int2")) { + System.err.println("Test3 failed"); + endResult &= false; + } + + if (arePaddedPairwise(Test4.class, "int1", "int2") || + !isPadded(Test4.class, "int1") || + !isPadded(Test4.class, "int2")) { + System.err.println("Test4 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test5.class, "int1", "int2") || + !isPadded(Test5.class, "int1") || + !isPadded(Test5.class, "int2")) { + System.err.println("Test5 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test6.class, "int1", "int2") || + !isPadded(Test6.class, "int1") || + !isPadded(Test6.class, "int2")) { + System.err.println("Test6 failed"); + endResult &= false; + } + + if (arePaddedPairwise(Test7.class, "int1", "int2") || + !isPadded(Test7.class, "int1") || + !isPadded(Test7.class, "int2")) { + System.err.println("Test7 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test8.class, "int1", "int2") || + !isPadded(Test8.class, "int1") || + !isPadded(Test8.class, "int2")) { + System.err.println("Test8 failed"); + endResult &= false; + } + + if (!arePaddedPairwise(Test9.class, "int1", "int2") || + !isPadded(Test9.class, "int1") || + !isPadded(Test9.class, "int2")) { + System.err.println("Test9 failed"); + endResult &= false; + } + + if (!sameLayout(Test4.class, Test7.class)) { + System.err.println("Test4 and Test7 have different layouts"); + endResult &= false; + } + + if (!sameLayout(Test5.class, Test6.class)) { + System.err.println("Test5 and Test6 have different layouts"); + endResult &= false; + } + + if (!sameLayout(Test8.class, Test9.class)) { + System.err.println("Test8 and Test9 have different layouts"); + endResult &= false; + } + + System.out.println(endResult ? "Test PASSES" : "Test FAILS"); + if (!endResult) { + throw new Error("Test failed"); + } + } + + // ----------------------------------- INSTANCE FIELDS ----------------------------------------- + + // naturally packed + public static class Test1 { + private int int1; + private int int2; + } + + // int1 is padded + public static class Test2 { + @Contended private int int1; + private int int2; + } + + // both fields are padded + public static class Test3 { + @Contended private int int1; + @Contended private int int2; + } + + // fields are padded in the singular group + public static class Test4 { + @Contended("sameGroup") private int int1; + @Contended("sameGroup") private int int2; + } + + // fields are padded in disjoint groups + public static class Test5 { + @Contended("diffGroup1") private int int1; + @Contended("diffGroup2") private int int2; + } + + // fields are padded in disjoint groups + public static class Test6 { + @Contended private int int1; + @Contended("diffGroup2") private int int2; + } + + // fields are padded in the singular group + @Contended + public static class Test7 { + private int int1; + private int int2; + } + + // all fields are padded as the group, and one field is padded specifically + @Contended + public static class Test8 { + @Contended private int int1; + private int int2; + } + + // all fields are padded as the group, and one field is padded specifically + @Contended + public static class Test9 { + @Contended("group") private int int1; + private int int2; + } + +} + diff -r 0298d8a0caf5 -r 79b098d44d20 test/runtime/8007736/TestStaticIF.java --- a/test/runtime/8007736/TestStaticIF.java Thu Apr 04 11:57:04 2013 +0200 +++ /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 0298d8a0caf5 -r 79b098d44d20 test/runtime/8010389/VMThreadDlopen.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/8010389/VMThreadDlopen.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/CommandLine/BooleanFlagWithInvalidValue.java --- a/test/runtime/CommandLine/BooleanFlagWithInvalidValue.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/runtime/CommandLine/BooleanFlagWithInvalidValue.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/CommandLine/FlagWithInvalidValue.java --- a/test/runtime/CommandLine/FlagWithInvalidValue.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/runtime/CommandLine/FlagWithInvalidValue.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/CommandLine/NonBooleanFlagWithInvalidBooleanPrefix.java --- a/test/runtime/CommandLine/NonBooleanFlagWithInvalidBooleanPrefix.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/runtime/CommandLine/NonBooleanFlagWithInvalidBooleanPrefix.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/NMT/AllocTestType.java --- a/test/runtime/NMT/AllocTestType.java Thu Apr 04 11:57:04 2013 +0200 +++ /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 0298d8a0caf5 -r 79b098d44d20 test/runtime/NMT/BaselineWithParameter.java --- a/test/runtime/NMT/BaselineWithParameter.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/runtime/NMT/BaselineWithParameter.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/NMT/MallocTestType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/MallocTestType.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/NMT/PrintNMTStatistics.java --- a/test/runtime/NMT/PrintNMTStatistics.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/runtime/NMT/PrintNMTStatistics.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/NMT/ThreadedMallocTestType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/ThreadedMallocTestType.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/NMT/ThreadedVirtualAllocTestType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/ThreadedVirtualAllocTestType.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/NMT/VirtualAllocTestType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/VirtualAllocTestType.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/runtime/interned/SanityTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/interned/SanityTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/test_env.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/test_env.sh Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/testlibrary/OutputAnalyzerTest.java --- a/test/testlibrary/OutputAnalyzerTest.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/testlibrary/OutputAnalyzerTest.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 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 Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java --- a/test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java Mon Apr 15 08:51:19 2013 +0200 @@ -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 0298d8a0caf5 -r 79b098d44d20 test/testlibrary/whitebox/sun/hotspot/WhiteBox.java --- a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Thu Apr 04 11:57:04 2013 +0200 +++ b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Mon Apr 15 08:51:19 2013 +0200 @@ -80,18 +80,34 @@ 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 public native void deoptimizeAll(); public native boolean isMethodCompiled(Method method); - public native boolean isMethodCompilable(Method method); + public boolean isMethodCompilable(Method method) { + return isMethodCompilable(method, -1 /*any*/); + } + public native boolean isMethodCompilable(Method method, int compLevel); public native boolean isMethodQueuedForCompilation(Method method); public native int deoptimizeMethod(Method method); public native void makeMethodNotCompilable(Method method); public native int getMethodCompilationLevel(Method method); - public native boolean setDontInlineMethod(Method method, boolean value); + public native boolean testSetDontInlineMethod(Method method, boolean value); public native int getCompileQueuesSize(); + public native boolean testSetForceInlineMethod(Method method, boolean value); + public native boolean enqueueMethodForCompilation(Method method, int compLevel); + public native void clearMethodState(Method method); + + //Intered strings + public native boolean isInStringTable(String str); + + // force Full GC + public native void fullGC(); }