# HG changeset patch # User Christos Kotselidis # Date 1363871473 -3600 # Node ID c3657d00e343c110c86990cd00ecc227355e763d # Parent dee7c8b578c7ffcd0bd4f33a1f17cd14f818b916# Parent 2bfb9644dcc23f4383afe0c123d9d02e1fbdef60 -Merge with tip diff -r dee7c8b578c7 -r c3657d00e343 .hgignore --- a/.hgignore Thu Mar 21 11:30:38 2013 +0100 +++ b/.hgignore Thu Mar 21 14:11:13 2013 +0100 @@ -7,7 +7,7 @@ ^dist/ ^java/ ^lib/ -^jdk1.7.0 +^jdk1.(7|8).0 ^java64/ ^work/ \.checkstyle$ @@ -61,10 +61,11 @@ .DS_Store javadoc/ .idea/ +^cscope.out +^tags syntax: glob *.bgv core.* *.jar eclipse-build.xml rebuild-launch.out - diff -r dee7c8b578c7 -r c3657d00e343 .hgtags --- a/.hgtags Thu Mar 21 11:30:38 2013 +0100 +++ b/.hgtags Thu Mar 21 14:11:13 2013 +0100 @@ -311,3 +311,12 @@ 70c89bd6b895a10d25ca70e08093c09ff2005fda hs25-b16 1a3e54283c54aaa8b3437813e8507fbdc966e5b6 jdk8-b74 b4391649e91ea8d37f66317a03d6d2573a93d10d hs25-b17 +6778d0b1659323a506ca47600ca29a9d9f8b383d jdk8-b75 +20b605466ccb1b3725eb25314d9e8782199630c5 jdk8-b76 +412d722168bc23f8e6d98995202728678561417f hs25-b18 +cdb46031e7184d37301288f5719121a63c7054b5 jdk8-b77 +9f19f4a7d48a4ebe7f616b6068971ea5f8b075fa hs25-b19 +d5e12e7d2f719144d84903d9151455661c47b476 jdk8-b78 +555ec35a250783110aa070dbc8a8603f6cabe41f hs25-b20 +6691814929b606fe0e7954fd6e485dd876505c83 jdk8-b79 +df5396524152118535c36da5801d828b560d19a2 hs25-b21 diff -r dee7c8b578c7 -r c3657d00e343 GRAAL_AUTHORS --- a/GRAAL_AUTHORS Thu Mar 21 11:30:38 2013 +0100 +++ b/GRAAL_AUTHORS Thu Mar 21 14:11:13 2013 +0100 @@ -1,9 +1,12 @@ Gilles Duboscq (gdub) Peter Hofer +Christian Haeubl (chaeubl) +Christian Humer (chumer) +Roland Schatz +Doug Simon (dnsimon) +Lukas Stadler (lstadler) Alexander Stipsits Katrin Strassl -Christian Humer (chumer) Christian Wimmer (cwimmer) -Doug Simon (dnsimon) -Lukas Stadler (lstadler) +Andreas Woess (aw) Thomas Wuerthinger (thomaswue) diff -r dee7c8b578c7 -r c3657d00e343 agent/make/Makefile --- a/agent/make/Makefile Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/make/Makefile Thu Mar 21 14:11:13 2013 +0100 @@ -19,7 +19,7 @@ # 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 guards against adding broken .java files to the directory @@ -42,8 +42,6 @@ sun.jvm.hotspot \ sun.jvm.hotspot.asm \ sun.jvm.hotspot.asm.sparc \ -sun.jvm.hotspot.bugspot \ -sun.jvm.hotspot.bugspot.tree \ sun.jvm.hotspot.c1 \ sun.jvm.hotspot.ci \ sun.jvm.hotspot.code \ @@ -84,7 +82,6 @@ sun.jvm.hotspot.gc_interface \ sun.jvm.hotspot.interpreter \ sun.jvm.hotspot.jdi \ -sun.jvm.hotspot.livejvm \ sun.jvm.hotspot.memory \ sun.jvm.hotspot.opto \ sun.jvm.hotspot.oops \ @@ -130,8 +127,6 @@ sun/jvm/hotspot/*.java \ sun/jvm/hotspot/asm/*.java \ sun/jvm/hotspot/asm/sparc/*.java \ -sun/jvm/hotspot/bugspot/*.java \ -sun/jvm/hotspot/bugspot/tree/*.java \ sun/jvm/hotspot/c1/*.java \ sun/jvm/hotspot/ci/*.java \ sun/jvm/hotspot/code/*.java \ @@ -168,7 +163,6 @@ sun/jvm/hotspot/gc_implementation/shared/*.java \ sun/jvm/hotspot/interpreter/*.java \ sun/jvm/hotspot/jdi/*.java \ -sun/jvm/hotspot/livejvm/*.java \ sun/jvm/hotspot/memory/*.java \ sun/jvm/hotspot/oops/*.java \ sun/jvm/hotspot/opto/*.java \ @@ -205,7 +199,7 @@ sun/jvm/hotspot/utilities/memo/*.java \ sun/jvm/hotspot/utilities/soql/*.java \ com/sun/java/swing/action/*.java \ -com/sun/java/swing/ui/*.java +com/sun/java/swing/ui/*.java #END FILELIST ifneq "x$(ALT_BOOTDIR)" "x" @@ -231,7 +225,7 @@ OUTPUT_DIR = $(BUILD_DIR)/classes DOC_DIR = $(BUILD_DIR)/doc -# gnumake 3.78.1 does not accept the *s, +# gnumake 3.78.1 does not accept the *s, # so use the shell to expand them ALLFILES := $(patsubst %,$(SRC_DIR)/%,$(FILELIST)) ALLFILES := $(shell /bin/ls $(ALLFILES)) @@ -303,7 +297,7 @@ cscope: $(ALLFILES) rm -f java.files echo $(ALLFILES) > java.files - cscope -b -i java.files -f java.out + cscope -b -i java.files -f java.out rm -f java.files .PHONY: sa.jar diff -r dee7c8b578c7 -r c3657d00e343 agent/make/bugspot.bat --- a/agent/make/bugspot.bat Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -REM -REM Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. -REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -REM -REM This code is free software; you can redistribute it and/or modify it -REM under the terms of the GNU General Public License version 2 only, as -REM published by the Free Software Foundation. -REM -REM This code is distributed in the hope that it will be useful, but WITHOUT -REM ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -REM FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -REM version 2 for more details (a copy is included in the LICENSE file that -REM accompanied this code). -REM -REM You should have received a copy of the GNU General Public License version -REM 2 along with this work; if not, write to the Free Software Foundation, -REM Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -REM -REM Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -REM or visit www.oracle.com if you need additional information or have any -REM questions. -REM -REM - -java -showversion -cp ..\build\classes;..\src\share\lib\js.jar;.\sa.jar;lib\js.jar sun.jvm.hotspot.bugspot.Main diff -r dee7c8b578c7 -r c3657d00e343 agent/make/marks_notes.html --- a/agent/make/marks_notes.html Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/make/marks_notes.html Thu Mar 21 14:11:13 2013 +0100 @@ -26,14 +26,12 @@

Feedback

Refactoring of package hierarchy. All user interface components should be in - the ui package. Perhaps: sun.jvm.hotspot.ui.hsdb.Main for the HSDB and - sun.jvm.hotspot.ui.bugspot.Main for BugSpot. + the ui package. Perhaps: sun.jvm.hotspot.ui.hsdb.Main for the HSDB.

The src\share\vm\agent area seems like a workspace so it should be organized like one. In particular, I'd like to suggest the following directory layout:
@@ -47,7 +45,7 @@

- Seems like there is a lot of redundant functionality. Between the HSDB and BugSpot. Perhaps + Seems like there is a lot of redundant functionality. Perhaps this can be consolidated with a javax.swing.Actions architecture.

Tasklist

@@ -55,11 +53,7 @@

Stack memory pane: It's one of the more useful JVM debugging tools in the SA. However, it - doesn't support any interaction with the text; the Memory Panel in BugSpot - was written afterward (with help from Shannon) and implements proper - selection, scrolling, and drag-and-drop, but no annotations. I'm not sure how - to integrate the annotations with the JTable that's being used for the memory - view; if you have suggestions here please let me know. + doesn't support any interaction with the text.

Integrations with the NetBeans architecture (plug in). See the Netbeans Open APIs homepage diff -r dee7c8b578c7 -r c3657d00e343 agent/src/os/bsd/MacosxDebuggerLocal.m --- a/agent/src/os/bsd/MacosxDebuggerLocal.m Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/os/bsd/MacosxDebuggerLocal.m Thu Mar 21 14:11:13 2013 +0100 @@ -38,6 +38,8 @@ #import #import #import +#import +#import jboolean debug = JNI_FALSE; @@ -97,7 +99,8 @@ * Method: init0 * Signature: ()V */ -JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls) { +JNIEXPORT void JNICALL +Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_init0(JNIEnv *env, jclass cls) { symbolicatorID = (*env)->GetFieldID(env, cls, "symbolicator", "J"); taskID = (*env)->GetFieldID(env, cls, "task", "J"); CHECK_EXCEPTION; @@ -108,7 +111,11 @@ * Method: lookupByName0 * Signature: (Ljava/lang/String;Ljava/lang/String;)J */ -JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0(JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) { +JNIEXPORT jlong JNICALL +Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0( + JNIEnv *env, jobject this_obj, + jstring objectName, jstring symbolName) +{ jlong address = 0; JNF_COCOA_ENTER(env); @@ -137,7 +144,11 @@ * Method: readBytesFromProcess0 * Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult; */ -JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0(JNIEnv *env, jobject this_obj, jlong addr, jlong numBytes) { +JNIEXPORT jbyteArray JNICALL +Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0( + JNIEnv *env, jobject this_obj, + jlong addr, jlong numBytes) +{ if (debug) printf("readBytesFromProcess called. addr = %llx numBytes = %lld\n", addr, numBytes); // must allocate storage instead of using former parameter buf @@ -209,12 +220,74 @@ return array; } + /* - * Class: sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal + * Lookup the thread_t that corresponds to the given thread_id. + * The thread_id should be the result from calling thread_info() with THREAD_IDENTIFIER_INFO + * and reading the m_ident_info.thread_id returned. + * The returned thread_t is the mach send right to the kernel port for the corresponding thread. + * + * We cannot simply use the OSThread._thread_id field in the JVM. This is set to ::mach_thread_self() + * in the VM, but that thread port is not valid for a remote debugger to access the thread. + */ +thread_t +lookupThreadFromThreadId(task_t task, jlong thread_id) { + if (debug) { + printf("lookupThreadFromThreadId thread_id=0x%llx\n", thread_id); + } + + thread_array_t thread_list = NULL; + mach_msg_type_number_t thread_list_count = 0; + thread_t result_thread = 0; + int i; + + // 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); + } + return 0; + } + + for(i = 0 ; i < thread_list_count; i++) { + thread_identifier_info_data_t m_ident_info; + mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; + + // 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); + } + break; + } + + // if this is the one we're looking for, return the send right + if (thread_id == m_ident_info.thread_id) + { + result_thread = thread_list[i]; + break; + } + } + + vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (thread_t)); + vm_deallocate(mach_task_self(), (vm_address_t) thread_list, thread_list_count); + + return result_thread; +} + + +/* + * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal * Method: getThreadIntegerRegisterSet0 - * Signature: (I)[J + * Signature: (J)[J */ -JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0(JNIEnv *env, jobject this_obj, jint lwp_id) { +JNIEXPORT jlongArray JNICALL +Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0( + JNIEnv *env, jobject this_obj, + jlong thread_id) +{ if (debug) printf("getThreadRegisterSet0 called\n"); @@ -226,8 +299,9 @@ int i; jlongArray registerArray; jlong *primitiveArray; + task_t gTask = getTask(env, this_obj); - tid = lwp_id; + tid = lookupThreadFromThreadId(gTask, thread_id); result = thread_get_state(tid, HSDB_THREAD_STATE, (thread_state_t)&state, &count); @@ -328,19 +402,21 @@ } /* - * Class: sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal + * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal * Method: translateTID0 * Signature: (I)I */ JNIEXPORT jint JNICALL -Java_sun_jvm_hotspot_debugger_macosx_MacOSXDebuggerLocal_translateTID0(JNIEnv *env, jobject this_obj, jint tid) { +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); kern_return_t result; thread_t foreign_tid, usable_tid; mach_msg_type_name_t type; - + foreign_tid = tid; task_t gTask = getTask(env, this_obj); @@ -356,19 +432,90 @@ return (jint) usable_tid; } + +static bool ptrace_continue(pid_t pid, int signal) { + // pass the signal to the process so we don't swallow it + int res; + if ((res = ptrace(PT_CONTINUE, pid, (caddr_t)1, signal)) < 0) { + fprintf(stderr, "attach: ptrace(PT_CONTINUE, %d) failed with %d\n", pid, res); + return false; + } + return true; +} + +// waits until the ATTACH has stopped the process +// by signal SIGSTOP +static bool ptrace_waitpid(pid_t pid) { + int ret; + int status; + while (true) { + // Wait for debuggee to stop. + ret = waitpid(pid, &status, 0); + if (ret >= 0) { + if (WIFSTOPPED(status)) { + // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP + // will still be pending and delivered when the process is DETACHED and the process + // will go to sleep. + if (WSTOPSIG(status) == SIGSTOP) { + // Debuggee stopped by SIGSTOP. + 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)); + return false; + } + } else { + fprintf(stderr, "attach: waitpid(): Child process exited/terminated (status = 0x%x)\n", status); + return false; + } + } else { + switch (errno) { + case EINTR: + continue; + break; + case ECHILD: + fprintf(stderr, "attach: waitpid() failed. Child process pid (%d) does not exist \n", pid); + break; + case EINVAL: + fprintf(stderr, "attach: waitpid() failed. Invalid options argument.\n"); + break; + default: + fprintf(stderr, "attach: waitpid() failed. Unexpected error %d\n",errno); + break; + } + return false; + } + } +} + +// attach to a process/thread specified by "pid" +static bool ptrace_attach(pid_t pid) { + int res; + if ((res = ptrace(PT_ATTACH, pid, 0, 0)) < 0) { + fprintf(stderr, "ptrace(PT_ATTACH, %d) failed with %d\n", pid, res); + return false; + } else { + return ptrace_waitpid(pid); + } +} + /* * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal * Method: attach0 * Signature: (I)V */ -JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I(JNIEnv *env, jobject this_obj, jint jpid) { +JNIEXPORT void JNICALL +Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I( + JNIEnv *env, jobject this_obj, jint 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); @@ -378,6 +525,13 @@ } putTask(env, this_obj, gTask); + // use ptrace to stop the process + // on os x, ptrace only needs to be called on the process, not the individual threads + if (ptrace_attach(jpid) != true) { + mach_port_deallocate(mach_task_self(), gTask); + THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process"); + } + id symbolicator = nil; id jrsSymbolicator = objc_lookUpClass("JRSSymbolicator"); if (jrsSymbolicator != nil) { @@ -401,11 +555,29 @@ * Method: detach0 * Signature: ()V */ -JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0(JNIEnv *env, jobject this_obj) { +JNIEXPORT void JNICALL +Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0( + JNIEnv *env, jobject this_obj) +{ 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 + int pid; + 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); + } + else { + int res = ptrace(PT_DETACH, pid, 0, 0); + if (res < 0) { + fprintf(stderr, "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) { @@ -419,10 +591,13 @@ * 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) { +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; @@ -533,13 +708,16 @@ * 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) { +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); diff -r dee7c8b578c7 -r c3657d00e343 agent/src/os/bsd/libproc_impl.c --- a/agent/src/os/bsd/libproc_impl.c Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/os/bsd/libproc_impl.c Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -91,6 +91,14 @@ } } +void print_error(const char* format,...) { + va_list alist; + va_start(alist, format); + fputs("ERROR: ", stderr); + vfprintf(stderr, format, alist); + va_end(alist); +} + bool is_debug() { return _libsaproc_debug; } diff -r dee7c8b578c7 -r c3657d00e343 agent/src/os/bsd/libproc_impl.h --- a/agent/src/os/bsd/libproc_impl.h Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/os/bsd/libproc_impl.h Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, 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 @@ -107,6 +107,7 @@ int pathmap_open(const char* name); void print_debug(const char* format,...); +void print_error(const char* format,...); bool is_debug(); typedef bool (*thread_info_callback)(struct ps_prochandle* ph, pthread_t pid, lwpid_t lwpid); diff -r dee7c8b578c7 -r c3657d00e343 agent/src/os/bsd/ps_proc.c --- a/agent/src/os/bsd/ps_proc.c Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/os/bsd/ps_proc.c Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -129,42 +129,66 @@ return (errno == 0)? true: false; } +static bool ptrace_continue(pid_t pid, int signal) { + // pass the signal to the process so we don't swallow it + if (ptrace(PTRACE_CONT, pid, NULL, signal) < 0) { + print_debug("ptrace(PTRACE_CONT, ..) failed for %d\n", pid); + return false; + } + return true; +} + +// waits until the ATTACH has stopped the process +// by signal SIGSTOP +static bool ptrace_waitpid(pid_t pid) { + int ret; + int status; + do { + // Wait for debuggee to stop. + ret = waitpid(pid, &status, 0); + if (ret >= 0) { + if (WIFSTOPPED(status)) { + // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP + // will still be pending and delivered when the process is DETACHED and the process + // will go to sleep. + if (WSTOPSIG(status) == SIGSTOP) { + // Debuggee stopped by SIGSTOP. + return true; + } + if (!ptrace_continue(pid, WSTOPSIG(status))) { + print_error("Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status)); + return false; + } + } else { + print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status); + return false; + } + } else { + switch (errno) { + case EINTR: + continue; + break; + case ECHILD: + print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid); + break; + case EINVAL: + print_debug("waitpid() failed. Invalid options argument.\n"); + break; + default: + print_debug("waitpid() failed. Unexpected error %d\n",errno); + } + return false; + } + } while(true); +} + // attach to a process/thread specified by "pid" static bool ptrace_attach(pid_t pid) { if (ptrace(PT_ATTACH, pid, NULL, 0) < 0) { print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid); return false; } else { - int ret; - int status; - do { - // Wait for debuggee to stop. - ret = waitpid(pid, &status, 0); - if (ret >= 0) { - if (WIFSTOPPED(status)) { - // Debuggee stopped. - return true; - } else { - print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status); - return false; - } - } else { - switch (errno) { - case EINTR: - continue; - break; - case ECHILD: - print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid); - break; - case EINVAL: - print_debug("waitpid() failed. Invalid options argument.\n"); - break; - default: - print_debug("waitpid() failed. Unexpected error %d\n",errno); - } - return false; - } - } while(true); + return ptrace_waitpid(pid); } } diff -r dee7c8b578c7 -r c3657d00e343 agent/src/os/linux/LinuxDebuggerLocal.c --- a/agent/src/os/linux/LinuxDebuggerLocal.c Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/os/linux/LinuxDebuggerLocal.c Thu Mar 21 14:11:13 2013 +0100 @@ -280,7 +280,7 @@ return (err == PS_OK)? array : 0; } -#if defined(i386) || defined(ia64) || defined(amd64) || defined(sparc) || defined(sparcv9) +#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9) JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_getThreadIntegerRegisterSet0 (JNIEnv *env, jobject this_obj, jint lwp_id) { @@ -299,9 +299,6 @@ #ifdef i386 #define NPRGREG sun_jvm_hotspot_debugger_x86_X86ThreadContext_NPRGREG #endif -#ifdef ia64 -#define NPRGREG IA64_REG_COUNT -#endif #ifdef amd64 #define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG #endif @@ -336,13 +333,6 @@ #endif /* i386 */ -#if ia64 - regs = (*env)->GetLongArrayElements(env, array, &isCopy); - for (i = 0; i < NPRGREG; i++ ) { - regs[i] = 0xDEADDEAD; - } -#endif /* ia64 */ - #ifdef amd64 #define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg diff -r dee7c8b578c7 -r c3657d00e343 agent/src/os/linux/libproc.h --- a/agent/src/os/linux/libproc.h Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/os/linux/libproc.h Thu Mar 21 14:11:13 2013 +0100 @@ -79,14 +79,6 @@ *************************************************************************************/ -#ifdef ia64 -struct user_regs_struct { -/* copied from user.h which doesn't define this in a struct */ - -#define IA64_REG_COUNT (EF_SIZE/8+32) /* integer and fp regs */ -unsigned long regs[IA64_REG_COUNT]; /* integer and fp regs */ -}; -#endif #if defined(sparc) || defined(sparcv9) #define user_regs_struct pt_regs diff -r dee7c8b578c7 -r c3657d00e343 agent/src/os/linux/libproc_impl.c --- a/agent/src/os/linux/libproc_impl.c Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/os/linux/libproc_impl.c Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -92,6 +92,14 @@ } } +void print_error(const char* format,...) { + va_list alist; + va_start(alist, format); + fputs("ERROR: ", stderr); + vfprintf(stderr, format, alist); + va_end(alist); +} + bool is_debug() { return _libsaproc_debug; } diff -r dee7c8b578c7 -r c3657d00e343 agent/src/os/linux/libproc_impl.h --- a/agent/src/os/linux/libproc_impl.h Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/os/linux/libproc_impl.h Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, 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 @@ -105,6 +105,7 @@ int pathmap_open(const char* name); void print_debug(const char* format,...); +void print_error(const char* format,...); bool is_debug(); typedef bool (*thread_info_callback)(struct ps_prochandle* ph, pthread_t pid, lwpid_t lwpid); diff -r dee7c8b578c7 -r c3657d00e343 agent/src/os/linux/ps_proc.c --- a/agent/src/os/linux/ps_proc.c Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/os/linux/ps_proc.c Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include "libproc_impl.h" @@ -142,46 +143,71 @@ } +static bool ptrace_continue(pid_t pid, int signal) { + // pass the signal to the process so we don't swallow it + if (ptrace(PTRACE_CONT, pid, NULL, signal) < 0) { + print_debug("ptrace(PTRACE_CONT, ..) failed for %d\n", pid); + return false; + } + return true; +} + +// waits until the ATTACH has stopped the process +// by signal SIGSTOP +static bool ptrace_waitpid(pid_t pid) { + int ret; + int status; + while (true) { + // Wait for debuggee to stop. + ret = waitpid(pid, &status, 0); + if (ret == -1 && errno == ECHILD) { + // try cloned process. + ret = waitpid(pid, &status, __WALL); + } + if (ret >= 0) { + if (WIFSTOPPED(status)) { + // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP + // will still be pending and delivered when the process is DETACHED and the process + // will go to sleep. + if (WSTOPSIG(status) == SIGSTOP) { + // Debuggee stopped by SIGSTOP. + return true; + } + if (!ptrace_continue(pid, WSTOPSIG(status))) { + print_error("Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status)); + return false; + } + } else { + print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status); + return false; + } + } else { + switch (errno) { + case EINTR: + continue; + break; + case ECHILD: + print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid); + break; + case EINVAL: + print_debug("waitpid() failed. Invalid options argument.\n"); + break; + default: + print_debug("waitpid() failed. Unexpected error %d\n",errno); + break; + } + return false; + } + } +} + // attach to a process/thread specified by "pid" static bool ptrace_attach(pid_t pid) { if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) { print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid); return false; } else { - int ret; - int status; - do { - // Wait for debuggee to stop. - ret = waitpid(pid, &status, 0); - if (ret == -1 && errno == ECHILD) { - // try cloned process. - ret = waitpid(pid, &status, __WALL); - } - if (ret >= 0) { - if (WIFSTOPPED(status)) { - // Debuggee stopped. - return true; - } else { - print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status); - return false; - } - } else { - switch (errno) { - case EINTR: - continue; - break; - case ECHILD: - print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid); - break; - case EINVAL: - print_debug("waitpid() failed. Invalid options argument.\n"); - break; - default: - print_debug("waitpid() failed. Unexpected error %d\n",errno); - } - return false; - } - } while(true); + return ptrace_waitpid(pid); } } diff -r dee7c8b578c7 -r c3657d00e343 agent/src/os/win32/windbg/sawindbg.cpp --- a/agent/src/os/win32/windbg/sawindbg.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/os/win32/windbg/sawindbg.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -27,10 +27,7 @@ #include "sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal.h" -#ifdef _M_IA64 - #include "sun_jvm_hotspot_debugger_ia64_IA64ThreadContext.h" - #define NPRGREG sun_jvm_hotspot_debugger_ia64_IA64ThreadContext_NPRGREG -#elif _M_IX86 +#ifdef _M_IX86 #include "sun_jvm_hotspot_debugger_x86_X86ThreadContext.h" #define NPRGREG sun_jvm_hotspot_debugger_x86_X86ThreadContext_NPRGREG #elif _M_AMD64 @@ -375,8 +372,7 @@ We are attaching to a process in 'read-only' mode. i.e., we do not want to put breakpoints, suspend/resume threads etc. For read-only JDI and HSDB kind of - usage this should suffice. We are not intending to use this for full-fledged - ProcessControl implementation to be used with BugSpotAgent. + usage this should suffice. Please refer to DEBUG_ATTACH_NONINVASIVE mode source comments from dbgeng.h. In this mode, debug engine does not call DebugActiveProrcess. i.e., we are not @@ -491,92 +487,7 @@ memset(&context, 0, sizeof(CONTEXT)); #undef REG_INDEX -#ifdef _M_IA64 - #define REG_INDEX(x) sun_jvm_hotspot_debugger_ia64_IA64ThreadContext_##x - - context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG; - ptrIDebugAdvanced->GetThreadContext(&context, sizeof(CONTEXT)); - - ptrRegs[REG_INDEX(GR0)] = 0; // always 0 - ptrRegs[REG_INDEX(GR1)] = context.IntGp; // r1 - ptrRegs[REG_INDEX(GR2)] = context.IntT0; // r2-r3 - ptrRegs[REG_INDEX(GR3)] = context.IntT1; - ptrRegs[REG_INDEX(GR4)] = context.IntS0; // r4-r7 - ptrRegs[REG_INDEX(GR5)] = context.IntS1; - ptrRegs[REG_INDEX(GR6)] = context.IntS2; - ptrRegs[REG_INDEX(GR7)] = context.IntS3; - ptrRegs[REG_INDEX(GR8)] = context.IntV0; // r8 - ptrRegs[REG_INDEX(GR9)] = context.IntT2; // r9-r11 - ptrRegs[REG_INDEX(GR10)] = context.IntT3; - ptrRegs[REG_INDEX(GR11)] = context.IntT4; - ptrRegs[REG_INDEX(GR12)] = context.IntSp; // r12 stack pointer - ptrRegs[REG_INDEX(GR13)] = context.IntTeb; // r13 teb - ptrRegs[REG_INDEX(GR14)] = context.IntT5; // r14-r31 - ptrRegs[REG_INDEX(GR15)] = context.IntT6; - ptrRegs[REG_INDEX(GR16)] = context.IntT7; - ptrRegs[REG_INDEX(GR17)] = context.IntT8; - ptrRegs[REG_INDEX(GR18)] = context.IntT9; - ptrRegs[REG_INDEX(GR19)] = context.IntT10; - ptrRegs[REG_INDEX(GR20)] = context.IntT11; - ptrRegs[REG_INDEX(GR21)] = context.IntT12; - ptrRegs[REG_INDEX(GR22)] = context.IntT13; - ptrRegs[REG_INDEX(GR23)] = context.IntT14; - ptrRegs[REG_INDEX(GR24)] = context.IntT15; - ptrRegs[REG_INDEX(GR25)] = context.IntT16; - ptrRegs[REG_INDEX(GR26)] = context.IntT17; - ptrRegs[REG_INDEX(GR27)] = context.IntT18; - ptrRegs[REG_INDEX(GR28)] = context.IntT19; - ptrRegs[REG_INDEX(GR29)] = context.IntT20; - ptrRegs[REG_INDEX(GR30)] = context.IntT21; - ptrRegs[REG_INDEX(GR31)] = context.IntT22; - - ptrRegs[REG_INDEX(INT_NATS)] = context.IntNats; - ptrRegs[REG_INDEX(PREDS)] = context.Preds; - - ptrRegs[REG_INDEX(BR_RP)] = context.BrRp; - ptrRegs[REG_INDEX(BR1)] = context.BrS0; // b1-b5 - ptrRegs[REG_INDEX(BR2)] = context.BrS1; - ptrRegs[REG_INDEX(BR3)] = context.BrS2; - ptrRegs[REG_INDEX(BR4)] = context.BrS3; - ptrRegs[REG_INDEX(BR5)] = context.BrS4; - ptrRegs[REG_INDEX(BR6)] = context.BrT0; // b6-b7 - ptrRegs[REG_INDEX(BR7)] = context.BrT1; - - ptrRegs[REG_INDEX(AP_UNAT)] = context.ApUNAT; - ptrRegs[REG_INDEX(AP_LC)] = context.ApLC; - ptrRegs[REG_INDEX(AP_EC)] = context.ApEC; - ptrRegs[REG_INDEX(AP_CCV)] = context.ApCCV; - ptrRegs[REG_INDEX(AP_DCR)] = context.ApDCR; - - ptrRegs[REG_INDEX(RS_PFS)] = context.RsPFS; - ptrRegs[REG_INDEX(RS_BSP)] = context.RsBSP; - ptrRegs[REG_INDEX(RS_BSPSTORE)] = context.RsBSPSTORE; - ptrRegs[REG_INDEX(RS_RSC)] = context.RsRSC; - ptrRegs[REG_INDEX(RS_RNAT)] = context.RsRNAT; - - ptrRegs[REG_INDEX(ST_IPSR)] = context.StIPSR; - ptrRegs[REG_INDEX(ST_IIP)] = context.StIIP; - ptrRegs[REG_INDEX(ST_IFS)] = context.StIFS; - - ptrRegs[REG_INDEX(DB_I0)] = context.DbI0; - ptrRegs[REG_INDEX(DB_I1)] = context.DbI1; - ptrRegs[REG_INDEX(DB_I2)] = context.DbI2; - ptrRegs[REG_INDEX(DB_I3)] = context.DbI3; - ptrRegs[REG_INDEX(DB_I4)] = context.DbI4; - ptrRegs[REG_INDEX(DB_I5)] = context.DbI5; - ptrRegs[REG_INDEX(DB_I6)] = context.DbI6; - ptrRegs[REG_INDEX(DB_I7)] = context.DbI7; - - ptrRegs[REG_INDEX(DB_D0)] = context.DbD0; - ptrRegs[REG_INDEX(DB_D1)] = context.DbD1; - ptrRegs[REG_INDEX(DB_D2)] = context.DbD2; - ptrRegs[REG_INDEX(DB_D3)] = context.DbD3; - ptrRegs[REG_INDEX(DB_D4)] = context.DbD4; - ptrRegs[REG_INDEX(DB_D5)] = context.DbD5; - ptrRegs[REG_INDEX(DB_D6)] = context.DbD6; - ptrRegs[REG_INDEX(DB_D7)] = context.DbD7; - -#elif _M_IX86 +#ifdef _M_IX86 #define REG_INDEX(x) sun_jvm_hotspot_debugger_x86_X86ThreadContext_##x context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/asm/amd64/AMD64FloatRegister.java --- a/agent/src/share/classes/sun/jvm/hotspot/asm/amd64/AMD64FloatRegister.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.asm.amd64; - -import sun.jvm.hotspot.asm.Register; -import sun.jvm.hotspot.utilities.Assert; - -public class AMD64FloatRegister extends Register { - - public AMD64FloatRegister(int number) { - super(number); - } - - public int getNumber() { - return number; - } - - public int getNumberOfRegisters() { - return AMD64FloatRegisters.getNumRegisters(); - } - - public boolean isFloat() { - return true; - } - - public boolean isFramePointer() { - return false; - } - - public boolean isStackPointer() { - return false; - } - - public boolean isValid() { - return number >= 0 && number < AMD64FloatRegisters.getNumRegisters(); - } - - public String toString() { - return AMD64FloatRegisters.getRegisterName(number); - } - -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/BugSpot.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/BugSpot.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1536 +0,0 @@ -/* - * Copyright (c) 2001, 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 sun.jvm.hotspot.bugspot; - -import java.awt.*; -import java.awt.event.*; -import java.io.*; -import java.net.*; -import java.util.*; -import javax.swing.*; -import javax.swing.filechooser.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.debugger.posix.*; -import sun.jvm.hotspot.debugger.windbg.*; -import sun.jvm.hotspot.livejvm.*; -import sun.jvm.hotspot.memory.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.ui.*; -import sun.jvm.hotspot.utilities.*; - -/** The BugSpot component. This is embeddable in an application by - virtue of its being a JComponent. It (currently) requires the use - of a menu bar which can be fetched via getMenuBar(). This is - intended ultimately to replace HSDB. */ - -public class BugSpot extends JPanel { - public BugSpot() { - super(); - Runtime.getRuntime().addShutdownHook(new java.lang.Thread() { - public void run() { - detachDebugger(); - } - }); - } - - /** Turn on or off MDI (Multiple Document Interface) mode. When MDI - is enabled, the BugSpot component contains a JDesktopPane and all - windows are JInternalFrames. When disabled, only the menu bar is - relevant. */ - public void setMDIMode(boolean onOrOff) { - mdiMode = onOrOff; - } - - /** Indicates whether MDI mode is enabled. */ - public boolean getMDIMode() { - return mdiMode; - } - - /** Build user interface widgets. This must be called before adding - the BugSpot component to its parent. */ - public void build() { - setLayout(new BorderLayout()); - - menuBar = new JMenuBar(); - - attachMenuItems = new java.util.ArrayList(); - detachMenuItems = new java.util.ArrayList(); - debugMenuItems = new java.util.ArrayList(); - suspendDebugMenuItems = new java.util.ArrayList(); - resumeDebugMenuItems = new java.util.ArrayList(); - - // - // File menu - // - - JMenu menu = createMenu("File", 'F', 0); - JMenuItem item; - item = createMenuItem("Open source file...", - new ActionListener() { - public void actionPerformed(ActionEvent e) { - openSourceFile(); - } - }, - KeyEvent.VK_O, InputEvent.CTRL_MASK, - 'O', 0); - menu.add(item); - detachMenuItems.add(item); - - menu.addSeparator(); - - item = createMenuItem("Attach to process...", - new ActionListener() { - public void actionPerformed(ActionEvent e) { - showAttachDialog(); - } - }, - 'A', 0); - menu.add(item); - attachMenuItems.add(item); - - item = createMenuItem("Detach", - new ActionListener() { - public void actionPerformed(ActionEvent e) { - detach(); - } - }, - 'D', 0); - menu.add(item); - detachMenuItems.add(item); - - // Disable detach menu items at first - setMenuItemsEnabled(detachMenuItems, false); - - menu.addSeparator(); - - menu.add(createMenuItem("Exit", - new ActionListener() { - public void actionPerformed(ActionEvent e) { - detach(); - System.exit(0); - } - }, - 'x', 1)); - - menuBar.add(menu); - - // - // Debug menu - // - - debugMenu = createMenu("Debug", 'D', 0); - item = createMenuItem("Go", - new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (!attached) return; - if (!isSuspended()) return; - resume(); - } - }, - KeyEvent.VK_F5, 0, - 'G', 0); - debugMenu.add(item); - resumeDebugMenuItems.add(item); - - item = createMenuItem("Break", - new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (!attached) { - System.err.println("Not attached"); - return; - } - if (isSuspended()) { - System.err.println("Already suspended"); - return; - } - suspend(); - } - }, - 'B', 0); - debugMenu.add(item); - suspendDebugMenuItems.add(item); - - debugMenu.addSeparator(); - - item = createMenuItem("Threads...", - new ActionListener() { - public void actionPerformed(ActionEvent e) { - showThreadsDialog(); - } - }, - 'T', 0); - debugMenu.add(item); - debugMenuItems.add(item); - // FIXME: belongs under "View -> Debug Windows" - item = createMenuItem("Memory", - new ActionListener() { - public void actionPerformed(ActionEvent e) { - showMemoryDialog(); - } - }, - 'M', 0); - debugMenu.add(item); - debugMenuItems.add(item); - - debugMenu.setEnabled(false); - menuBar.add(debugMenu); - - if (mdiMode) { - desktop = new JDesktopPane(); - add(desktop, BorderLayout.CENTER); - } - - fixedWidthFont = GraphicsUtilities.lookupFont("Courier"); - - debugEventTimer = new javax.swing.Timer(100, new ActionListener() { - public void actionPerformed(ActionEvent e) { - pollForDebugEvent(); - } - }); - } - - public JMenuBar getMenuBar() { - return menuBar; - } - - public void showAttachDialog() { - setMenuItemsEnabled(attachMenuItems, false); - final FrameWrapper attachDialog = newFrame("Attach to process"); - attachDialog.getContentPane().setLayout(new BorderLayout()); - attachDialog.setClosable(true); - attachDialog.setResizable(true); - - JPanel panel = new JPanel(); - panel.setLayout(new BorderLayout()); - panel.setBorder(GraphicsUtilities.newBorder(5)); - attachDialog.setBackground(panel.getBackground()); - - JPanel listPanel = new JPanel(); - listPanel.setLayout(new BorderLayout()); - final ProcessListPanel plist = new ProcessListPanel(getLocalDebugger()); - panel.add(plist, BorderLayout.CENTER); - JCheckBox check = new JCheckBox("Update list continuously"); - check.addItemListener(new ItemListener() { - public void itemStateChanged(ItemEvent e) { - if (e.getStateChange() == ItemEvent.SELECTED) { - plist.start(); - } else { - plist.stop(); - } - } - }); - listPanel.add(plist, BorderLayout.CENTER); - listPanel.add(check, BorderLayout.SOUTH); - panel.add(listPanel, BorderLayout.CENTER); - attachDialog.getContentPane().add(panel, BorderLayout.CENTER); - attachDialog.setClosingActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - plist.stop(); - setMenuItemsEnabled(attachMenuItems, true); - } - }); - - ActionListener attacher = new ActionListener() { - public void actionPerformed(ActionEvent e) { - plist.stop(); - attachDialog.setVisible(false); - removeFrame(attachDialog); - ProcessInfo info = plist.getSelectedProcess(); - if (info != null) { - attach(info.getPid()); - } - } - }; - - Box hbox = Box.createHorizontalBox(); - hbox.add(Box.createGlue()); - JButton button = new JButton("OK"); - button.addActionListener(attacher); - hbox.add(button); - hbox.add(Box.createHorizontalStrut(20)); - button = new JButton("Cancel"); - button.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - plist.stop(); - attachDialog.setVisible(false); - removeFrame(attachDialog); - setMenuItemsEnabled(attachMenuItems, true); - } - }); - hbox.add(button); - hbox.add(Box.createGlue()); - panel = new JPanel(); - panel.setBorder(GraphicsUtilities.newBorder(5)); - panel.add(hbox); - - attachDialog.getContentPane().add(panel, BorderLayout.SOUTH); - - addFrame(attachDialog); - attachDialog.pack(); - attachDialog.setSize(400, 300); - GraphicsUtilities.centerInContainer(attachDialog.getComponent(), - getParentDimension(attachDialog.getComponent())); - attachDialog.setVisible(true); - } - - public void showThreadsDialog() { - final FrameWrapper threadsDialog = newFrame("Threads"); - threadsDialog.getContentPane().setLayout(new BorderLayout()); - threadsDialog.setClosable(true); - threadsDialog.setResizable(true); - - ThreadListPanel threads = new ThreadListPanel(getCDebugger(), getAgent().isJavaMode()); - threads.addListener(new ThreadListPanel.Listener() { - public void setFocus(ThreadProxy thread, JavaThread jthread) { - setCurrentThread(thread); - // FIXME: print this to GUI, bring some windows to foreground - System.err.println("Focus changed to thread " + thread); - } - }); - threads.setBorder(GraphicsUtilities.newBorder(5)); - threadsDialog.getContentPane().add(threads); - addFrame(threadsDialog); - threadsDialog.pack(); - GraphicsUtilities.reshapeToAspectRatio(threadsDialog.getComponent(), - 3.0f, - 0.9f, - getParentDimension(threadsDialog.getComponent())); - GraphicsUtilities.centerInContainer(threadsDialog.getComponent(), - getParentDimension(threadsDialog.getComponent())); - threadsDialog.setVisible(true); - } - - public void showMemoryDialog() { - final FrameWrapper memoryDialog = newFrame("Memory"); - memoryDialog.getContentPane().setLayout(new BorderLayout()); - memoryDialog.setClosable(true); - memoryDialog.setResizable(true); - - memoryDialog.getContentPane().add(new MemoryViewer(getDebugger(), - (getDebugger().getMachineDescription().getAddressSize() == 8)), - BorderLayout.CENTER); - addFrame(memoryDialog); - memoryDialog.pack(); - GraphicsUtilities.reshapeToAspectRatio(memoryDialog.getComponent(), - 1.0f, - 0.7f, - getParentDimension(memoryDialog.getComponent())); - GraphicsUtilities.centerInContainer(memoryDialog.getComponent(), - getParentDimension(memoryDialog.getComponent())); - memoryDialog.setVisible(true); - } - - /** Changes the editor factory this debugger uses to display source - code. Specified factory may be null, in which case the default - factory is used. */ - public void setEditorFactory(EditorFactory fact) { - if (fact != null) { - editorFact = fact; - } else { - editorFact = new DefaultEditorFactory(); - } - } - - //---------------------------------------------------------------------- - // Internals only below this point - // - - private WorkerThread workerThread; - private boolean mdiMode; - private JVMDebugger localDebugger; - private BugSpotAgent agent = new BugSpotAgent(); - private JMenuBar menuBar; - /** List */ - private java.util.List attachMenuItems; - private java.util.List detachMenuItems; - private java.util.List debugMenuItems; - private java.util.List suspendDebugMenuItems; - private java.util.List resumeDebugMenuItems; - private FrameWrapper stackFrame; - private VariablePanel localsPanel; - private StackTracePanel stackTracePanel; - private FrameWrapper registerFrame; - private RegisterPanel registerPanel; - // Used for mixed-language stack traces - private Map threadToJavaThreadMap; - - private JMenu debugMenu; - - // MDI mode only: desktop pane - private JDesktopPane desktop; - - // Attach/detach state - private boolean attached; - - // Suspension (combined Java/C++) state - private boolean suspended; - - // Fixed-width font - private Font fixedWidthFont; - - // Breakpoint setting - // Maps Strings to List/**/ - private Map sourceFileToLineNumberInfoMap; - // Maps Strings (file names) to Sets of Integers (line numbers) - private Map fileToBreakpointMap; - - // Debug events - private javax.swing.Timer debugEventTimer; - - // Java debug events - private boolean javaEventPending; - - static class BreakpointResult { - private boolean success; - private boolean set; - private int lineNo; - private String why; - - /** For positive results */ - BreakpointResult(boolean success, boolean set, int lineNo) { - this(success, set, lineNo, null); - } - - /** For negative results */ - BreakpointResult(boolean success, boolean set, int lineNo, String why) { - this.success = success; - this.set = set; - this.lineNo = lineNo; - this.why = why; - } - - public boolean succeeded() { - return success; - } - - public boolean set() { - return set; - } - - /** Line at which the breakpoint was actually set; only valid if - succeeded() returns true */ - public int getLine() { - return lineNo; - } - - public String getWhy() { - return why; - } - } - - - // Editors for source code. File name-to-Editor mapping. - private Map editors; - private EditorFactory editorFact = new DefaultEditorFactory(); - private EditorCommands editorComm = new EditorCommands() { - public void windowClosed(Editor editor) { - editors.remove(editor.getSourceFileName()); - } - - public void toggleBreakpointAtLine(Editor editor, int lineNumber) { - // FIXME: handle "lazy" breakpoints where the source file has - // been opened with some other mechanism (File -> Open) and we - // don't have debug information pointing to that file yet - // FIXME: NOT FINISHED - - BreakpointResult res = - handleBreakpointToggle(editor, lineNumber); - if (res.succeeded()) { - if (res.set()) { - editor.showBreakpointAtLine(res.getLine()); - } else { - editor.clearBreakpointAtLine(res.getLine()); - } - } else { - String why = res.getWhy(); - if (why == null) { - why = ""; - } else { - why = ": " + why; - } - showMessageDialog("Unable to toggle breakpoint" + why, - "Unable to toggle breakpoint", - JOptionPane.WARNING_MESSAGE); - } - } - }; - - private void attach(final int pid) { - try { - getAgent().attach(pid); - setMenuItemsEnabled(detachMenuItems, true); - setMenuItemsEnabled(suspendDebugMenuItems, false); - setMenuItemsEnabled(resumeDebugMenuItems, true); - debugMenu.setEnabled(true); - attached = true; - suspended = true; - - if (getAgent().isJavaMode()) { - System.err.println("Java HotSpot(TM) virtual machine detected."); - } else { - System.err.println("(No Java(TM) virtual machine detected)"); - } - - // Set up editor map - editors = new HashMap(); - - // Initialize breakpoints - fileToBreakpointMap = new HashMap(); - - // Create combined stack trace and local variable panel - JPanel framePanel = new JPanel(); - framePanel.setLayout(new BorderLayout()); - framePanel.setBorder(GraphicsUtilities.newBorder(5)); - localsPanel = new VariablePanel(); - JTabbedPane tab = new JTabbedPane(); - tab.addTab("Locals", localsPanel); - tab.setTabPlacement(JTabbedPane.BOTTOM); - framePanel.add(tab, BorderLayout.CENTER); - JPanel stackPanel = new JPanel(); - stackPanel.setLayout(new BoxLayout(stackPanel, BoxLayout.X_AXIS)); - stackPanel.add(new JLabel("Context:")); - stackPanel.add(Box.createHorizontalStrut(5)); - stackTracePanel = new StackTracePanel(); - stackTracePanel.addListener(new StackTracePanel.Listener() { - public void frameChanged(CFrame fr, JavaVFrame jfr) { - setCurrentFrame(fr, jfr); - } - }); - stackPanel.add(stackTracePanel); - framePanel.add(stackPanel, BorderLayout.NORTH); - stackFrame = newFrame("Stack"); - stackFrame.getContentPane().setLayout(new BorderLayout()); - stackFrame.getContentPane().add(framePanel, BorderLayout.CENTER); - stackFrame.setResizable(true); - stackFrame.setClosable(false); - addFrame(stackFrame); - stackFrame.setSize(400, 200); - GraphicsUtilities.moveToInContainer(stackFrame.getComponent(), 0.0f, 1.0f, 0, 20); - stackFrame.setVisible(true); - - // Create register panel - registerPanel = new RegisterPanel(); - registerPanel.setFont(fixedWidthFont); - registerFrame = newFrame("Registers"); - registerFrame.getContentPane().setLayout(new BorderLayout()); - registerFrame.getContentPane().add(registerPanel, BorderLayout.CENTER); - addFrame(registerFrame); - registerFrame.setResizable(true); - registerFrame.setClosable(false); - registerFrame.setSize(225, 200); - GraphicsUtilities.moveToInContainer(registerFrame.getComponent(), - 1.0f, 0.0f, 0, 0); - registerFrame.setVisible(true); - - resetCurrentThread(); - } catch (DebuggerException e) { - final String errMsg = formatMessage(e.getMessage(), 80); - setMenuItemsEnabled(attachMenuItems, true); - showMessageDialog("Unable to connect to process ID " + pid + ":\n\n" + errMsg, - "Unable to Connect", - JOptionPane.WARNING_MESSAGE); - getAgent().detach(); - } - } - - private synchronized void detachDebugger() { - if (!attached) { - return; - } - if (isSuspended()) { - resume(); // Necessary for JVMDI resumption - } - getAgent().detach(); - // FIXME: clear out breakpoints (both Java and C/C++) from target - // process - sourceFileToLineNumberInfoMap = null; - fileToBreakpointMap = null; - threadToJavaThreadMap = null; - editors = null; - attached = false; - } - - private synchronized void detach() { - detachDebugger(); - setMenuItemsEnabled(attachMenuItems, true); - setMenuItemsEnabled(detachMenuItems, false); - debugMenu.setEnabled(false); - if (mdiMode) { - // FIXME: is this sufficient, or will I have to do anything else - // to the components to kill them off? What about WorkerThreads? - desktop.removeAll(); - desktop.invalidate(); - desktop.validate(); - desktop.repaint(); - } - // FIXME: keep track of all windows and close them even in non-MDI - // mode - debugEventTimer.stop(); - } - - // Returns a Debugger for processes on the local machine. This is - // only used to fetch the process list. - private Debugger getLocalDebugger() { - if (localDebugger == null) { - String os = PlatformInfo.getOS(); - String cpu = PlatformInfo.getCPU(); - - if (os.equals("win32")) { - if (!cpu.equals("x86")) { - throw new DebuggerException("Unsupported CPU \"" + cpu + "\" for Windows"); - } - - localDebugger = new WindbgDebuggerLocal(new MachineDescriptionIntelX86(), true); - } else if (os.equals("linux")) { - if (!cpu.equals("x86")) { - throw new DebuggerException("Unsupported CPU \"" + cpu + "\" for Linux"); - } - - // FIXME: figure out how to specify path to debugger module - throw new RuntimeException("FIXME: figure out how to specify path to debugger module"); - // localDebugger = new PosixDebuggerLocal(new MachineDescriptionIntelX86(), true); - } else { - // FIXME: port to Solaris - throw new DebuggerException("Unsupported OS \"" + os + "\""); - } - - // FIXME: we require that the primitive type sizes be configured - // in order to use basic functionality in class Address such as - // the fetching of floating-point values. There are a lot of - // assumptions in the current code that Java floats and doubles - // are of equivalent size to C values. The configurability of the - // primitive type sizes hasn't seemed necessary and in this kind - // of debugging scenario (namely, debugging arbitrary C++ - // processes) it appears difficult to support that kind of - // flexibility. - localDebugger.configureJavaPrimitiveTypeSizes(1, 1, 2, 8, 4, 4, 8, 2); - } - - return localDebugger; - } - - private BugSpotAgent getAgent() { - return agent; - } - - private Debugger getDebugger() { - return getAgent().getDebugger(); - } - - private CDebugger getCDebugger() { - return getAgent().getCDebugger(); - } - - private void resetCurrentThread() { - setCurrentThread((ThreadProxy) getCDebugger().getThreadList().get(0)); - } - - private void setCurrentThread(ThreadProxy t) { - // Create stack trace - // FIXME: add ability to intermix C/Java frames - java.util.List trace = new ArrayList(); - CFrame fr = getCDebugger().topFrameForThread(t); - while (fr != null) { - trace.add(new StackTraceEntry(fr, getCDebugger())); - try { - fr = fr.sender(t); - } catch (AddressException e) { - e.printStackTrace(); - showMessageDialog("Error while walking stack; stack trace will be truncated\n(see console for details)", - "Error walking stack", - JOptionPane.WARNING_MESSAGE); - fr = null; - } - } - JavaThread jthread = javaThreadForProxy(t); - if (jthread != null) { - // Java mode, and we have a Java thread. - // Find all Java frames on the stack. We currently do this in a - // manner which involves minimal interaction between the Java - // and C/C++ debugging systems: any C frame which has a PC in an - // unknown location (i.e., not in any DSO) is assumed to be a - // Java frame. We merge stack segments of unknown frames with - // segments of Java frames beginning with native methods. - java.util.List javaTrace = new ArrayList(); - VFrame vf = jthread.getLastJavaVFrameDbg(); - while (vf != null) { - if (vf.isJavaFrame()) { - javaTrace.add(new StackTraceEntry((JavaVFrame) vf)); - vf = vf.sender(); - } - } - // Merge stack traces - java.util.List mergedTrace = new ArrayList(); - int c = 0; - int j = 0; - while (c < trace.size()) { - StackTraceEntry entry = (StackTraceEntry) trace.get(c); - if (entry.isUnknownCFrame()) { - boolean gotJavaFrame = false; - while (j < javaTrace.size()) { - StackTraceEntry javaEntry = (StackTraceEntry) javaTrace.get(j); - JavaVFrame jvf = javaEntry.getJavaFrame(); - Method m = jvf.getMethod(); - if (!m.isNative() || !gotJavaFrame) { - gotJavaFrame = true; - mergedTrace.add(javaEntry); - ++j; - } else { - break; // Reached native method; have intervening C frames - } - } - if (gotJavaFrame) { - // Skip this sequence of unknown frames, as we've - // successfully identified it as Java frames - while (c < trace.size() && entry.isUnknownCFrame()) { - ++c; - if (c < trace.size()) { - entry = (StackTraceEntry) trace.get(c); - } - } - continue; - } - } - // If we get here, we either have an unknown frame we didn't - // know how to categorize or we have a known C frame. Add it - // to the trace. - mergedTrace.add(entry); - ++c; - } - trace = mergedTrace; - } - stackTracePanel.setTrace(trace); - - registerPanel.update(t); - } - - private void setCurrentFrame(CFrame fr, JavaVFrame jfr) { - localsPanel.clear(); - - if (fr != null) { - localsPanel.update(fr); - - // FIXME: load source file if we can find it, otherwise display disassembly - LoadObject lo = getCDebugger().loadObjectContainingPC(fr.pc()); - if (lo != null) { - CDebugInfoDataBase db = lo.getDebugInfoDataBase(); - if (db != null) { - LineNumberInfo info = db.lineNumberForPC(fr.pc()); - if (info != null) { - System.err.println("PC " + fr.pc() + ": Source file \"" + - info.getSourceFileName() + - "\", line number " + - info.getLineNumber() + - ", PC range [" + - info.getStartPC() + - ", " + - info.getEndPC() + - ")"); - // OK, here we go... - showLineNumber(null, info.getSourceFileName(), info.getLineNumber()); - } else { - System.err.println("(No line number information for PC " + fr.pc() + ")"); - // Dump line number information for database - db.iterate(new LineNumberVisitor() { - public void doLineNumber(LineNumberInfo info) { - System.err.println(" Source file \"" + - info.getSourceFileName() + - "\", line number " + - info.getLineNumber() + - ", PC range [" + - info.getStartPC() + - ", " + - info.getEndPC() + - ")"); - } - }); - } - } - } - } else { - if (Assert.ASSERTS_ENABLED) { - Assert.that(jfr != null, "Must have either C or Java frame"); - } - localsPanel.update(jfr); - // See whether we can locate source file and line number - // FIXME: infer pathmap entries from user's locating of this - // source file - // FIXME: figure out what to do for native methods. Possible to - // go to line number for the native method declaration? - Method m = jfr.getMethod(); - Symbol sfn = ((InstanceKlass) m.getMethodHolder()).getSourceFileName(); - if (sfn != null) { - int bci = jfr.getBCI(); - int lineNo = m.getLineNumberFromBCI(bci); - if (lineNo >= 0) { - // FIXME: show disassembly otherwise - showLineNumber(packageName(m.getMethodHolder().getName().asString()), - sfn.asString(), lineNo); - } - } - } - } - - private String packageName(String str) { - int idx = str.lastIndexOf('/'); - if (idx < 0) { - return ""; - } - return str.substring(0, idx).replace('/', '.'); - } - - private JavaThread javaThreadForProxy(ThreadProxy t) { - if (!getAgent().isJavaMode()) { - return null; - } - if (threadToJavaThreadMap == null) { - threadToJavaThreadMap = new HashMap(); - Threads threads = VM.getVM().getThreads(); - for (JavaThread thr = threads.first(); thr != null; thr = thr.next()) { - threadToJavaThreadMap.put(thr.getThreadProxy(), thr); - } - } - return (JavaThread) threadToJavaThreadMap.get(t); - } - - private static JMenu createMenu(String name, char mnemonic, int mnemonicPos) { - JMenu menu = new JMenu(name); - menu.setMnemonic(mnemonic); - menu.setDisplayedMnemonicIndex(mnemonicPos); - return menu; - } - - private static JMenuItem createMenuItem(String name, ActionListener l) { - JMenuItem item = new JMenuItem(name); - item.addActionListener(l); - return item; - } - - private static JMenuItem createMenuItemInternal(String name, ActionListener l, int accelerator, int modifiers) { - JMenuItem item = createMenuItem(name, l); - item.setAccelerator(KeyStroke.getKeyStroke(accelerator, modifiers)); - return item; - } - - private static JMenuItem createMenuItem(String name, ActionListener l, int accelerator) { - return createMenuItemInternal(name, l, accelerator, 0); - } - - private static JMenuItem createMenuItem(String name, ActionListener l, char mnemonic, int mnemonicPos) { - JMenuItem item = createMenuItem(name, l); - item.setMnemonic(mnemonic); - item.setDisplayedMnemonicIndex(mnemonicPos); - return item; - } - - private static JMenuItem createMenuItem(String name, - ActionListener l, - int accelerator, - int acceleratorMods, - char mnemonic, - int mnemonicPos) { - JMenuItem item = createMenuItemInternal(name, l, accelerator, acceleratorMods); - item.setMnemonic(mnemonic); - item.setDisplayedMnemonicIndex(mnemonicPos); - return item; - } - - /** Punctuates the given string with \n's where necessary to not - exceed the given number of characters per line. Strips - extraneous whitespace. */ - private static String formatMessage(String message, int charsPerLine) { - StringBuffer buf = new StringBuffer(message.length()); - StringTokenizer tokenizer = new StringTokenizer(message); - int curLineLength = 0; - while (tokenizer.hasMoreTokens()) { - String tok = tokenizer.nextToken(); - if (curLineLength + tok.length() > charsPerLine) { - buf.append('\n'); - curLineLength = 0; - } else { - if (curLineLength != 0) { - buf.append(' '); - ++curLineLength; - } - } - buf.append(tok); - curLineLength += tok.length(); - } - return buf.toString(); - } - - private void setMenuItemsEnabled(java.util.List items, boolean enabled) { - for (Iterator iter = items.iterator(); iter.hasNext(); ) { - ((JMenuItem) iter.next()).setEnabled(enabled); - } - } - - private void showMessageDialog(final String message, final String title, final int jOptionPaneKind) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - if (mdiMode) { - JOptionPane.showInternalMessageDialog(desktop, message, title, jOptionPaneKind); - } else { - JOptionPane.showMessageDialog(null, message, title, jOptionPaneKind); - } - } - }); - } - - private FrameWrapper newFrame(String title) { - if (mdiMode) { - return new JInternalFrameWrapper(new JInternalFrame(title)); - } else { - return new JFrameWrapper(new JFrame(title)); - } - } - - private void addFrame(FrameWrapper frame) { - if (mdiMode) { - desktop.add(frame.getComponent()); - } - } - - private void removeFrame(FrameWrapper frame) { - if (mdiMode) { - desktop.remove(frame.getComponent()); - desktop.invalidate(); - desktop.validate(); - desktop.repaint(); - } - // FIXME: do something when not in MDI mode - } - - private Dimension getParentDimension(Component c) { - if (mdiMode) { - return desktop.getSize(); - } else { - return Toolkit.getDefaultToolkit().getScreenSize(); - } - } - - // Default editor implementation - class DefaultEditor implements Editor { - private DefaultEditorFactory factory; - private FrameWrapper editorFrame; - private String filename; - private SourceCodePanel code; - private boolean shown; - private Object userData; - - public DefaultEditor(DefaultEditorFactory fact, String filename, final EditorCommands comm) { - this.filename = filename; - this.factory = fact; - editorFrame = newFrame(filename); - code = new SourceCodePanel(); - // FIXME: when font changes, change font in editors as well - code.setFont(fixedWidthFont); - editorFrame.getContentPane().add(code); - editorFrame.setClosable(true); - editorFrame.setResizable(true); - editorFrame.setClosingActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - comm.windowClosed(DefaultEditor.this); - removeFrame(editorFrame); - editorFrame.dispose(); - factory.editorClosed(DefaultEditor.this); - } - }); - editorFrame.setActivatedActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - factory.makeEditorCurrent(DefaultEditor.this); - code.requestFocus(); - } - }); - code.setEditorCommands(comm, this); - } - - public boolean openFile() { return code.openFile(filename); } - public String getSourceFileName() { return filename; } - public int getCurrentLineNumber() { return code.getCurrentLineNumber(); } - public void showLineNumber(int lineNo) { - if (!shown) { - addFrame(editorFrame); - GraphicsUtilities.reshapeToAspectRatio(editorFrame.getComponent(), - 1.0f, - 0.85f, - getParentDimension(editorFrame.getComponent())); - editorFrame.setVisible(true); - shown = true; - } - code.showLineNumber(lineNo); - editorFrame.toFront(); - } - public void highlightLineNumber(int lineNo) { code.highlightLineNumber(lineNo); } - public void showBreakpointAtLine(int lineNo) { code.showBreakpointAtLine(lineNo); } - public boolean hasBreakpointAtLine(int lineNo) { return code.hasBreakpointAtLine(lineNo); } - public void clearBreakpointAtLine(int lineNo) { code.clearBreakpointAtLine(lineNo); } - public void clearBreakpoints() { code.clearBreakpoints(); } - public void setUserData(Object o) { userData = o; } - public Object getUserData() { return userData; } - public void toFront() { editorFrame.toFront(); - factory.makeEditorCurrent(this); } - } - - class DefaultEditorFactory implements EditorFactory { - private LinkedList/**/ editors = new LinkedList(); - - public Editor openFile(String filename, EditorCommands commands) { - DefaultEditor editor = new DefaultEditor(this, filename, editorComm); - if (!editor.openFile()) { - return null; - } - return editor; - } - - public Editor getCurrentEditor() { - if (editors.isEmpty()) { - return null; - } - return (Editor) editors.getFirst(); - } - - void editorClosed(Editor editor) { - editors.remove(editor); - } - - void makeEditorCurrent(Editor editor) { - editors.remove(editor); - editors.addFirst(editor); - } - } - - // Helper class for loading .java files; show only those with - // correct file name which are also in the correct package - static class JavaFileFilter extends javax.swing.filechooser.FileFilter { - private String packageName; - private String fileName; - - JavaFileFilter(String packageName, String fileName) { - this.packageName = packageName; - this.fileName = fileName; - } - - public boolean accept(File f) { - if (f.isDirectory()) { - return true; - } - // This rejects most files - if (!f.getName().equals(fileName)) { - return false; - } - // Ensure selected file is in the correct package - PackageScanner scanner = new PackageScanner(); - String pkg = scanner.scan(f); - if (!pkg.equals(packageName)) { - return false; - } - return true; - } - - public String getDescription() { return "Java source files"; } - } - - // Auxiliary information used only for Java source files - static class JavaUserData { - private String packageName; // External format - private String sourceFileName; - - /** Source file name is equivalent to that found in the .java - file; i.e., not a full path */ - JavaUserData(String packageName, String sourceFileName) { - this.packageName = packageName; - this.sourceFileName = sourceFileName; - } - - String packageName() { return packageName; } - String sourceFileName() { return sourceFileName; } - } - - // Opens a source file. This makes it available for the setting of - // lazy breakpoints. - private void openSourceFile() { - JFileChooser chooser = new JFileChooser(); - chooser.setDialogTitle("Open source code file"); - chooser.setMultiSelectionEnabled(false); - if (chooser.showOpenDialog(null) != JFileChooser.APPROVE_OPTION) { - return; - } - File chosen = chooser.getSelectedFile(); - if (chosen == null) { - return; - } - - // See whether we have a Java source file. If so, derive a package - // name for it. - String path = chosen.getPath(); - String name = null; - JavaUserData data = null; - if (path.endsWith(".java")) { - PackageScanner scanner = new PackageScanner(); - String pkg = scanner.scan(chosen); - // Now knowing both the package name and file name, we can put - // this in the editor map and use it for setting breakpoints - // later - String fileName = chosen.getName(); - name = pkg + "." + fileName; - data = new JavaUserData(pkg, fileName); - } else { - // FIXME: need pathmap mechanism - name = path; - } - Editor editor = (Editor) editors.get(name); - if (editor == null) { - editor = editorFact.openFile(path, editorComm); - if (editor == null) { - showMessageDialog("Unable to open file \"" + path + "\" -- unexpected error.", - "Unable to open file", - JOptionPane.WARNING_MESSAGE); - return; - } - editors.put(name, editor); - if (data != null) { - editor.setUserData(data); - } - } else { - editor.toFront(); - } - editor.showLineNumber(1); - // Show breakpoints as well if we have any for this file - Set set = (Set) fileToBreakpointMap.get(editor.getSourceFileName()); - if (set != null) { - for (Iterator iter = set.iterator(); iter.hasNext(); ) { - editor.showBreakpointAtLine(((Integer) iter.next()).intValue()); - } - } - } - - // Package name may be null, in which case the file is assumed to be - // a C source file. Otherwise it is assumed to be a Java source file - // and certain filtering rules will be applied. - private void showLineNumber(String packageName, String fileName, int lineNumber) { - String name; - if (packageName == null) { - name = fileName; - } else { - name = packageName + "." + fileName; - } - Editor editor = (Editor) editors.get(name); - if (editor == null) { - // See whether file exists - File file = new File(fileName); - String realFileName = fileName; - if (!file.exists()) { - // User must specify path to file - JFileChooser chooser = new JFileChooser(); - chooser.setDialogTitle("Please locate " + fileName); - chooser.setMultiSelectionEnabled(false); - if (packageName != null) { - chooser.setFileFilter(new JavaFileFilter(packageName, fileName)); - } - int res = chooser.showOpenDialog(null); - if (res != JFileChooser.APPROVE_OPTION) { - // FIXME: show disassembly instead - return; - } - // FIXME: would like to infer more from the selection; i.e., - // a pathmap leading up to this file - File chosen = chooser.getSelectedFile(); - if (chosen == null) { - return; - } - realFileName = chosen.getPath(); - } - // Now instruct editor factory to open file - editor = editorFact.openFile(realFileName, editorComm); - if (editor == null) { - showMessageDialog("Unable to open file \"" + realFileName + "\" -- unexpected error.", - "Unable to open file", - JOptionPane.WARNING_MESSAGE); - return; - } - // Got an editor; put it in map - editors.put(name, editor); - // If Java source file, add additional information for later - if (packageName != null) { - editor.setUserData(new JavaUserData(packageName, fileName)); - } - } - // Got editor; show line - editor.showLineNumber(lineNumber); - editor.highlightLineNumber(lineNumber); - // Show breakpoints as well if we have any for this file - Set set = (Set) fileToBreakpointMap.get(editor.getSourceFileName()); - if (set != null) { - for (Iterator iter = set.iterator(); iter.hasNext(); ) { - editor.showBreakpointAtLine(((Integer) iter.next()).intValue()); - } - } - } - - // - // Suspend/resume - // - - private boolean isSuspended() { - return suspended; - } - - private synchronized void suspend() { - setMenuItemsEnabled(resumeDebugMenuItems, true); - setMenuItemsEnabled(suspendDebugMenuItems, false); - BugSpotAgent agent = getAgent(); - if (agent.canInteractWithJava() && !agent.isJavaSuspended()) { - agent.suspendJava(); - } - agent.suspend(); - // FIXME: call VM.getVM().fireVMSuspended() - resetCurrentThread(); - debugEventTimer.stop(); - suspended = true; - } - - private synchronized void resume() { - // Note: we don't wipe out the cached state like the - // sourceFileToLineNumberInfoMap since it is too expensive to - // recompute. Instead we recompute it if any DLLs are loaded or - // unloaded. - threadToJavaThreadMap = null; - setMenuItemsEnabled(resumeDebugMenuItems, false); - setMenuItemsEnabled(suspendDebugMenuItems, true); - registerPanel.clear(); - // FIXME: call VM.getVM().fireVMResumed() - BugSpotAgent agent = getAgent(); - agent.resume(); - if (agent.canInteractWithJava()) { - if (agent.isJavaSuspended()) { - agent.resumeJava(); - } - if (javaEventPending) { - javaEventPending = false; - // Clear it out before resuming polling for events - agent.javaEventContinue(); - } - } - agent.enableJavaInteraction(); - suspended = false; - debugEventTimer.start(); - } - - // - // Breakpoints - // - - private synchronized BreakpointResult handleBreakpointToggle(Editor editor, int lineNumber) { - // Currently we only use user data in editors to indicate Java - // source files. If this changes then this code will need to - // change. - JavaUserData data = (JavaUserData) editor.getUserData(); - String filename = editor.getSourceFileName(); - if (data == null) { - // C/C++ code - // FIXME: as noted above in EditorCommands.toggleBreakpointAtLine, - // this needs more work to handle "lazy" breakpoints in files - // which we don't know about in the debug information yet - CDebugger dbg = getCDebugger(); - ProcessControl prctl = dbg.getProcessControl(); - if (prctl == null) { - return new BreakpointResult(false, false, 0, "Process control not enabled"); - } - boolean mustSuspendAndResume = (!prctl.isSuspended()); - try { - if (mustSuspendAndResume) { - prctl.suspend(); - } - // Search debug info for all DSOs - LineNumberInfo info = getLineNumberInfo(filename, lineNumber); - if (info != null) { - Set bpset = (Set) fileToBreakpointMap.get(filename); - if (bpset == null) { - bpset = new HashSet(); - fileToBreakpointMap.put(filename, bpset); - } - Integer key = new Integer(info.getLineNumber()); - if (bpset.contains(key)) { - // Clear breakpoint at this line's PC - prctl.clearBreakpoint(info.getStartPC()); - bpset.remove(key); - return new BreakpointResult(true, false, info.getLineNumber()); - } else { - // Set breakpoint at this line's PC - System.err.println("Setting breakpoint at PC " + info.getStartPC()); - prctl.setBreakpoint(info.getStartPC()); - bpset.add(key); - return new BreakpointResult(true, true, info.getLineNumber()); - } - } else { - return new BreakpointResult(false, false, 0, "No debug information for this source file and line"); - } - } finally { - if (mustSuspendAndResume) { - prctl.resume(); - } - } - } else { - BugSpotAgent agent = getAgent(); - if (!agent.canInteractWithJava()) { - String why; - if (agent.isJavaInteractionDisabled()) { - why = "Can not toggle Java breakpoints while stopped because\nof C/C++ debug events (breakpoints, single-stepping)"; - } else { - why = "Could not talk to SA's JVMDI module to enable Java\nprogramming language breakpoints (run with -Xdebug -Xrunsa)"; - } - return new BreakpointResult(false, false, 0, why); - } - Set bpset = (Set) fileToBreakpointMap.get(filename); - if (bpset == null) { - bpset = new HashSet(); - fileToBreakpointMap.put(filename, bpset); - } - boolean mustResumeAndSuspend = isSuspended(); - try { - if (mustResumeAndSuspend) { - agent.resume(); - } - ServiceabilityAgentJVMDIModule.BreakpointToggleResult res = - getAgent().toggleJavaBreakpoint(data.sourceFileName(), - data.packageName(), - lineNumber); - if (res.getSuccess()) { - Integer key = new Integer(res.getLineNumber()); - boolean addRemRes = false; - if (res.getWasSet()) { - addRemRes = bpset.add(key); - System.err.println("Setting breakpoint at " + res.getMethodName() + res.getMethodSignature() + - ", bci " + res.getBCI() + ", line " + res.getLineNumber()); - } else { - addRemRes = bpset.remove(key); - System.err.println("Clearing breakpoint at " + res.getMethodName() + res.getMethodSignature() + - ", bci " + res.getBCI() + ", line " + res.getLineNumber()); - } - if (Assert.ASSERTS_ENABLED) { - Assert.that(addRemRes, "Inconsistent Java breakpoint state with respect to target process"); - } - return new BreakpointResult(true, res.getWasSet(), res.getLineNumber()); - } else { - return new BreakpointResult(false, false, 0, res.getErrMsg()); - } - } finally { - if (mustResumeAndSuspend) { - agent.suspend(); - resetCurrentThread(); - } - } - } - } - - // Must call only when suspended - private LineNumberInfo getLineNumberInfo(String filename, int lineNumber) { - Map map = getSourceFileToLineNumberInfoMap(); - java.util.List infos = (java.util.List) map.get(filename); - if (infos == null) { - return null; - } - // Binary search for line number - return searchLineNumbers(infos, lineNumber, 0, infos.size()); - } - - // Must call only when suspended - private Map getSourceFileToLineNumberInfoMap() { - if (sourceFileToLineNumberInfoMap == null) { - // Build from debug info - java.util.List loadObjects = getCDebugger().getLoadObjectList(); - final Map map = new HashMap(); - for (Iterator iter = loadObjects.iterator(); iter.hasNext(); ) { - LoadObject lo = (LoadObject) iter.next(); - CDebugInfoDataBase db = lo.getDebugInfoDataBase(); - if (db != null) { - db.iterate(new LineNumberVisitor() { - public void doLineNumber(LineNumberInfo info) { - String name = info.getSourceFileName(); - if (name != null) { - java.util.List val = (java.util.List) map.get(name); - if (val == null) { - val = new ArrayList(); - map.put(name, val); - } - val.add(info); - } - } - }); - } - } - // Sort all lists - for (Iterator iter = map.values().iterator(); iter.hasNext(); ) { - java.util.List list = (java.util.List) iter.next(); - Collections.sort(list, new Comparator() { - public int compare(Object o1, Object o2) { - LineNumberInfo l1 = (LineNumberInfo) o1; - LineNumberInfo l2 = (LineNumberInfo) o2; - int n1 = l1.getLineNumber(); - int n2 = l2.getLineNumber(); - if (n1 < n2) return -1; - if (n1 == n2) return 0; - return 1; - } - }); - } - sourceFileToLineNumberInfoMap = map; - } - return sourceFileToLineNumberInfoMap; - } - - private LineNumberInfo searchLineNumbers(java.util.List infoList, int lineNo, int lowIdx, int highIdx) { - if (highIdx < lowIdx) return null; - if (lowIdx == highIdx) { - // Base case: see whether start PC is less than or equal to addr - if (checkLineNumber(infoList, lineNo, lowIdx)) { - return (LineNumberInfo) infoList.get(lowIdx); - } else { - return null; - } - } else if (lowIdx == highIdx - 1) { - if (checkLineNumber(infoList, lineNo, lowIdx)) { - return (LineNumberInfo) infoList.get(lowIdx); - } else if (checkLineNumber(infoList, lineNo, highIdx)) { - return (LineNumberInfo) infoList.get(highIdx); - } else { - return null; - } - } - int midIdx = (lowIdx + highIdx) >> 1; - LineNumberInfo info = (LineNumberInfo) infoList.get(midIdx); - if (lineNo < info.getLineNumber()) { - // Always move search down - return searchLineNumbers(infoList, lineNo, lowIdx, midIdx); - } else if (lineNo == info.getLineNumber()) { - return info; - } else { - // Move search up - return searchLineNumbers(infoList, lineNo, midIdx, highIdx); - } - } - - private boolean checkLineNumber(java.util.List infoList, int lineNo, int idx) { - LineNumberInfo info = (LineNumberInfo) infoList.get(idx); - return (info.getLineNumber() >= lineNo); - } - - // - // Debug events - // - - private synchronized void pollForDebugEvent() { - ProcessControl prctl = getCDebugger().getProcessControl(); - if (prctl == null) { - return; - } - DebugEvent ev = prctl.debugEventPoll(); - if (ev != null) { - DebugEvent.Type t = ev.getType(); - if (t == DebugEvent.Type.LOADOBJECT_LOAD || - t == DebugEvent.Type.LOADOBJECT_UNLOAD) { - // Conservatively clear cached debug info state - sourceFileToLineNumberInfoMap = null; - // FIXME: would be very useful to have "stop on load/unload" - // events - // FIXME: must do work at these events to implement lazy - // breakpoints - prctl.debugEventContinue(); - } else if (t == DebugEvent.Type.BREAKPOINT) { - // Note: Visual C++ only notifies on breakpoints it doesn't - // know about - - // FIXME: put back test - // if (!prctl.isBreakpointSet(ev.getPC())) { - showMessageDialog("Breakpoint reached at PC " + ev.getPC(), - "Breakpoint reached", - JOptionPane.INFORMATION_MESSAGE); - // } - agent.disableJavaInteraction(); - suspend(); - prctl.debugEventContinue(); - } else if (t == DebugEvent.Type.SINGLE_STEP) { - agent.disableJavaInteraction(); - suspend(); - prctl.debugEventContinue(); - } else if (t == DebugEvent.Type.ACCESS_VIOLATION) { - showMessageDialog("Access violation attempting to " + - (ev.getWasWrite() ? "write" : "read") + - " address " + ev.getAddress() + - " at PC " + ev.getPC(), - "Access Violation", - JOptionPane.WARNING_MESSAGE); - agent.disableJavaInteraction(); - suspend(); - prctl.debugEventContinue(); - } else { - String info = "Unknown debug event encountered"; - if (ev.getUnknownEventDetail() != null) { - info = info + ": " + ev.getUnknownEventDetail(); - } - showMessageDialog(info, "Unknown debug event", JOptionPane.INFORMATION_MESSAGE); - suspend(); - prctl.debugEventContinue(); - } - return; - } - - // No C++ debug event; poll for Java debug event - if (getAgent().canInteractWithJava()) { - if (!javaEventPending) { - if (getAgent().javaEventPending()) { - suspend(); - // This does a lot of work and we want to have the page - // cache available to us as it runs - sun.jvm.hotspot.livejvm.Event jev = getAgent().javaEventPoll(); - if (jev != null) { - javaEventPending = true; - if (jev.getType() == sun.jvm.hotspot.livejvm.Event.Type.BREAKPOINT) { - BreakpointEvent bpev = (BreakpointEvent) jev; - showMessageDialog("Breakpoint reached in method\n" + - bpev.methodID().method().externalNameAndSignature() + - ",\nbci " + bpev.location(), - "Breakpoint reached", - JOptionPane.INFORMATION_MESSAGE); - } else if (jev.getType() == sun.jvm.hotspot.livejvm.Event.Type.EXCEPTION) { - ExceptionEvent exev = (ExceptionEvent) jev; - showMessageDialog(exev.exception().getKlass().getName().asString() + - "\nthrown in method\n" + - exev.methodID().method().externalNameAndSignature() + - "\nat BCI " + exev.location(), - "Exception thrown", - JOptionPane.INFORMATION_MESSAGE); - } else { - Assert.that(false, "Should not reach here"); - } - } - } - } - } - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/BugSpotAgent.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/BugSpotAgent.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,799 +0,0 @@ -/* - * Copyright (c) 2002, 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 sun.jvm.hotspot.bugspot; - -import java.io.PrintStream; -import java.net.*; -import java.rmi.*; -import sun.jvm.hotspot.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.debugger.bsd.*; -import sun.jvm.hotspot.debugger.proc.*; -import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.debugger.windbg.*; -import sun.jvm.hotspot.debugger.linux.*; -import sun.jvm.hotspot.debugger.sparc.*; -import sun.jvm.hotspot.debugger.remote.*; -import sun.jvm.hotspot.livejvm.*; -import sun.jvm.hotspot.memory.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.*; - -/**

This class wraps the basic functionality for connecting to the - * target process or debug server. It makes it simple to start up the - * debugging system.

- * - *

This agent (as compared to the HotSpotAgent) can connect to - * and interact with arbitrary processes. If the target process - * happens to be a HotSpot JVM, the Java debugging features of the - * Serviceability Agent are enabled. Further, if the Serviceability - * Agent's JVMDI module is loaded into the target VM, interaction - * with the live Java program is possible, specifically the catching - * of exceptions and setting of breakpoints.

- * - *

The BugSpot debugger requires that the underlying Debugger - * support C/C++ debugging via the CDebugger interface.

- * - *

FIXME: especially with the addition of remote debugging, this - * has turned into a mess; needs rethinking.

*/ - -public class BugSpotAgent { - - private JVMDebugger debugger; - private MachineDescription machDesc; - private TypeDataBase db; - - private String os; - private String cpu; - private String fileSep; - - // The system can work in several ways: - // - Attaching to local process - // - Attaching to local core file - // - Connecting to remote debug server - // - Starting debug server for process - // - Starting debug server for core file - - // These are options for the "client" side of things - private static final int PROCESS_MODE = 0; - private static final int CORE_FILE_MODE = 1; - private static final int REMOTE_MODE = 2; - private int startupMode; - - // This indicates whether we are really starting a server or not - private boolean isServer; - - // All possible required information for connecting - private int pid; - private String executableName; - private String coreFileName; - private String debugServerID; - - // All needed information for server side - private String serverID; - - // Indicates whether we are attached to a HotSpot JVM or not - private boolean javaMode; - - // Indicates whether we have process control over a live HotSpot JVM - // or not; non-null if so. - private ServiceabilityAgentJVMDIModule jvmdi; - // While handling C breakpoints interactivity with the Java program - // is forbidden. Too many invariants are broken while the target is - // stopped at a C breakpoint to risk making JVMDI calls. - private boolean javaInteractionDisabled; - - private String[] jvmLibNames; - private String[] saLibNames; - - // FIXME: make these configurable, i.e., via a dotfile; also - // consider searching within the JDK from which this Java executable - // comes to find them - private static final String defaultDbxPathPrefix = "/net/jano.eng/export/disk05/hotspot/sa"; - private static final String defaultDbxSvcAgentDSOPathPrefix = "/net/jano.eng/export/disk05/hotspot/sa"; - - private static final boolean DEBUG; - static { - DEBUG = System.getProperty("sun.jvm.hotspot.bugspot.BugSpotAgent.DEBUG") - != null; - } - - static void debugPrintln(String str) { - if (DEBUG) { - System.err.println(str); - } - } - - static void showUsage() { - System.out.println(" You can also pass these -D options to java to specify where to find dbx and the \n" + - " Serviceability Agent plugin for dbx:"); - System.out.println(" -DdbxPathName=\n" + - " Default is derived from dbxPathPrefix"); - System.out.println(" or"); - System.out.println(" -DdbxPathPrefix=\n" + - " where xxx is the path name of a dir structure that contains:\n" + - " //bin/dbx\n" + - " The default is " + defaultDbxPathPrefix); - System.out.println(" and"); - System.out.println(" -DdbxSvcAgentDSOPathName=\n" + - " Default is determined from dbxSvcAgentDSOPathPrefix"); - System.out.println(" or"); - System.out.println(" -DdbxSvcAgentDSOPathPrefix=\n" + - " where xxx is the pathname of a dir structure that contains:\n" + - " //bin/lib/libsvc_agent_dbx.so\n" + - " The default is " + defaultDbxSvcAgentDSOPathPrefix); - } - - public BugSpotAgent() { - // for non-server add shutdown hook to clean-up debugger in case - // of forced exit. For remote server, shutdown hook is added by - // DebugServer. - Runtime.getRuntime().addShutdownHook(new java.lang.Thread( - new Runnable() { - public void run() { - synchronized (BugSpotAgent.this) { - if (!isServer) { - detach(); - } - } - } - })); - } - - //-------------------------------------------------------------------------------- - // Accessors (once the system is set up) - // - - public synchronized Debugger getDebugger() { - return debugger; - } - - public synchronized CDebugger getCDebugger() { - return getDebugger().getCDebugger(); - } - - public synchronized ProcessControl getProcessControl() { - return getCDebugger().getProcessControl(); - } - - public synchronized TypeDataBase getTypeDataBase() { - return db; - } - - /** Indicates whether the target process is suspended - completely. Equivalent to getProcessControl().isSuspended(). */ - public synchronized boolean isSuspended() throws DebuggerException { - return getProcessControl().isSuspended(); - } - - /** Suspends the target process completely. Equivalent to - getProcessControl().suspend(). */ - public synchronized void suspend() throws DebuggerException { - getProcessControl().suspend(); - } - - /** Resumes the target process completely. Equivalent to - getProcessControl().suspend(). */ - public synchronized void resume() throws DebuggerException { - getProcessControl().resume(); - } - - /** Indicates whether we are attached to a Java HotSpot virtual - machine */ - public synchronized boolean isJavaMode() { - return javaMode; - } - - /** Temporarily disables interaction with the target process via - JVMDI. This is done while the target process is stopped at a C - breakpoint. Can be called even if the JVMDI agent has not been - initialized. */ - public synchronized void disableJavaInteraction() { - javaInteractionDisabled = true; - } - - /** Re-enables interaction with the target process via JVMDI. This - is done while the target process is continued past a C - braekpoint. Can be called even if the JVMDI agent has not been - initialized. */ - public synchronized void enableJavaInteraction() { - javaInteractionDisabled = false; - } - - /** Indicates whether Java interaction has been disabled */ - public synchronized boolean isJavaInteractionDisabled() { - return javaInteractionDisabled; - } - - /** Indicates whether we can talk to the Serviceability Agent's - JVMDI module to be able to set breakpoints */ - public synchronized boolean canInteractWithJava() { - return (jvmdi != null) && !javaInteractionDisabled; - } - - /** Suspends all Java threads in the target process. Can only be - called if we are attached to a HotSpot JVM and can connect to - the SA's JVMDI module. Must not be called when the target - process has been suspended with suspend(). */ - public synchronized void suspendJava() throws DebuggerException { - if (!canInteractWithJava()) { - throw new DebuggerException("Could not connect to SA's JVMDI module"); - } - if (jvmdi.isSuspended()) { - throw new DebuggerException("Target process already suspended via JVMDI"); - } - jvmdi.suspend(); - } - - /** Resumes all Java threads in the target process. Can only be - called if we are attached to a HotSpot JVM and can connect to - the SA's JVMDI module. Must not be called when the target - process has been suspended with suspend(). */ - public synchronized void resumeJava() throws DebuggerException { - if (!canInteractWithJava()) { - throw new DebuggerException("Could not connect to SA's JVMDI module"); - } - if (!jvmdi.isSuspended()) { - throw new DebuggerException("Target process already resumed via JVMDI"); - } - jvmdi.resume(); - } - - /** Indicates whether the target process has been suspended at the - Java language level via the SA's JVMDI module */ - public synchronized boolean isJavaSuspended() throws DebuggerException { - return jvmdi.isSuspended(); - } - - /** Toggle a Java breakpoint at the given location. */ - public synchronized ServiceabilityAgentJVMDIModule.BreakpointToggleResult - toggleJavaBreakpoint(String srcFileName, - String pkgName, - int lineNo) { - if (!canInteractWithJava()) { - throw new DebuggerException("Could not connect to SA's JVMDI module; can not toggle Java breakpoints"); - } - return jvmdi.toggleBreakpoint(srcFileName, pkgName, lineNo); - } - - /** Access to JVMDI module's eventPending */ - public synchronized boolean javaEventPending() throws DebuggerException { - if (!canInteractWithJava()) { - throw new DebuggerException("Could not connect to SA's JVMDI module; can not poll for Java debug events"); - } - return jvmdi.eventPending(); - } - - /** Access to JVMDI module's eventPoll */ - public synchronized Event javaEventPoll() throws DebuggerException { - if (!canInteractWithJava()) { - throw new DebuggerException("Could not connect to SA's JVMDI module; can not poll for Java debug events"); - } - return jvmdi.eventPoll(); - } - - /** Access to JVMDI module's eventContinue */ - public synchronized void javaEventContinue() throws DebuggerException { - if (!canInteractWithJava()) { - throw new DebuggerException("Could not connect to SA's JVMDI module; can not continue past Java debug events"); - } - jvmdi.eventContinue(); - } - - - // FIXME: add other accessors. For example, suspension and - // resumption should be done through this interface, as well as - // interaction with the live Java process such as breakpoint setting. - // Probably should not expose the ServiceabilityAgentJVMDIModule - // from this interface. - - //-------------------------------------------------------------------------------- - // Client-side operations - // - - /** This attaches to a process running on the local machine. */ - public synchronized void attach(int processID) - throws DebuggerException { - if (debugger != null) { - throw new DebuggerException("Already attached"); - } - pid = processID; - startupMode = PROCESS_MODE; - isServer = false; - go(); - } - - /** This opens a core file on the local machine */ - public synchronized void attach(String executableName, String coreFileName) - throws DebuggerException { - if (debugger != null) { - throw new DebuggerException("Already attached"); - } - if ((executableName == null) || (coreFileName == null)) { - throw new DebuggerException("Both the core file name and executable name must be specified"); - } - this.executableName = executableName; - this.coreFileName = coreFileName; - startupMode = CORE_FILE_MODE; - isServer = false; - go(); - } - - /** This attaches to a "debug server" on a remote machine; this - remote server has already attached to a process or opened a - core file and is waiting for RMI calls on the Debugger object to - come in. */ - public synchronized void attach(String remoteServerID) - throws DebuggerException { - if (debugger != null) { - throw new DebuggerException("Already attached to a process"); - } - if (remoteServerID == null) { - throw new DebuggerException("Debug server id must be specified"); - } - - debugServerID = remoteServerID; - startupMode = REMOTE_MODE; - isServer = false; - go(); - } - - /** This should only be called by the user on the client machine, - not the server machine */ - public synchronized boolean detach() throws DebuggerException { - if (isServer) { - throw new DebuggerException("Should not call detach() for server configuration"); - } - return detachInternal(); - } - - //-------------------------------------------------------------------------------- - // Server-side operations - // - - /** This attaches to a process running on the local machine and - starts a debug server, allowing remote machines to connect and - examine this process. uniqueID is used to uniquely identify the - debuggee */ - public synchronized void startServer(int processID, String uniqueID) - throws DebuggerException { - if (debugger != null) { - throw new DebuggerException("Already attached"); - } - pid = processID; - startupMode = PROCESS_MODE; - isServer = true; - serverID = uniqueID; - go(); - } - - /** This attaches to a process running on the local machine and - starts a debug server, allowing remote machines to connect and - examine this process. */ - public synchronized void startServer(int processID) - throws DebuggerException { - startServer(processID, null); - } - - /** This opens a core file on the local machine and starts a debug - server, allowing remote machines to connect and examine this - core file. uniqueID is used to uniquely identify the - debuggee */ - public synchronized void startServer(String executableName, String coreFileName, - String uniqueID) - throws DebuggerException { - if (debugger != null) { - throw new DebuggerException("Already attached"); - } - if ((executableName == null) || (coreFileName == null)) { - throw new DebuggerException("Both the core file name and Java executable name must be specified"); - } - this.executableName = executableName; - this.coreFileName = coreFileName; - startupMode = CORE_FILE_MODE; - isServer = true; - serverID = uniqueID; - go(); - } - - /** This opens a core file on the local machine and starts a debug - server, allowing remote machines to connect and examine this - core file.*/ - public synchronized void startServer(String executableName, String coreFileName) - throws DebuggerException { - startServer(executableName, coreFileName, null); - } - - /** This may only be called on the server side after startServer() - has been called */ - public synchronized boolean shutdownServer() throws DebuggerException { - if (!isServer) { - throw new DebuggerException("Should not call shutdownServer() for client configuration"); - } - return detachInternal(); - } - - - //-------------------------------------------------------------------------------- - // Internals only below this point - // - - private boolean detachInternal() { - if (debugger == null) { - return false; - } - if (canInteractWithJava()) { - jvmdi.detach(); - jvmdi = null; - } - boolean retval = true; - if (!isServer) { - VM.shutdown(); - } - // We must not call detach() if we are a client and are connected - // to a remote debugger - Debugger dbg = null; - DebuggerException ex = null; - if (isServer) { - try { - RMIHelper.unbind(serverID); - } - catch (DebuggerException de) { - ex = de; - } - dbg = debugger; - } else { - if (startupMode != REMOTE_MODE) { - dbg = debugger; - } - } - if (dbg != null) { - retval = dbg.detach(); - } - - debugger = null; - machDesc = null; - db = null; - if (ex != null) { - throw(ex); - } - return retval; - } - - private void go() { - setupDebugger(); - javaMode = setupVM(); - } - - private void setupDebugger() { - if (startupMode != REMOTE_MODE) { - // - // Local mode (client attaching to local process or setting up - // server, but not client attaching to server) - // - - try { - os = PlatformInfo.getOS(); - cpu = PlatformInfo.getCPU(); - } - catch (UnsupportedPlatformException e) { - throw new DebuggerException(e); - } - fileSep = System.getProperty("file.separator"); - - if (os.equals("solaris")) { - setupDebuggerSolaris(); - } else if (os.equals("win32")) { - setupDebuggerWin32(); - } else if (os.equals("linux")) { - setupDebuggerLinux(); - } else if (os.equals("bsd")) { - setupDebuggerBsd(); - } else { - // Add support for more operating systems here - throw new DebuggerException("Operating system " + os + " not yet supported"); - } - if (isServer) { - RemoteDebuggerServer remote = null; - try { - remote = new RemoteDebuggerServer(debugger); - } - catch (RemoteException rem) { - throw new DebuggerException(rem); - } - RMIHelper.rebind(serverID, remote); - } - } else { - // - // Remote mode (client attaching to server) - // - - // Create and install a security manager - - // FIXME: currently commented out because we were having - // security problems since we're "in the sun.* hierarchy" here. - // Perhaps a permissive policy file would work around this. In - // the long run, will probably have to move into com.sun.*. - - // if (System.getSecurityManager() == null) { - // System.setSecurityManager(new RMISecurityManager()); - // } - - connectRemoteDebugger(); - } - } - - private boolean setupVM() { - // We need to instantiate a HotSpotTypeDataBase on both the client - // and server machine. On the server it is only currently used to - // configure the Java primitive type sizes (which we should - // consider making constant). On the client it is used to - // configure the VM. - - try { - if (os.equals("solaris")) { - db = new HotSpotTypeDataBase(machDesc, new HotSpotSolarisVtblAccess(debugger, jvmLibNames), - debugger, jvmLibNames); - } else if (os.equals("win32")) { - db = new HotSpotTypeDataBase(machDesc, new Win32VtblAccess(debugger, jvmLibNames), - debugger, jvmLibNames); - } else if (os.equals("linux")) { - db = new HotSpotTypeDataBase(machDesc, new LinuxVtblAccess(debugger, jvmLibNames), - debugger, jvmLibNames); - } else if (os.equals("bsd")) { - db = new HotSpotTypeDataBase(machDesc, new BsdVtblAccess(debugger, jvmLibNames), - debugger, jvmLibNames); - } else { - throw new DebuggerException("OS \"" + os + "\" not yet supported (no VtblAccess implemented yet)"); - } - } - catch (NoSuchSymbolException e) { - e.printStackTrace(); - return false; - } - - if (startupMode != REMOTE_MODE) { - // Configure the debugger with the primitive type sizes just obtained from the VM - debugger.configureJavaPrimitiveTypeSizes(db.getJBooleanType().getSize(), - db.getJByteType().getSize(), - db.getJCharType().getSize(), - db.getJDoubleType().getSize(), - db.getJFloatType().getSize(), - db.getJIntType().getSize(), - db.getJLongType().getSize(), - db.getJShortType().getSize()); - } - - if (!isServer) { - // Do not initialize the VM on the server (unnecessary, since it's - // instantiated on the client) - VM.initialize(db, debugger); - } - - try { - jvmdi = new ServiceabilityAgentJVMDIModule(debugger, saLibNames); - if (jvmdi.canAttach()) { - jvmdi.attach(); - jvmdi.setCommandTimeout(6000); - debugPrintln("Attached to Serviceability Agent's JVMDI module."); - // Jog VM to suspended point with JVMDI module - resume(); - suspendJava(); - suspend(); - debugPrintln("Suspended all Java threads."); - } else { - debugPrintln("Could not locate SA's JVMDI module; skipping attachment"); - jvmdi = null; - } - } catch (Exception e) { - e.printStackTrace(); - jvmdi = null; - } - - return true; - } - - //-------------------------------------------------------------------------------- - // OS-specific debugger setup/connect routines - // - - // - // Solaris - // - - private void setupDebuggerSolaris() { - setupJVMLibNamesSolaris(); - ProcDebuggerLocal dbg = new ProcDebuggerLocal(null, true); - debugger = dbg; - attachDebugger(); - - // Set up CPU-dependent stuff - if (cpu.equals("x86")) { - machDesc = new MachineDescriptionIntelX86(); - } else if (cpu.equals("sparc")) { - int addressSize = dbg.getRemoteProcessAddressSize(); - if (addressSize == -1) { - throw new DebuggerException("Error occurred while trying to determine the remote process's address size"); - } - - if (addressSize == 32) { - machDesc = new MachineDescriptionSPARC32Bit(); - } else if (addressSize == 64) { - machDesc = new MachineDescriptionSPARC64Bit(); - } else { - throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC"); - } - } else if (cpu.equals("amd64")) { - machDesc = new MachineDescriptionAMD64(); - } else { - throw new DebuggerException("Solaris only supported on sparc/sparcv9/x86/amd64"); - } - - dbg.setMachineDescription(machDesc); - } - - private void connectRemoteDebugger() throws DebuggerException { - RemoteDebugger remote = - (RemoteDebugger) RMIHelper.lookup(debugServerID); - debugger = new RemoteDebuggerClient(remote); - machDesc = ((RemoteDebuggerClient) debugger).getMachineDescription(); - os = debugger.getOS(); - if (os.equals("solaris")) { - setupJVMLibNamesSolaris(); - } else if (os.equals("win32")) { - setupJVMLibNamesWin32(); - } else if (os.equals("linux")) { - setupJVMLibNamesLinux(); - } else if (os.equals("bsd")) { - setupJVMLibNamesBsd(); - } else { - throw new RuntimeException("Unknown OS type"); - } - - cpu = debugger.getCPU(); - } - - private void setupJVMLibNamesSolaris() { - jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so", "gamma_g" }; - saLibNames = new String[] { "libsa.so", "libsa_g.so" }; - } - - // - // Win32 - // - - private void setupDebuggerWin32() { - setupJVMLibNamesWin32(); - - if (cpu.equals("x86")) { - machDesc = new MachineDescriptionIntelX86(); - } else if (cpu.equals("amd64")) { - machDesc = new MachineDescriptionAMD64(); - } else if (cpu.equals("ia64")) { - machDesc = new MachineDescriptionIA64(); - } else { - throw new DebuggerException("Win32 supported under x86, amd64 and ia64 only"); - } - - // Note we do not use a cache for the local debugger in server - // mode; it will be taken care of on the client side (once remote - // debugging is implemented). - - debugger = new WindbgDebuggerLocal(machDesc, !isServer); - - attachDebugger(); - } - - private void setupJVMLibNamesWin32() { - jvmLibNames = new String[] { "jvm.dll", "jvm_g.dll" }; - saLibNames = new String[] { "sa.dll", "sa_g.dll" }; - } - - // - // Linux - // - - private void setupDebuggerLinux() { - setupJVMLibNamesLinux(); - - if (cpu.equals("x86")) { - machDesc = new MachineDescriptionIntelX86(); - } else if (cpu.equals("ia64")) { - machDesc = new MachineDescriptionIA64(); - } else if (cpu.equals("amd64")) { - machDesc = new MachineDescriptionAMD64(); - } else if (cpu.equals("sparc")) { - if (LinuxDebuggerLocal.getAddressSize()==8) { - machDesc = new MachineDescriptionSPARC64Bit(); - } else { - machDesc = new MachineDescriptionSPARC32Bit(); - } - } else { - try { - machDesc = (MachineDescription) - Class.forName("sun.jvm.hotspot.debugger.MachineDescription" + - cpu.toUpperCase()).newInstance(); - } catch (Exception e) { - throw new DebuggerException("unsupported machine type"); - } - } - - - // Note we do not use a cache for the local debugger in server - // mode; it will be taken care of on the client side (once remote - // debugging is implemented). - - debugger = new LinuxDebuggerLocal(machDesc, !isServer); - attachDebugger(); - } - - private void setupJVMLibNamesLinux() { - // same as solaris - setupJVMLibNamesSolaris(); - } - - // - // BSD - // - - private void setupDebuggerBsd() { - setupJVMLibNamesBsd(); - - if (cpu.equals("x86")) { - machDesc = new MachineDescriptionIntelX86(); - } else if (cpu.equals("amd64") || (cpu.equals("x86_64"))) { - machDesc = new MachineDescriptionAMD64(); - } else { - throw new DebuggerException("Bsd only supported on x86/x86_64. Current arch: " + cpu); - } - - // Note we do not use a cache for the local debugger in server - // mode; it will be taken care of on the client side (once remote - // debugging is implemented). - - debugger = new BsdDebuggerLocal(machDesc, !isServer); - attachDebugger(); - } - - private void setupJVMLibNamesBsd() { - // same as solaris - setupJVMLibNamesSolaris(); - } - - /** Convenience routine which should be called by per-platform - debugger setup. Should not be called when startupMode is - REMOTE_MODE. */ - private void attachDebugger() { - if (startupMode == PROCESS_MODE) { - debugger.attach(pid); - } else if (startupMode == CORE_FILE_MODE) { - debugger.attach(executableName, coreFileName); - } else { - throw new DebuggerException("Should not call attach() for startupMode == " + startupMode); - } - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/JavaLineNumberInfo.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/JavaLineNumberInfo.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.bugspot; - -import sun.jvm.hotspot.oops.*; - -/** Wrapper class which describes line number information for Java - class files. The line number table is converted into this - representation on demand. These objects are then sorted by line - number for fast lookup when setting breakpoints in a particular - source file. */ - -public class JavaLineNumberInfo { - private InstanceKlass klass; - private Method method; - private int startBCI; - private int lineNumber; - - public JavaLineNumberInfo(InstanceKlass klass, - Method method, - int startBCI, - int lineNumber) { - this.klass = klass; - this.method = method; - this.startBCI = startBCI; - this.lineNumber = lineNumber; - } - - public InstanceKlass getKlass() { return klass; } - public Method getMethod() { return method; } - public int getStartBCI() { return startBCI; } - public int getLineNumber() { return lineNumber; } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/Main.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/Main.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2001, 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. - * - */ - -package sun.jvm.hotspot.bugspot; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; - -import sun.jvm.hotspot.ui.*; - -/** The main class for the BugSpot debugger. */ - -public class Main { - public static void main(String[] args) { - JFrame frame = new JFrame("BugSpot"); - frame.setSize(800, 600); - BugSpot db = new BugSpot(); - db.setMDIMode(true); - db.build(); - frame.setJMenuBar(db.getMenuBar()); - frame.getContentPane().add(db); - frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - - GraphicsUtilities.reshapeToAspectRatio(frame, - 4.0f/3.0f, 0.85f, Toolkit.getDefaultToolkit().getScreenSize()); - GraphicsUtilities.centerInContainer(frame, - Toolkit.getDefaultToolkit().getScreenSize()); - frame.setVisible(true); - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/PCFinder.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/PCFinder.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.bugspot; - -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.debugger.cdbg.*; - -/** Helper class for locating a program counter. Indicates the - confidence of the find. */ - -public class PCFinder { - public static final int LOW_CONFIDENCE = 1; - public static final int HIGH_CONFIDENCE = 2; - - public static class Info { - private String name; - private long offset; - private int confidence; - - public Info(String name, long offset, int confidence) { - this.name = name; - this.offset = offset; - this.confidence = confidence; - } - - /** May be null */ - public String getName() { return name; } - - /** If this is -1, a symbol could not be found, and the offset - should not be shown */ - public long getOffset() { return offset; } - - /** PCFinder.LOW_CONFIDENCE or PCFinder.HIGH_CONFIDENCE */ - public int getConfidence() { return confidence; } - } - - /** Passed loadobject may be null in which case the returned Info - object has low confidence */ - public static Info findPC(Address pc, LoadObject lo, CDebugger dbg) { - if (lo == null) { - return new Info(null, -1, LOW_CONFIDENCE); - } - - // First try debug info - BlockSym sym = lo.debugInfoForPC(pc); - while (sym != null) { - if (sym.isFunction()) { - // Highest confidence - return new Info(sym.toString(), pc.minus(sym.getAddress()), HIGH_CONFIDENCE); - } - } - - // Now try looking up symbol in loadobject - - // FIXME: must add support for mapfiles on Win32 and try looking - // up there first if possible. Should we hide that behind - // LoadObject.closestSymbolToPC and have the ClosestSymbol return - // confidence? I think so. On Solaris there is no notion of a - // mapfile, and the confidence for closestSymbolToPC will be high - // instead of low. - - int confidence = HIGH_CONFIDENCE; - - ClosestSymbol cs = lo.closestSymbolToPC(pc); - if (cs != null) { - // FIXME: currently low confidence (only on Win32) - return new Info(cs.getName() + "()", cs.getOffset(), LOW_CONFIDENCE); - } - - // Unknown location - return new Info(dbg.getNameOfFile(lo.getName()).toUpperCase() + - "! " + pc + "()", -1, HIGH_CONFIDENCE); - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/PackageScanner.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/PackageScanner.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.bugspot; - -import java.io.*; - -/** Scans a .java file for the package that it is in. */ - -public class PackageScanner { - - public PackageScanner() { - } - - public String scan(String filename) { - return scan(new File(filename)); - } - - /** Returns the String comprising the package name of the classes in - this .java file. Returns the (non-null) empty string if any - error occurs or if the classes are in the unnamed package. */ - public String scan(File file) { - BufferedReader buf = null; - String res = ""; - try { - buf = new BufferedReader(new FileReader(file)); - StreamTokenizer tok = new StreamTokenizer(buf); - tok.slashStarComments(true); - tok.slashSlashComments(true); - if (tok.nextToken() != StreamTokenizer.TT_WORD) { - return res; - } - if (!tok.sval.equals("package")) { - return res; - } - if (tok.nextToken() != StreamTokenizer.TT_WORD) { - return res; - } - res = tok.sval; - return res; - } catch (FileNotFoundException e) { - return res; - } catch (IOException e) { - return res; - } finally { - try { - if (buf != null) { - buf.close(); - } - } catch (IOException e) { - } - } - } - - public static void main(String[] args) { - if (args.length != 1) { - usage(); - } - - System.out.println(new PackageScanner().scan(args[0])); - } - - private static void usage() { - System.err.println("Usage: java PackageScanner <.java file name>"); - System.err.println("Prints package the .java file is in to stdout."); - System.exit(1); - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/RegisterPanel.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/RegisterPanel.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.bugspot; - -import java.awt.*; -import java.util.*; -import javax.swing.*; -import javax.swing.table.*; - -import sun.jvm.hotspot.debugger.*; - -/** Displays registers in a window. FIXME: this will need more work to - understand and handle register windows. */ - -public class RegisterPanel extends JPanel { - private java.util.List/**/ registers; - private AbstractTableModel dataModel; - private boolean valid; - private boolean editable; - private String nullAddressString; - private ThreadProxy curThread; - private JTable table; - - static class RegisterInfo { - private String name; - private Address value; - - RegisterInfo(String name, Address value) { - this.name = name; - this.value = value; - } - - String getName() { return name; } - Address getValue() { return value; } - } - - public RegisterPanel() { - super(); - - registers = new ArrayList(); - - dataModel = new AbstractTableModel() { - public int getColumnCount() { return 2; } - public int getRowCount() { return registers.size(); } - public String getColumnName(int col) { - switch (col) { - case 0: - return "Register Name"; - case 1: - return "Register Value"; - default: - throw new RuntimeException("Index " + col + " out of bounds"); - } - } - public Object getValueAt(int row, int col) { - RegisterInfo info = (RegisterInfo) registers.get(row); - - switch (col) { - case 0: - return info.getName(); - case 1: - if (valid) { - Address val = info.getValue(); - if (val != null) { - return val; - } else { - return nullAddressString; - } - } else { - return "-"; - } - default: - throw new RuntimeException("Index (" + col + ", " + row + ") out of bounds"); - } - } - public boolean isCellEditable(int row, int col) { - if (col == 0) return false; - if (!valid) return false; - if (curThread == null) return false; - if (!curThread.canSetContext()) return false; - - // FIXME: add listener to watch for register changes - // return true; - return false; - } - }; - - // Build user interface - setLayout(new BorderLayout()); - table = new JTable(dataModel); - table.setCellSelectionEnabled(true); - table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); - table.setDragEnabled(true); - JTableHeader header = table.getTableHeader(); - header.setReorderingAllowed(false); - JScrollPane scrollPane = new JScrollPane(table); - add(scrollPane, BorderLayout.CENTER); - } - - - /** Updates the register panel with the register set from the - specified thread. Call this when the process has been suspended - and the current thread has been set. FIXME: this interface will - need to change to support register windows. */ - public void update(ThreadProxy curThread) { - this.curThread = curThread; - ThreadContext context = curThread.getContext(); - editable = curThread.canSetContext(); - registers.clear(); - for (int i = 0; i < context.getNumRegisters(); i++) { - String name = context.getRegisterName(i); - Address addr = context.getRegisterAsAddress(i); - if ((nullAddressString == null) && (addr != null)) { - String addrStr = addr.toString(); - StringBuffer buf = new StringBuffer(); - buf.append("0x"); - int len = addrStr.length() - 2; - for (int j = 0; j < len; j++) { - buf.append("0"); - } - nullAddressString = buf.toString(); - } - registers.add(new RegisterInfo(name, addr)); - } - valid = true; - SwingUtilities.invokeLater(new Runnable() { - public void run() { - dataModel.fireTableDataChanged(); - } - }); - } - - /** Clears the registers' values. Call this when the processs has - been resumed. */ - public void clear() { - valid = false; - nullAddressString = null; - SwingUtilities.invokeLater(new Runnable() { - public void run() { - dataModel.fireTableDataChanged(); - } - }); - } - - public void setFont(Font font) { - super.setFont(font); - if (table != null) { - table.setFont(font); - } - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/StackTraceEntry.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/StackTraceEntry.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2001, 2002, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.bugspot; - -import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.runtime.*; - -/** This class describes a frame in a stack trace. It abstracts over - C/C++ and Java frames. */ - -public class StackTraceEntry { - private CFrame cFrame; - private CDebugger dbg; - private JavaVFrame javaFrame; - private String value; // What is displayed in a stack trace - // For merging C and Java stack traces. - // For more precise stack traces, should probably have a way to - // convert a CFrame to a sun.jvm.hotspot.runtime.Frame. For now, - // doing similar algorithm to jdbx (which does not have intimate - // knowledge of the VM). - private boolean isUnknownCFrame; - - public StackTraceEntry(CFrame cFrame, CDebugger dbg) { - this.cFrame = cFrame; - this.dbg = dbg; - computeValue(); - } - - public StackTraceEntry(JavaVFrame javaFrame) { - this.javaFrame = javaFrame; - computeValue(); - } - - public boolean isCFrame() { return (cFrame != null); } - public boolean isJavaFrame() { return (javaFrame != null); } - public CFrame getCFrame() { return cFrame; } - public JavaVFrame getJavaFrame() { return javaFrame; } - public boolean isUnknownCFrame() { return isUnknownCFrame; } - public String toString() { - return value; - } - - private void computeValue() { - isUnknownCFrame = true; - value = ""; - if (cFrame != null) { - PCFinder.Info info = PCFinder.findPC(cFrame.pc(), cFrame.loadObjectForPC(), dbg); - if (info.getName() != null) { - value = "(C) " + info.getName(); - isUnknownCFrame = false; - if (info.getConfidence() == PCFinder.LOW_CONFIDENCE) { - value = value + " (?)"; - } - if (info.getOffset() >= 0) { - value = value + " + 0x" + Long.toHexString(info.getOffset()); - } - } - } else if (javaFrame != null) { - isUnknownCFrame = false; - Method m = javaFrame.getMethod(); - value = "(J) " + m.externalNameAndSignature(); - } - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/StackTracePanel.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/StackTracePanel.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.bugspot; - -import java.awt.*; -import java.awt.event.*; -import java.util.*; -import javax.swing.*; -import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.ui.*; - -/** This panel contains a ListBox with all of the stack frames in a - given thread. When a given entry is selected, an event is - fired. */ - -public class StackTracePanel extends JPanel { - public interface Listener { - public void frameChanged(CFrame fr, JavaVFrame jfr); - } - - class Model extends AbstractListModel implements ComboBoxModel { - private Object selectedItem; - public Object getElementAt(int index) { - if (trace == null) return null; - return trace.get(index); - } - public int getSize() { - if (trace == null) return 0; - return trace.size(); - } - public Object getSelectedItem() { - return selectedItem; - } - public void setSelectedItem(Object item) { - selectedItem = item; - } - public void dataChanged() { - fireContentsChanged(this, 0, trace.size()); - } - } - - private java.util.List trace; - private Model model; - private JComboBox list; - private java.util.List listeners; - - public StackTracePanel() { - super(); - - model = new Model(); - - // Build user interface - setLayout(new BorderLayout()); - setBorder(GraphicsUtilities.newBorder(5)); - list = new JComboBox(model); - list.setPrototypeDisplayValue("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"); - add(list, BorderLayout.CENTER); - - // Add selection listener - list.addItemListener(new ItemListener() { - public void itemStateChanged(ItemEvent e) { - if (e.getStateChange() == ItemEvent.SELECTED) { - fireFrameChanged(); - } - } - }); - } - - /** Takes a List of StackTraceEntry objects */ - public void setTrace(java.util.List trace) { - this.trace = trace; - model.dataChanged(); - list.setSelectedIndex(0); - fireFrameChanged(); - } - - public void addListener(Listener listener) { - if (listeners == null) { - listeners = new ArrayList(); - } - listeners.add(listener); - } - - protected void fireFrameChanged() { - if (listeners != null) { - StackTraceEntry entry = (StackTraceEntry) trace.get(list.getSelectedIndex()); - for (Iterator iter = listeners.iterator(); iter.hasNext(); ) { - ((Listener) iter.next()).frameChanged(entry.getCFrame(), entry.getJavaFrame()); - } - } - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/ThreadListPanel.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/ThreadListPanel.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,237 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.bugspot; - -import java.awt.*; -import java.awt.event.*; -import java.util.*; -import javax.swing.*; -import javax.swing.table.*; - -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.ui.*; - -// NOTE: this class was not placed in sun.jvm.hotspot.ui to prevent -// mixing components designed for C and C++ debugging with the ones -// that work with the core serviceability agent functionality (which -// does not require that the CDebugger interface be implemented). - -/** The ThreadListPanel is used for C and C++ debugging and can - visualize all threads in the target process. The caller passes in - a CDebugger attached to the target process and can request that - JavaThreads' associations with these underlying threads be - displayed; this option is only valid when attached to a HotSpot - JVM and when the {@link sun.jvm.hotspot.runtime.VM} has been - initialized. */ - -public class ThreadListPanel extends JPanel { - /** Listener which can be added to receive "Set Focus" events */ - public static interface Listener { - /** ThreadProxy will always be provided; JavaThread will only be - present if displayJavaThreads was specified in the constructor - for the panel and the thread was a JavaThread. */ - public void setFocus(ThreadProxy thread, JavaThread jthread); - } - - static class ThreadInfo { - private ThreadProxy thread; - // Distinguish between PC == null and no top frame - private boolean gotPC; - private Address pc; - private String location; - private JavaThread javaThread; - private String javaThreadName; - - public ThreadInfo(ThreadProxy thread, CDebugger dbg, JavaThread jthread) { - this.thread = thread; - this.location = ""; - CFrame fr = dbg.topFrameForThread(thread); - if (fr != null) { - gotPC = true; - pc = fr.pc(); - PCFinder.Info info = PCFinder.findPC(pc, fr.loadObjectForPC(), dbg); - if (info.getName() != null) { - location = info.getName(); - if (info.getConfidence() == PCFinder.LOW_CONFIDENCE) { - location = location + " (?)"; - } - if (info.getOffset() < 0) { - location = location + " + 0x" + Long.toHexString(info.getOffset()); - } - } - } - if (jthread != null) { - javaThread = jthread; - javaThreadName = jthread.getThreadName(); - } - } - - public ThreadProxy getThread() { return thread; } - public boolean hasPC() { return gotPC; } - public Address getPC() { return pc; } - public String getLocation() { return location; } - public boolean isJavaThread() { return (javaThread != null); } - public JavaThread getJavaThread() { return javaThread; } - public String getJavaThreadName() { return javaThreadName; } - } - - // List - private java.util.List threadList; - private JTable table; - private AbstractTableModel dataModel; - // List - private java.util.List listeners; - - /** Takes a CDebugger from which the thread list is queried. - displayJavaThreads must only be set to true if the debugger is - attached to a HotSpot JVM and if the VM has already been - initialized. */ - public ThreadListPanel(CDebugger dbg, final boolean displayJavaThreads) { - super(); - - Map threadToJavaThreadMap = null; - if (displayJavaThreads) { - // Collect Java threads from virtual machine and insert them in - // table for later querying - threadToJavaThreadMap = new HashMap(); - Threads threads = VM.getVM().getThreads(); - for (JavaThread thr = threads.first(); thr != null; thr = thr.next()) { - threadToJavaThreadMap.put(thr.getThreadProxy(), thr); - } - } - - java.util.List/**/ threads = dbg.getThreadList(); - threadList = new ArrayList(threads.size()); - for (Iterator iter = threads.iterator(); iter.hasNext(); ) { - ThreadProxy thr = (ThreadProxy) iter.next(); - JavaThread jthr = null; - if (displayJavaThreads) { - jthr = (JavaThread) threadToJavaThreadMap.get(thr); - } - threadList.add(new ThreadInfo(thr, dbg, jthr)); - } - - // Thread ID, current PC, current symbol, Java Thread, [Java thread name] - dataModel = new AbstractTableModel() { - public int getColumnCount() { return (displayJavaThreads ? 5 : 3); } - public int getRowCount() { return threadList.size(); } - public String getColumnName(int col) { - switch (col) { - case 0: - return "Thread ID"; - case 1: - return "PC"; - case 2: - return "Location"; - case 3: - return "Java?"; - case 4: - return "Java Thread Name"; - default: - throw new RuntimeException("Index " + col + " out of bounds"); - } - } - public Object getValueAt(int row, int col) { - ThreadInfo info = (ThreadInfo) threadList.get(row); - - switch (col) { - case 0: - return info.getThread(); - case 1: - { - if (info.hasPC()) { - return info.getPC(); - } - return ""; - } - case 2: - return info.getLocation(); - case 3: - if (info.isJavaThread()) { - return "Yes"; - } else { - return ""; - } - case 4: - if (info.isJavaThread()) { - return info.getJavaThreadName(); - } else { - return ""; - } - default: - throw new RuntimeException("Index (" + col + ", " + row + ") out of bounds"); - } - } - }; - - // Build user interface - setLayout(new BorderLayout()); - table = new JTable(dataModel); - table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - JTableHeader header = table.getTableHeader(); - header.setReorderingAllowed(false); - table.setRowSelectionAllowed(true); - table.setColumnSelectionAllowed(false); - JScrollPane scrollPane = new JScrollPane(table); - add(scrollPane, BorderLayout.CENTER); - if (threadList.size() > 0) { - table.setRowSelectionInterval(0, 0); - } - - JButton button = new JButton("Set Focus"); - button.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - int i = table.getSelectedRow(); - if (i < 0) { - return; - } - ThreadInfo info = (ThreadInfo) threadList.get(i); - for (Iterator iter = listeners.iterator(); iter.hasNext(); ) { - ((Listener) iter.next()).setFocus(info.getThread(), info.getJavaThread()); - } - } - }); - JPanel focusPanel = new JPanel(); - focusPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0)); - focusPanel.setLayout(new BoxLayout(focusPanel, BoxLayout.Y_AXIS)); - focusPanel.add(Box.createGlue()); - focusPanel.add(button); - focusPanel.add(Box.createGlue()); - add(focusPanel, BorderLayout.EAST); - - // FIXME: make listener model for the debugger so if the user - // specifies a mapfile for or path to a given DSO later we can - // update our state - } - - public void addListener(Listener l) { - if (listeners == null) { - listeners = new ArrayList(); - } - listeners.add(l); - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/VariablePanel.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/VariablePanel.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2001, 2002, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.bugspot; - -import java.awt.*; -import javax.swing.*; -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.bugspot.tree.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.ui.tree.*; -import sun.jvm.hotspot.ui.treetable.*; - -/** Manages display of a set of local variables in a frame, or the - contents of the "this" pointer */ - -public class VariablePanel extends JPanel { - private JTreeTable treeTable; - private SimpleTreeTableModel model; - private SimpleTreeGroupNode root; - - public VariablePanel() { - super(); - - model = new SimpleTreeTableModel(); - model.setValuesEditable(false); - root = new SimpleTreeGroupNode(); - model.setRoot(root); - treeTable = new JTreeTable(model); - treeTable.setRootVisible(false); - treeTable.setShowsRootHandles(true); - treeTable.setShowsIcons(false); - treeTable.setTreeEditable(false); - treeTable.getTableHeader().setReorderingAllowed(false); - treeTable.setCellSelectionEnabled(true); - treeTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); - treeTable.setDragEnabled(true); - JScrollPane sp = new JScrollPane(treeTable); - sp.getViewport().setBackground(Color.white); - - setLayout(new BorderLayout()); - add(sp, BorderLayout.CENTER); - } - - /** Clear the contents of this VariablePanel */ - public void clear() { - root.removeAllChildren(); - model.fireTreeStructureChanged(); - } - - /** Update the contents of this VariablePanel from the given CFrame */ - public void update(CFrame fr) { - // Collect locals - CCollector coll = new CCollector(); - fr.iterateLocals(coll); - update(coll); - } - - /** Update the contents of this VariablePanel from the given JavaVFrame */ - public void update(JavaVFrame jfr) { - Method m = jfr.getMethod(); - if (!m.hasLocalVariableTable()) { - return; - } - int bci = jfr.getBCI(); - // Get local variable table - LocalVariableTableElement[] locals = m.getLocalVariableTable(); - // Get locals as StackValueCollection - StackValueCollection coll = jfr.getLocals(); - root.removeAllChildren(); - // See which locals are live - for (int i = 0; i < locals.length; i++) { - LocalVariableTableElement local = locals[i]; - if (local.getStartBCI() <= bci && bci < local.getStartBCI() + local.getLength()) { - // Valid; add it - SimpleTreeNode node = null; - Symbol name = null; - try { - name = m.getConstants().getSymbolAt(local.getNameCPIndex()); - if (name == null) { - System.err.println("Null name at slot " + - local.getNameCPIndex() + - " for local variable at slot " + - local.getSlot()); - continue; - } - } catch (Exception e) { - System.err.println("Unable to fetch name at slot " + - local.getNameCPIndex() + - " for local variable at slot " + - local.getSlot()); - e.printStackTrace(); - continue; - } - sun.jvm.hotspot.oops.NamedFieldIdentifier f = - new sun.jvm.hotspot.oops.NamedFieldIdentifier(name.asString()); - Symbol descriptor = null; - try { - descriptor = m.getConstants().getSymbolAt(local.getDescriptorCPIndex()); - } catch (Exception e) { - System.err.println("Unable to fetch descriptor at slot " + - local.getDescriptorCPIndex() + - " for local variable " + f.getName() + - " at slot " + local.getSlot()); - e.printStackTrace(); - continue; - } - - if (descriptor != null) { - switch (descriptor.getByteAt(0)) { - case 'F': { - node = new sun.jvm.hotspot.ui.tree.FloatTreeNodeAdapter(coll.floatAt(local.getSlot()), f, true); - break; - } - case 'D': { - node = new sun.jvm.hotspot.ui.tree.DoubleTreeNodeAdapter(coll.doubleAt(local.getSlot()), f, true); - break; - } - case 'C': { - node = new sun.jvm.hotspot.ui.tree.CharTreeNodeAdapter((char) coll.intAt(local.getSlot()), f, true); - break; - } - case 'B': - case 'S': - case 'I': { - node = new sun.jvm.hotspot.ui.tree.LongTreeNodeAdapter(coll.intAt(local.getSlot()), f, true); - break; - } - case 'Z': { - node = new sun.jvm.hotspot.ui.tree.BooleanTreeNodeAdapter( - ((coll.intAt(local.getSlot()) != 0) ? true : false), f, true - ); - break; - } - case 'J': { - node = new sun.jvm.hotspot.ui.tree.LongTreeNodeAdapter(coll.longAt(local.getSlot()), f, true); - break; - } - default: { - try { - node = new sun.jvm.hotspot.ui.tree.OopTreeNodeAdapter( - VM.getVM().getObjectHeap().newOop(coll.oopHandleAt(local.getSlot())), f, true - ); - } catch (AddressException e) { - node = new sun.jvm.hotspot.ui.tree.FieldTreeNodeAdapter(f, true) { - public int getChildCount() { return 0; } - public SimpleTreeNode getChild(int i) { return null; } - public boolean isLeaf() { return false; } - public int getIndexOfChild(SimpleTreeNode child) { return 0; } - public String getValue() { - return ""; - } - }; - } - break; - } - } - if (node != null) { - root.addChild(node); - } - } - } - } - - model.fireTreeStructureChanged(); - } - - /** Update the contents of this VariablePanel from the given "this" - pointer of the given type */ - public void update(Address thisAddr, Type type) { - // Collect fields - CCollector coll = new CCollector(); - type.iterateObject(thisAddr, coll); - update(coll); - } - - private void update(CCollector coll) { - root.removeAllChildren(); - for (int i = 0; i < coll.getNumChildren(); i++) { - root.addChild(coll.getChild(i)); - } - model.fireTreeStructureChanged(); - } - - static class CCollector extends DefaultObjectVisitor { - private java.util.List children; - - public CCollector() { - children = new ArrayList(); - } - - public int getNumChildren() { - return children.size(); - } - - public SimpleTreeNode getChild(int i) { - return (SimpleTreeNode) children.get(i); - } - - public void doBit(sun.jvm.hotspot.debugger.cdbg.FieldIdentifier f, long val) { - children.add(new sun.jvm.hotspot.bugspot.tree.LongTreeNodeAdapter(val, f, true)); - } - public void doInt(sun.jvm.hotspot.debugger.cdbg.FieldIdentifier f, long val) { - children.add(new sun.jvm.hotspot.bugspot.tree.LongTreeNodeAdapter(val, f, true)); - } - public void doEnum(sun.jvm.hotspot.debugger.cdbg.FieldIdentifier f, long val, String enumName) { - children.add(new sun.jvm.hotspot.bugspot.tree.EnumTreeNodeAdapter(enumName, val, f, true)); - } - public void doFloat(sun.jvm.hotspot.debugger.cdbg.FieldIdentifier f, float val) { - children.add(new sun.jvm.hotspot.bugspot.tree.FloatTreeNodeAdapter(val, f, true)); - } - public void doDouble(sun.jvm.hotspot.debugger.cdbg.FieldIdentifier f, double val) { - children.add(new sun.jvm.hotspot.bugspot.tree.DoubleTreeNodeAdapter(val, f, true)); - } - public void doPointer(sun.jvm.hotspot.debugger.cdbg.FieldIdentifier f, Address val) { - children.add(new sun.jvm.hotspot.bugspot.tree.AddressTreeNodeAdapter(val, f, true)); - } - public void doArray(sun.jvm.hotspot.debugger.cdbg.FieldIdentifier f, Address val) { - children.add(new sun.jvm.hotspot.bugspot.tree.AddressTreeNodeAdapter(val, f, true)); - } - public void doRef(sun.jvm.hotspot.debugger.cdbg.FieldIdentifier f, Address val) { - children.add(new sun.jvm.hotspot.bugspot.tree.AddressTreeNodeAdapter(val, f, true)); - } - public void doCompound(sun.jvm.hotspot.debugger.cdbg.FieldIdentifier f, Address val) { - children.add(new sun.jvm.hotspot.bugspot.tree.ObjectTreeNodeAdapter(val, f, true)); - } - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/AddressTreeNodeAdapter.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/AddressTreeNodeAdapter.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.bugspot.tree; - -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.ui.tree.SimpleTreeNode; - -/** Encapsulates a float value in a tree handled by SimpleTreeModel */ - -public class AddressTreeNodeAdapter extends FieldTreeNodeAdapter { - private Address val; - - public AddressTreeNodeAdapter(Address val, FieldIdentifier id) { - this(val, id, false); - } - - public AddressTreeNodeAdapter(Address val, FieldIdentifier id, boolean treeTableMode) { - super(id, treeTableMode); - this.val = val; - } - - public int getChildCount() { - return 0; - } - - public SimpleTreeNode getChild(int index) { - return null; - } - - public boolean isLeaf() { - return true; - } - - public int getIndexOfChild(SimpleTreeNode child) { - return 0; - } - - public String getValue() { - if (val != null) { - return val.toString(); - } - return "NULL"; - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/DoubleTreeNodeAdapter.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/DoubleTreeNodeAdapter.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.bugspot.tree; - -import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.ui.tree.SimpleTreeNode; - -/** Encapsulates a double value in a tree handled by SimpleTreeModel */ - -public class DoubleTreeNodeAdapter extends FieldTreeNodeAdapter { - private double val; - - public DoubleTreeNodeAdapter(double val, FieldIdentifier id) { - this(val, id, false); - } - - public DoubleTreeNodeAdapter(double val, FieldIdentifier id, boolean treeTableMode) { - super(id, treeTableMode); - this.val = val; - } - - public int getChildCount() { - return 0; - } - - public SimpleTreeNode getChild(int index) { - return null; - } - - public boolean isLeaf() { - return true; - } - - public int getIndexOfChild(SimpleTreeNode child) { - return 0; - } - - public String getValue() { - return Double.toString(val); - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/EnumTreeNodeAdapter.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/EnumTreeNodeAdapter.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.bugspot.tree; - -import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.ui.tree.SimpleTreeNode; - -/** Encapsulates an enumerated value in a tree handled by SimpleTreeModel */ - -public class EnumTreeNodeAdapter extends FieldTreeNodeAdapter { - private long val; - private String enumName; - - public EnumTreeNodeAdapter(String enumName, long val, FieldIdentifier id) { - this(enumName, val, id, false); - } - - public EnumTreeNodeAdapter(String enumName, long val, FieldIdentifier id, boolean treeTableMode) { - super(id, treeTableMode); - this.enumName = enumName; - this.val = val; - } - - public int getChildCount() { - return 0; - } - - public SimpleTreeNode getChild(int index) { - return null; - } - - public boolean isLeaf() { - return true; - } - - public int getIndexOfChild(SimpleTreeNode child) { - return 0; - } - - public String getValue() { - if (enumName != null) { - return enumName; - } else { - return Long.toString(val); - } - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/FieldTreeNodeAdapter.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/FieldTreeNodeAdapter.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.bugspot.tree; - -import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.ui.tree.SimpleTreeNode; - -/** Abstract base class for all adapters for fields of C/C++ objects */ - -public abstract class FieldTreeNodeAdapter implements SimpleTreeNode { - private FieldIdentifier id; - private boolean treeTableMode; - - /** The identifier may be null, i.e., for the root of the tree */ - public FieldTreeNodeAdapter(FieldIdentifier id, boolean treeTableMode) { - this.id = id; - this.treeTableMode = treeTableMode; - } - - public FieldIdentifier getID() { - return id; - } - - /** Defaults to false in subclasses */ - public boolean getTreeTableMode() { - return treeTableMode; - } - - public Type getType() { - return getID().getType(); - } - - public String getName() { - if (getID() != null) { - return getID().toString(); - } - return ""; - } - - public String toString() { - if (treeTableMode) { - return getName(); - } else { - if (getID() != null) { - return getName() + ": " + getValue(); - } else { - return getValue(); - } - } - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/FloatTreeNodeAdapter.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/FloatTreeNodeAdapter.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.bugspot.tree; - -import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.ui.tree.SimpleTreeNode; - -/** Encapsulates a float value in a tree handled by SimpleTreeModel */ - -public class FloatTreeNodeAdapter extends FieldTreeNodeAdapter { - private float val; - - public FloatTreeNodeAdapter(float val, FieldIdentifier id) { - this(val, id, false); - } - - public FloatTreeNodeAdapter(float val, FieldIdentifier id, boolean treeTableMode) { - super(id, treeTableMode); - this.val = val; - } - - public int getChildCount() { - return 0; - } - - public SimpleTreeNode getChild(int index) { - return null; - } - - public boolean isLeaf() { - return true; - } - - public int getIndexOfChild(SimpleTreeNode child) { - return 0; - } - - public String getValue() { - return Float.toString(val); - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/LongTreeNodeAdapter.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/LongTreeNodeAdapter.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.bugspot.tree; - -import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.ui.tree.SimpleTreeNode; - -/** Encapsulates a long value in a tree handled by SimpleTreeModel */ - -public class LongTreeNodeAdapter extends FieldTreeNodeAdapter { - private long val; - - public LongTreeNodeAdapter(long val, FieldIdentifier id) { - this(val, id, false); - } - - public LongTreeNodeAdapter(long val, FieldIdentifier id, boolean treeTableMode) { - super(id, treeTableMode); - this.val = val; - } - - public int getChildCount() { - return 0; - } - - public SimpleTreeNode getChild(int index) { - return null; - } - - public boolean isLeaf() { - return true; - } - - public int getIndexOfChild(SimpleTreeNode child) { - return 0; - } - - public String getValue() { - return Long.toString(val); - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/ObjectTreeNodeAdapter.java --- a/agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/ObjectTreeNodeAdapter.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.bugspot.tree; - -import java.io.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.ui.tree.SimpleTreeNode; - -/** An adapter class which allows C/C++ objects to be displayed in a - tree via the SimpleTreeNode interface. */ - -public class ObjectTreeNodeAdapter extends FieldTreeNodeAdapter { - // Address of object - private Address addr; - - /** The address may be null (for object fields of objcets which are - null). The FieldIdentifier should not be null. treeTableMode - defaults to false. */ - public ObjectTreeNodeAdapter(Address addr, FieldIdentifier id) { - this(addr, id, false); - } - - /** The address may be null (for object fields of objcets which are - null). The FieldIdentifier should not be null. */ - public ObjectTreeNodeAdapter(Address addr, FieldIdentifier id, boolean treeTableMode) { - super(id, treeTableMode); - this.addr = addr; - } - - public int getChildCount() { - if (addr == null) { - return 0; - } - - Counter c = new Counter(); - getType().iterateObject(addr, c); - return c.getNumFields(); - } - - public SimpleTreeNode getChild(int index) { - if (addr == null) { - return null; - } - - Fetcher f = new Fetcher(index); - getType().iterateObject(addr, f); - return f.getChild(); - } - - public boolean isLeaf() { - return (addr == null); - } - - public int getIndexOfChild(SimpleTreeNode child) { - FieldIdentifier id = ((FieldTreeNodeAdapter) child).getID(); - Finder f = new Finder(id); - getType().iterateObject(addr, f); - return f.getIndex(); - } - - public String getValue() { - if (addr != null) { - return addr.toString(); - } - return "NULL"; - } - - /** Should be used only once, then have the number of fields - fetched. */ - static class Counter extends DefaultObjectVisitor { - private int numFields; - - public int getNumFields() { - return numFields; - } - - public void doBit(FieldIdentifier f, long val) { ++numFields; } - public void doInt(FieldIdentifier f, long val) { ++numFields; } - public void doEnum(FieldIdentifier f, long val, String enumName) { ++numFields; } - public void doFloat(FieldIdentifier f, float val) { ++numFields; } - public void doDouble(FieldIdentifier f, double val) { ++numFields; } - public void doPointer(FieldIdentifier f, Address val) { ++numFields; } - public void doArray(FieldIdentifier f, Address val) { ++numFields; } - public void doRef(FieldIdentifier f, Address val) { ++numFields; } - public void doCompound(FieldIdentifier f, Address addr) { ++numFields; } - } - - /** Creates a new SimpleTreeNode for the given field. */ - class Fetcher extends DefaultObjectVisitor { - private int index; - private int curField; - private SimpleTreeNode child; - - public Fetcher(int index) { - this.index = index; - } - - public SimpleTreeNode getChild() { - return child; - } - - public void doBit(FieldIdentifier f, long val) { - if (curField == index) { - child = new LongTreeNodeAdapter(val, f, getTreeTableMode()); - } - ++curField; - } - - public void doInt(FieldIdentifier f, long val) { - if (curField == index) { - child = new LongTreeNodeAdapter(val, f, getTreeTableMode()); - } - ++curField; - } - - public void doEnum(FieldIdentifier f, long val, String enumName) { - if (curField == index) { - child = new EnumTreeNodeAdapter(enumName, val, f, getTreeTableMode()); - } - ++curField; - } - - public void doFloat(FieldIdentifier f, float val) { - if (curField == index) { - child = new FloatTreeNodeAdapter(val, f, getTreeTableMode()); - } - ++curField; - } - - public void doDouble(FieldIdentifier f, double val) { - if (curField == index) { - child = new DoubleTreeNodeAdapter(val, f, getTreeTableMode()); - } - ++curField; - } - - public void doPointer(FieldIdentifier f, Address val) { - if (curField == index) { - child = new AddressTreeNodeAdapter(val, f, getTreeTableMode()); - } - ++curField; - } - - public void doArray(FieldIdentifier f, Address val) { - if (curField == index) { - child = new AddressTreeNodeAdapter(val, f, getTreeTableMode()); - } - ++curField; - } - - public void doRef(FieldIdentifier f, Address val) { - if (curField == index) { - child = new AddressTreeNodeAdapter(val, f, getTreeTableMode()); - } - ++curField; - } - - public void doCompound(FieldIdentifier f, Address val) { - if (curField == index) { - child = new ObjectTreeNodeAdapter(val, f, getTreeTableMode()); - } - ++curField; - } - } - - /** Finds the index of the given FieldIdentifier. */ - static class Finder extends DefaultObjectVisitor { - private FieldIdentifier id; - private int curField; - private int index = -1; - - public Finder(FieldIdentifier id) { - this.id = id; - } - - /** Returns -1 if not found */ - public int getIndex() { - return index; - } - - public void doBit(FieldIdentifier f, long val) { if (f.equals(id)) { index = curField; } ++curField; } - public void doInt(FieldIdentifier f, long val) { if (f.equals(id)) { index = curField; } ++curField; } - public void doEnum(FieldIdentifier f, long val, - String enumName) { if (f.equals(id)) { index = curField; } ++curField; } - public void doFloat(FieldIdentifier f, float val) { if (f.equals(id)) { index = curField; } ++curField; } - public void doDouble(FieldIdentifier f, double val) { if (f.equals(id)) { index = curField; } ++curField; } - public void doPointer(FieldIdentifier f, Address val) { if (f.equals(id)) { index = curField; } ++curField; } - public void doArray(FieldIdentifier f, Address val) { if (f.equals(id)) { index = curField; } ++curField; } - public void doRef(FieldIdentifier f, Address val) { if (f.equals(id)) { index = curField; } ++curField; } - public void doCompound(FieldIdentifier f, - Address val) { if (f.equals(id)) { index = curField; } ++curField; } - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebugger.java Thu Mar 21 14:11:13 2013 +0100 @@ -49,7 +49,7 @@ public BsdAddress readCompKlassAddress(long address) throws DebuggerException; public BsdOopHandle readOopHandle(long address) throws DebuggerException; public BsdOopHandle readCompOopHandle(long address) throws DebuggerException; - public long[] getThreadIntegerRegisterSet(int lwp_id) throws DebuggerException; + public long[] getThreadIntegerRegisterSet(long unique_thread_id) throws DebuggerException; public long getAddressValue(Address addr) throws DebuggerException; public Address newAddress(long value) throws DebuggerException; diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java Thu Mar 21 14:11:13 2013 +0100 @@ -90,7 +90,7 @@ throws DebuggerException; private native ClosestSymbol lookupByAddress0(long address) throws DebuggerException; - private native long[] getThreadIntegerRegisterSet0(int lwp_id) + private native long[] getThreadIntegerRegisterSet0(long unique_thread_id) throws DebuggerException; private native byte[] readBytesFromProcess0(long address, long numBytes) throws DebuggerException; @@ -400,10 +400,15 @@ // /** From the ThreadAccess interface via Debugger and JVMDebugger */ + public ThreadProxy getThreadForIdentifierAddress(Address threadIdAddr, Address uniqueThreadIdAddr) { + return new BsdThread(this, threadIdAddr, uniqueThreadIdAddr); + } + @Override public ThreadProxy getThreadForIdentifierAddress(Address addr) { - return new BsdThread(this, addr); + throw new RuntimeException("unimplemented"); } + /** From the ThreadAccess interface via Debugger and JVMDebugger */ public ThreadProxy getThreadForThreadId(long id) { return new BsdThread(this, id); @@ -455,22 +460,22 @@ // Thread context access // - public synchronized long[] getThreadIntegerRegisterSet(int lwp_id) + public synchronized long[] getThreadIntegerRegisterSet(long unique_thread_id) throws DebuggerException { requireAttach(); if (isCore) { - return getThreadIntegerRegisterSet0(lwp_id); + return getThreadIntegerRegisterSet0(unique_thread_id); } else { class GetThreadIntegerRegisterSetTask implements WorkerThreadTask { - int lwp_id; + long unique_thread_id; long[] result; public void doit(BsdDebuggerLocal debugger) { - result = debugger.getThreadIntegerRegisterSet0(lwp_id); + result = debugger.getThreadIntegerRegisterSet0(unique_thread_id); } } GetThreadIntegerRegisterSetTask task = new GetThreadIntegerRegisterSetTask(); - task.lwp_id = lwp_id; + task.unique_thread_id = unique_thread_id; workerThread.execute(task); return task.result; } diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdThread.java Thu Mar 21 14:11:13 2013 +0100 @@ -28,21 +28,23 @@ class BsdThread implements ThreadProxy { private BsdDebugger debugger; - private int lwp_id; + private int thread_id; + private long unique_thread_id; /** The address argument must be the address of the _thread_id in the OSThread. It's value is result ::gettid() call. */ - BsdThread(BsdDebugger debugger, Address addr) { + BsdThread(BsdDebugger debugger, Address threadIdAddr, Address uniqueThreadIdAddr) { this.debugger = debugger; // FIXME: size of data fetched here should be configurable. // However, making it so would produce a dependency on the "types" // package from the debugger package, which is not desired. - this.lwp_id = (int) addr.getCIntegerAt(0, 4, true); + this.thread_id = (int) threadIdAddr.getCIntegerAt(0, 4, true); + this.unique_thread_id = uniqueThreadIdAddr.getCIntegerAt(0, 8, true); } BsdThread(BsdDebugger debugger, long id) { this.debugger = debugger; - this.lwp_id = (int) id; + this.thread_id = (int) id; } public boolean equals(Object obj) { @@ -50,19 +52,19 @@ return false; } - return (((BsdThread) obj).lwp_id == lwp_id); + return (((BsdThread) obj).thread_id == thread_id); } public int hashCode() { - return lwp_id; + return thread_id; } public String toString() { - return Integer.toString(lwp_id); + return Integer.toString(thread_id); } public ThreadContext getContext() throws IllegalThreadStateException { - long[] data = debugger.getThreadIntegerRegisterSet(lwp_id); + long[] data = debugger.getThreadIntegerRegisterSet(unique_thread_id); ThreadContext context = BsdThreadContextFactory.createThreadContext(debugger); for (int i = 0; i < data.length; i++) { context.setRegister(i, data[i]); diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64Thread.java --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64Thread.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64Thread.java Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 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 @@ -34,21 +34,11 @@ private boolean gotID; private long id; - /** The address argument must be the address of the HANDLE of the - desired thread in the target process. */ + // The address argument must be the address of the OSThread::_thread_id WindbgAMD64Thread(WindbgDebugger debugger, Address addr) { this.debugger = debugger; - // FIXME: size of data fetched here should be configurable. - // However, making it so would produce a dependency on the "types" - // package from the debugger package, which is not desired. - - // another hack here is that we use sys thread id instead of handle. - // windbg can't get details based on handles it seems. - // I assume that osThread_win32 thread struct has _thread_id (which - // sys thread id) just after handle field. - - this.sysId = (int) addr.addOffsetTo(debugger.getAddressSize()).getCIntegerAt(0, 4, true); - gotID = false; + this.sysId = (long)addr.getCIntegerAt(0, 4, true); + gotID = false; } WindbgAMD64Thread(WindbgDebugger debugger, long sysId) { diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86Thread.java --- a/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86Thread.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86Thread.java Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,21 +34,11 @@ private boolean gotID; private long id; - /** The address argument must be the address of the HANDLE of the - desired thread in the target process. */ + // The address argument must be the address of OSThread::_thread_id WindbgX86Thread(WindbgDebugger debugger, Address addr) { this.debugger = debugger; - // FIXME: size of data fetched here should be configurable. - // However, making it so would produce a dependency on the "types" - // package from the debugger package, which is not desired. - - // another hack here is that we use sys thread id instead of handle. - // windbg can't get details based on handles it seems. - // I assume that osThread_win32 thread struct has _thread_id (which - // sys thread id) just after handle field. - - this.sysId = (int) addr.addOffsetTo(debugger.getAddressSize()).getCIntegerAt(0, 4, true); - gotID = false; + this.sysId = (long)addr.getCIntegerAt(0, 4, true); + gotID = false; } WindbgX86Thread(WindbgDebugger debugger, long sysId) { diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/livejvm/BreakpointEvent.java --- a/agent/src/share/classes/sun/jvm/hotspot/livejvm/BreakpointEvent.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.livejvm; - -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.runtime.*; - -public class BreakpointEvent extends Event { - private Oop thread; - private Oop clazz; - private JNIid method; - private int location; - - public BreakpointEvent(Oop thread, - Oop clazz, - JNIid method, - int location) { - super(Event.Type.BREAKPOINT); - this.thread = thread; - this.clazz = clazz; - this.method = method; - this.location = location; - } - - public Oop thread() { return thread; } - public Oop clazz() { return clazz; } - public JNIid methodID() { return method; } - public int location() { return location; } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/livejvm/CIntegerAccessor.java --- a/agent/src/share/classes/sun/jvm/hotspot/livejvm/CIntegerAccessor.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.livejvm; - -import sun.jvm.hotspot.debugger.*; - -class CIntegerAccessor { - private Address addr; - private long numBytes; - private boolean isUnsigned; - - CIntegerAccessor(Address addr, long numBytes, boolean isUnsigned) { - this.addr = addr; - this.numBytes = numBytes; - this.isUnsigned = isUnsigned; - } - - long getValue() { - return addr.getCIntegerAt(0, numBytes, isUnsigned); - } - - void setValue(long value) { - addr.setCIntegerAt(0, numBytes, value); - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/livejvm/CStringAccessor.java --- a/agent/src/share/classes/sun/jvm/hotspot/livejvm/CStringAccessor.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.livejvm; - -import java.io.UnsupportedEncodingException; -import sun.jvm.hotspot.debugger.*; - -class CStringAccessor { - private Address addr; - private int bufLen; - - CStringAccessor(Address addr, int bufLen) { - this.addr = addr; - this.bufLen = bufLen; - } - - String getValue() throws DebuggerException { - int len = 0; - while ((addr.getCIntegerAt(len, 1, true) != 0) && (len < bufLen)) { - ++len; - } - byte[] res = new byte[len]; - for (int i = 0; i < len; i++) { - res[i] = (byte) addr.getCIntegerAt(i, 1, true); - } - try { - return new String(res, "US-ASCII"); - } catch (UnsupportedEncodingException e) { - throw new DebuggerException("Unable to use US-ASCII encoding"); - } - } - - void setValue(String value) throws DebuggerException { - try { - byte[] data = value.getBytes("US-ASCII"); - if (data.length >= bufLen) { - throw new DebuggerException("String too long"); - } - for (int i = 0; i < data.length; i++) { - addr.setCIntegerAt(i, 1, data[i]); - } - addr.setCIntegerAt(data.length, 1, 0); - } catch (UnsupportedEncodingException e) { - throw new DebuggerException("Unable to use US-ASCII encoding"); - } - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/livejvm/Event.java --- a/agent/src/share/classes/sun/jvm/hotspot/livejvm/Event.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.livejvm; - -public class Event { - public static class Type { - private Type() {} - public static final Type BREAKPOINT = new Type(); - public static final Type EXCEPTION = new Type(); - } - - private Type type; - - public Event(Type type) { - this.type = type; - } - - public Type getType() { return type; } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/livejvm/ExceptionEvent.java --- a/agent/src/share/classes/sun/jvm/hotspot/livejvm/ExceptionEvent.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.livejvm; - -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.runtime.*; - -public class ExceptionEvent extends Event { - private Oop thread; - private Oop clazz; - private JNIid method; - private int location; - private Oop exception; - private Oop catchClass; - private JNIid catchMethod; - private int catchLocation; - - public ExceptionEvent(Oop thread, - Oop clazz, - JNIid method, - int location, - Oop exception, - Oop catchClass, - JNIid catchMethod, - int catchLocation) { - super(Event.Type.EXCEPTION); - this.thread = thread; - this.clazz = clazz; - this.method = method; - this.location = location; - this.exception = exception; - this.catchClass = catchClass; - this.catchMethod = catchMethod; - this.catchLocation = catchLocation; - } - - public Oop thread() { return thread; } - public Oop clazz() { return clazz; } - public JNIid methodID() { return method; } - public int location() { return location; } - public Oop exception() { return exception; } - public Oop catchClass() { return catchClass; } - public JNIid catchMethodID() { return catchMethod; } - public int catchLocation() { return catchLocation; } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/livejvm/JNIHandleAccessor.java --- a/agent/src/share/classes/sun/jvm/hotspot/livejvm/JNIHandleAccessor.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.livejvm; - -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.utilities.*; - -class JNIHandleAccessor { - private Address addr; - private ObjectHeap heap; - - JNIHandleAccessor(Address addr, ObjectHeap heap) { - this.addr = addr; - this.heap = heap; - } - - Oop getValue() { - // Accessing the contents of the JNIHandle is a double dereference - Address handle = addr.getAddressAt(0); - if (handle == null) return null; - return heap.newOop(handle.getOopHandleAt(0)); - } - - void setValue(Oop value) { - Address handle = addr.getAddressAt(0); - if (Assert.ASSERTS_ENABLED) { - Assert.that(handle != null, "Must have valid global JNI handle for setting"); - } - handle.setOopHandleAt(0, value.getHandle()); - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/livejvm/ServiceabilityAgentJVMDIModule.java --- a/agent/src/share/classes/sun/jvm/hotspot/livejvm/ServiceabilityAgentJVMDIModule.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,415 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.livejvm; - -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.runtime.*; - -/** Provides Java programming language-level interaction with a live - Java HotSpot VM via the use of the SA's JVMDI module. This is an - experimental mechanism. The BugSpot debugger should be converted - to use the JVMDI/JDWP-based JDI implementation for live process - interaction once the JDI binding for the SA is complete. */ - -public class ServiceabilityAgentJVMDIModule { - private Debugger dbg; - private String[] saLibNames; - private String saLibName; - private boolean attached; - - private boolean suspended; - - private static final int JVMDI_EVENT_BREAKPOINT = 2; - private static final int JVMDI_EVENT_EXCEPTION = 4; - - private static long timeoutMillis = 3000; - - // Values in target process - // Events sent from VM to SA - private CIntegerAccessor saAttached; - private CIntegerAccessor saEventPending; - private CIntegerAccessor saEventKind; - // Exception events - private JNIHandleAccessor saExceptionThread; - private JNIHandleAccessor saExceptionClass; - private JNIid saExceptionMethod; - private CIntegerAccessor saExceptionLocation; - private JNIHandleAccessor saExceptionException; - private JNIHandleAccessor saExceptionCatchClass; - private JNIid saExceptionCatchMethod; - private CIntegerAccessor saExceptionCatchLocation; - // Breakpoint events - private JNIHandleAccessor saBreakpointThread; - private JNIHandleAccessor saBreakpointClass; - private JNIid saBreakpointMethod; - private CIntegerAccessor saBreakpointLocation; - // Commands sent by the SA to the VM - private int SA_CMD_SUSPEND_ALL; - private int SA_CMD_RESUME_ALL; - private int SA_CMD_TOGGLE_BREAKPOINT; - private int SA_CMD_BUF_SIZE; - private CIntegerAccessor saCmdPending; - private CIntegerAccessor saCmdType; - private CIntegerAccessor saCmdResult; - private CStringAccessor saCmdResultErrMsg; - // Toggle breakpoint command arguments - private CStringAccessor saCmdBkptSrcFileName; - private CStringAccessor saCmdBkptPkgName; - private CIntegerAccessor saCmdBkptLineNumber; - private CIntegerAccessor saCmdBkptResWasError; - private CIntegerAccessor saCmdBkptResLineNumber; - private CIntegerAccessor saCmdBkptResBCI; - private CIntegerAccessor saCmdBkptResWasSet; - private CStringAccessor saCmdBkptResMethodName; - private CStringAccessor saCmdBkptResMethodSig; - - public ServiceabilityAgentJVMDIModule(Debugger dbg, String[] saLibNames) { - this.dbg = dbg; - this.saLibNames = saLibNames; - } - - /** Indicates whether a call to attach() should complete without an - exception. */ - public boolean canAttach() { - return setupLookup("SA_CMD_SUSPEND_ALL"); - } - - /** Attempt to initiate a connection with the JVMDI module in the - target VM. */ - public void attach() throws DebuggerException { - if (!canAttach()) { - throw new DebuggerException("Unable to initiate symbol lookup in SA's JVMDI module"); - } - - if (attached) { - throw new DebuggerException("Already attached"); - } - - // Attempt to look up well-known symbols in the target VM. - SA_CMD_SUSPEND_ALL = lookupConstInt("SA_CMD_SUSPEND_ALL"); - SA_CMD_RESUME_ALL = lookupConstInt("SA_CMD_RESUME_ALL"); - SA_CMD_TOGGLE_BREAKPOINT = lookupConstInt("SA_CMD_TOGGLE_BREAKPOINT"); - SA_CMD_BUF_SIZE = lookupConstInt("SA_CMD_BUF_SIZE"); - - saAttached = lookupCInt("saAttached"); - saEventPending = lookupCInt("saEventPending"); - saEventKind = lookupCInt("saEventKind"); - saCmdPending = lookupCInt("saCmdPending"); - saCmdType = lookupCInt("saCmdType"); - saCmdResult = lookupCInt("saCmdResult"); - saCmdResultErrMsg = lookupCString("saCmdResultErrMsg", SA_CMD_BUF_SIZE); - // Toggling of breakpoints - saCmdBkptSrcFileName = lookupCString("saCmdBkptSrcFileName", SA_CMD_BUF_SIZE); - saCmdBkptPkgName = lookupCString("saCmdBkptPkgName", SA_CMD_BUF_SIZE); - saCmdBkptLineNumber = lookupCInt("saCmdBkptLineNumber"); - saCmdBkptResWasError = lookupCInt("saCmdBkptResWasError"); - saCmdBkptResLineNumber = lookupCInt("saCmdBkptResLineNumber"); - saCmdBkptResBCI = lookupCInt("saCmdBkptResBCI"); - saCmdBkptResWasSet = lookupCInt("saCmdBkptResWasSet"); - saCmdBkptResMethodName = lookupCString("saCmdBkptResMethodName", SA_CMD_BUF_SIZE); - saCmdBkptResMethodSig = lookupCString("saCmdBkptResMethodSig", SA_CMD_BUF_SIZE); - - // Check for existence of symbols needed later - // FIXME: should probably cache these since we can't support the - // -Xrun module or the VM getting unloaded anyway - lookup("saExceptionThread"); - lookup("saExceptionClass"); - lookup("saExceptionMethod"); - lookup("saExceptionLocation"); - lookup("saExceptionException"); - lookup("saExceptionCatchClass"); - lookup("saExceptionCatchMethod"); - lookup("saExceptionCatchLocation"); - lookup("saBreakpointThread"); - lookup("saBreakpointClass"); - lookup("saBreakpointMethod"); - lookup("saBreakpointLocation"); - - saAttached.setValue(1); - attached = true; - } - - public void detach() { - saAttached.setValue(0); - attached = false; - saLibName = null; - } - - /** Set the timeout value (in milliseconds) for the VM to reply to - commands. Once this timeout has elapsed, the VM is assumed to - have disconnected. Defaults to 3000 milliseconds (3 seconds). */ - public void setCommandTimeout(long millis) { - timeoutMillis = millis; - } - - /** Get the timeout value (in milliseconds) for the VM to reply to - commands. Once this timeout has elapsed, the VM is assumed to - have disconnected. Defaults to 3000 milliseconds (3 seconds). */ - public long getCommandTimeout() { - return timeoutMillis; - } - - /** Indicates whether a Java debug event is pending */ - public boolean eventPending() { - return (saEventPending.getValue() != 0); - } - - /** Poll for event; returns null if none pending. */ - public Event eventPoll() { - if (saEventPending.getValue() == 0) { - return null; - } - - int kind = (int) saEventKind.getValue(); - switch (kind) { - case JVMDI_EVENT_EXCEPTION: { - JNIHandleAccessor thread = lookupJNIHandle("saExceptionThread"); - JNIHandleAccessor clazz = lookupJNIHandle("saExceptionClass"); - JNIid method = lookupJNIid("saExceptionMethod"); - CIntegerAccessor location = lookupCInt("saExceptionLocation"); - JNIHandleAccessor exception = lookupJNIHandle("saExceptionException"); - JNIHandleAccessor catchClass = lookupJNIHandle("saExceptionCatchClass"); - JNIid catchMethod = lookupJNIid("saExceptionCatchMethod"); - CIntegerAccessor catchLocation = lookupCInt("saExceptionCatchLocation"); - return new ExceptionEvent(thread.getValue(), clazz.getValue(), method, - (int) location.getValue(), exception.getValue(), - catchClass.getValue(), catchMethod, (int) catchLocation.getValue()); - } - - case JVMDI_EVENT_BREAKPOINT: { - JNIHandleAccessor thread = lookupJNIHandle("saBreakpointThread"); - JNIHandleAccessor clazz = lookupJNIHandle("saBreakpointClass"); - JNIid method = lookupJNIid("saBreakpointMethod"); - CIntegerAccessor location = lookupCInt("saBreakpointLocation"); - return new BreakpointEvent(thread.getValue(), clazz.getValue(), - method, (int) location.getValue()); - } - - default: - throw new DebuggerException("Unsupported event type " + kind); - } - } - - /** Continue past current event */ - public void eventContinue() { - saEventPending.setValue(0); - } - - /** Suspend all Java threads in the target VM. Throws - DebuggerException if the VM disconnected. */ - public void suspend() { - saCmdType.setValue(SA_CMD_SUSPEND_ALL); - saCmdPending.setValue(1); - waitForCommandCompletion(); - suspended = true; - } - - /** Resume all Java threads in the target VM. Throws - DebuggerException if the VM disconnected. */ - public void resume() { - saCmdType.setValue(SA_CMD_RESUME_ALL); - saCmdPending.setValue(1); - waitForCommandCompletion(); - suspended = false; - } - - /** Indicates whether all Java threads have been suspended via this - interface. */ - public boolean isSuspended() { - return suspended; - } - - /** Information about toggling of breakpoints */ - public static class BreakpointToggleResult { - private boolean success; - private String errMsg; - private int lineNumber; - private int bci; - private boolean wasSet; - private String methodName; - private String methodSig; - - /** Success constructor */ - public BreakpointToggleResult(int lineNumber, int bci, boolean wasSet, - String methodName, String methodSig) { - this.lineNumber = lineNumber; - this.bci = bci; - this.wasSet = wasSet; - this.methodName = methodName; - this.methodSig = methodSig; - success = true; - } - - /** Failure constructor */ - public BreakpointToggleResult(String errMsg) { - this.errMsg = errMsg; - success = false; - } - - /** Indicates whether this represents a successful return or not */ - public boolean getSuccess() { return success; } - - /** Valid only if getSuccess() returns false */ - public String getErrMsg() { return errMsg; } - - /** Line number at which breakpoint toggle occurred; valid only if - getSuccess() returns true. */ - public int getLineNumber() { return lineNumber; } - - /** BCI at which breakpoint toggle occurred; valid only if - getSuccess() returns true. */ - public int getBCI() { return bci; } - - /** Indicates whether the breakpoint toggle was the set of a - breakpoint or not; valid only if getSuccess() returns true. */ - public boolean getWasSet() { return wasSet; } - - /** Method name in which the breakpoint toggle occurred; valid - only if getSuccess() returns true. */ - public String getMethodName() { return methodName; } - - /** Method signature in which the breakpoint toggle occurred; - valid only if getSuccess() returns true. */ - public String getMethodSignature() { return methodSig; } - } - - /** Toggle a breakpoint. Throws DebuggerException if a real error - occurred; otherwise returns non-null BreakpointToggleResult. The - work of scanning the loaded classes is done in the target VM - because it turns out to be significantly faster than scanning - through the system dictionary from the SA, and interactivity - when setting breakpoints is important. */ - public BreakpointToggleResult toggleBreakpoint(String srcFileName, - String pkgName, - int lineNo) { - saCmdBkptSrcFileName.setValue(srcFileName); - saCmdBkptPkgName.setValue(pkgName); - saCmdBkptLineNumber.setValue(lineNo); - saCmdType.setValue(SA_CMD_TOGGLE_BREAKPOINT); - saCmdPending.setValue(1); - if (waitForCommandCompletion(true)) { - return new BreakpointToggleResult((int) saCmdBkptResLineNumber.getValue(), - (int) saCmdBkptResBCI.getValue(), - (saCmdBkptResWasSet.getValue() != 0), - saCmdBkptResMethodName.getValue(), - saCmdBkptResMethodSig.getValue()); - } else { - return new BreakpointToggleResult(saCmdResultErrMsg.getValue()); - } - } - - - //---------------------------------------------------------------------- - // Internals only below this point - // - - private CIntegerAccessor lookupCInt(String symbolName) { - return new CIntegerAccessor(lookup(symbolName), 4, false); - } - - private CStringAccessor lookupCString(String symbolName, int bufLen) { - return new CStringAccessor(lookup(symbolName), bufLen); - } - - private JNIHandleAccessor lookupJNIHandle(String symbolName) { - return new JNIHandleAccessor(lookup(symbolName), VM.getVM().getObjectHeap()); - } - - private JNIid lookupJNIid(String symbolName) { - Address idAddr = lookup(symbolName).getAddressAt(0); - if (idAddr == null) { - return null; - } - return new JNIid(idAddr, VM.getVM().getObjectHeap()); - } - - private int lookupConstInt(String symbolName) { - Address addr = lookup(symbolName); - return (int) addr.getCIntegerAt(0, 4, false); - } - - private boolean setupLookup(String symbolName) { - if (saLibName == null) { - for (int i = 0; i < saLibNames.length; i++) { - Address addr = dbg.lookup(saLibNames[i], symbolName); - if (addr != null) { - saLibName = saLibNames[i]; - return true; - } - } - return false; - } - return true; - } - - private Address lookup(String symbolName) { - if (saLibName == null) { - for (int i = 0; i < saLibNames.length; i++) { - Address addr = dbg.lookup(saLibNames[i], symbolName); - if (addr != null) { - saLibName = saLibNames[i]; - return addr; - } - } - throw new DebuggerException("Unable to find symbol " + symbolName + " in any of the known names for the SA"); - } - - Address addr = dbg.lookup(saLibName, symbolName); - if (addr == null) { - throw new DebuggerException("Unable to find symbol " + symbolName + " in " + saLibName); - } - return addr; - } - - private void waitForCommandCompletion() { - waitForCommandCompletion(false); - } - - /** Returns true if command succeeded, false if not */ - private boolean waitForCommandCompletion(boolean forBreakpoint) { - long start = System.currentTimeMillis(); - long cur = start; - while ((saCmdPending.getValue() != 0) && - (cur - start < timeoutMillis)) { - try { - java.lang.Thread.currentThread().sleep(10); - } catch (InterruptedException e) { - } - cur = System.currentTimeMillis(); - } - if (saCmdPending.getValue() != 0) { - detach(); - throw new DebuggerException("VM appears to have died"); - } - boolean succeeded = saCmdResult.getValue() == 0; - if (!succeeded && - (!forBreakpoint || saCmdBkptResWasError.getValue() != 0)) { - String err = saCmdResultErrMsg.getValue(); - throw new DebuggerException("Error executing JVMDI command: " + err); - } - return succeeded; - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/memory/AFLBinaryTreeDictionary.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/AFLBinaryTreeDictionary.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,59 @@ +/* + * @(#)BinaryTreeDictionary.java + * 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 + * 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 sun.jvm.hotspot.memory; + +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.runtime.*; + +public class AFLBinaryTreeDictionary extends VMObject { + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) { + Type type = db.lookupType("AFLBinaryTreeDictionary"); + totalSizeField = type.getCIntegerField("_total_size"); + } + + // Fields + private static CIntegerField totalSizeField; + + // Accessors + public long size() { + return totalSizeField.getValue(addr); + } + + // Constructor + public AFLBinaryTreeDictionary(Address addr) { + super(addr); + } +} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/memory/BinaryTreeDictionary.java --- a/agent/src/share/classes/sun/jvm/hotspot/memory/BinaryTreeDictionary.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * @(#)BinaryTreeDictionary.java - * Copyright (c) 2000, 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. - * - */ - -package sun.jvm.hotspot.memory; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.runtime.*; - -public class BinaryTreeDictionary extends VMObject { - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static synchronized void initialize(TypeDataBase db) { - Type type = db.lookupType("BinaryTreeDictionary"); - totalSizeField = type.getCIntegerField("_totalSize"); - } - - // Fields - private static CIntegerField totalSizeField; - - // Accessors - public long size() { - return totalSizeField.getValue(addr); - } - - // Constructor - public BinaryTreeDictionary(Address addr) { - super(addr); - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/memory/CMSCollector.java --- a/agent/src/share/classes/sun/jvm/hotspot/memory/CMSCollector.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/CMSCollector.java Thu Mar 21 14:11:13 2013 +0100 @@ -61,15 +61,13 @@ CMSBitMap markBitMap = markBitMap(); long addressSize = VM.getVM().getAddressSize(); if ( markBitMap.isMarked(addr) && markBitMap.isMarked(addr.addOffsetTo(1*addressSize)) ) { - System.err.println("Printezis bits are set..."); Address nextOneAddr = markBitMap.getNextMarkedWordAddress(addr.addOffsetTo(2*addressSize)); //return size in bytes long size = (nextOneAddr.addOffsetTo(1*addressSize)).minus(addr); return size; } else { - //missing Printezis marks - System.err.println("Missing Printszis marks..."); - return -1; + //missing Printezis marks + return -1; } } diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java --- a/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,9 +117,9 @@ } // large block - BinaryTreeDictionary bfbd = (BinaryTreeDictionary) VMObjectFactory.newObject(BinaryTreeDictionary.class, + AFLBinaryTreeDictionary aflbd = (AFLBinaryTreeDictionary) VMObjectFactory.newObject(AFLBinaryTreeDictionary.class, dictionaryField.getValue(addr)); - size += bfbd.size(); + size += aflbd.size(); // linear block in TLAB @@ -191,7 +191,6 @@ //Find the object size using Printezis bits and skip over long size = collector().blockSizeUsingPrintezisBits(cur); if (size == -1) { - System.err.println("Printezis bits not set..."); break; } cur = cur.addOffsetTo(adjustObjectSizeInBytes(size)); diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/memory/FreeList.java --- a/agent/src/share/classes/sun/jvm/hotspot/memory/FreeList.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/FreeList.java Thu Mar 21 14:11:13 2013 +0100 @@ -1,7 +1,7 @@ /* * @(#)FreeList.java * - * Copyright (c) 2000, 2008, 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 @@ -41,7 +41,7 @@ } private static synchronized void initialize(TypeDataBase db) { - Type type = db.lookupType("FreeList"); + Type type = db.lookupType("FreeList"); sizeField = type.getCIntegerField("_size"); countField = type.getCIntegerField("_count"); headerSize = type.getSize(); diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java --- a/agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,12 +49,18 @@ private static int HAS_LOCALVARIABLE_TABLE; private static int HAS_EXCEPTION_TABLE; private static int HAS_GENERIC_SIGNATURE; + private static int HAS_METHOD_ANNOTATIONS; + private static int HAS_PARAMETER_ANNOTATIONS; + private static int HAS_DEFAULT_ANNOTATIONS; + private static int HAS_TYPE_ANNOTATIONS; + + private static final int sizeofShort = 2; private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("ConstMethod"); constants = new MetadataField(type.getAddressField("_constants"), 0); constMethodSize = new CIntField(type.getCIntegerField("_constMethod_size"), 0); - flags = new ByteField(type.getJByteField("_flags"), 0); + flags = new CIntField(type.getCIntegerField("_flags"), 0); // enum constants for flags HAS_LINENUMBER_TABLE = db.lookupIntConstant("ConstMethod::_has_linenumber_table").intValue(); @@ -62,6 +68,10 @@ HAS_LOCALVARIABLE_TABLE = db.lookupIntConstant("ConstMethod::_has_localvariable_table").intValue(); HAS_EXCEPTION_TABLE = db.lookupIntConstant("ConstMethod::_has_exception_table").intValue(); HAS_GENERIC_SIGNATURE = db.lookupIntConstant("ConstMethod::_has_generic_signature").intValue(); + HAS_METHOD_ANNOTATIONS = db.lookupIntConstant("ConstMethod::_has_method_annotations").intValue(); + HAS_PARAMETER_ANNOTATIONS = db.lookupIntConstant("ConstMethod::_has_parameter_annotations").intValue(); + HAS_DEFAULT_ANNOTATIONS = db.lookupIntConstant("ConstMethod::_has_default_annotations").intValue(); + HAS_TYPE_ANNOTATIONS = db.lookupIntConstant("ConstMethod::_has_type_annotations").intValue(); // Size of Java bytecodes allocated immediately after ConstMethod*. codeSize = new CIntField(type.getCIntegerField("_code_size"), 0); @@ -92,7 +102,7 @@ // Fields private static MetadataField constants; private static CIntField constMethodSize; - private static ByteField flags; + private static CIntField flags; private static CIntField codeSize; private static CIntField nameIndex; private static CIntField signatureIndex; @@ -123,7 +133,7 @@ return constMethodSize.getValue(this); } - public byte getFlags() { + public long getFlags() { return flags.getValue(this); } @@ -253,7 +263,7 @@ public void iterateFields(MetadataVisitor visitor) { visitor.doMetadata(constants, true); visitor.doCInt(constMethodSize, true); - visitor.doByte(flags, true); + visitor.doCInt(flags, true); visitor.doCInt(codeSize, true); visitor.doCInt(nameIndex, true); visitor.doCInt(signatureIndex, true); @@ -381,6 +391,22 @@ return (getFlags() & HAS_GENERIC_SIGNATURE) != 0; } + private boolean hasMethodAnnotations() { + return (getFlags() & HAS_METHOD_ANNOTATIONS) != 0; + } + + private boolean hasParameterAnnotations() { + return (getFlags() & HAS_PARAMETER_ANNOTATIONS) != 0; + } + + private boolean hasDefaultAnnotations() { + return (getFlags() & HAS_DEFAULT_ANNOTATIONS) != 0; + } + + private boolean hasTypeAnnotations() { + return (getFlags() & HAS_TYPE_ANNOTATIONS) != 0; + } + //--------------------------------------------------------------------------- // Internals only below this point @@ -400,9 +426,15 @@ return offsetOfCodeEnd() + (isNative() ? 2 * VM.getVM().getAddressSize() : 0); } - // Offset of last short in Method* + // Offset of last short in Method* before annotations, if present private long offsetOfLastU2Element() { - return getSize() * VM.getVM().getObjectHeap().getOopSize() - 2; + int offset = 0; + if (hasMethodAnnotations()) offset++; + if (hasParameterAnnotations()) offset++; + if (hasTypeAnnotations()) offset++; + if (hasDefaultAnnotations()) offset++; + long wordSize = VM.getVM().getObjectHeap().getOopSize(); + return (getSize() * wordSize) - (offset * wordSize) - sizeofShort; } // Offset of the generic signature index @@ -411,7 +443,7 @@ } private long offsetOfCheckedExceptionsLength() { - return hasGenericSignature() ? offsetOfLastU2Element() - 2 : + return hasGenericSignature() ? offsetOfLastU2Element() - sizeofShort : offsetOfLastU2Element(); } @@ -461,11 +493,11 @@ } if (hasExceptionTable()) { - return offsetOfExceptionTable() - 2; + return offsetOfExceptionTable() - sizeofShort; } else if (hasCheckedExceptions()) { - return offsetOfCheckedExceptions() - 2; + return offsetOfCheckedExceptions() - sizeofShort; } else { - return hasGenericSignature() ? offsetOfLastU2Element() - 2 : + return hasGenericSignature() ? offsetOfLastU2Element() - sizeofShort : offsetOfLastU2Element(); } } @@ -493,9 +525,9 @@ Assert.that(hasExceptionTable(), "should only be called if table is present"); } if (hasCheckedExceptions()) { - return offsetOfCheckedExceptions() - 2; + return offsetOfCheckedExceptions() - sizeofShort; } else { - return hasGenericSignature() ? offsetOfLastU2Element() - 2 : + return hasGenericSignature() ? offsetOfLastU2Element() - sizeofShort : offsetOfLastU2Element(); } } diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java --- a/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -469,7 +469,6 @@ case JVM_CONSTANT_UnresolvedClassInError: return "JVM_CONSTANT_UnresolvedClassInError"; case JVM_CONSTANT_MethodHandleInError:return "JVM_CONSTANT_MethodHandleInError"; case JVM_CONSTANT_MethodTypeInError: return "JVM_CONSTANT_MethodTypeInError"; - case JVM_CONSTANT_Object: return "JVM_CONSTANT_Object"; } throw new InternalError("Unknown tag: " + tag); } diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/oops/MethodData.java --- a/agent/src/share/classes/sun/jvm/hotspot/oops/MethodData.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/MethodData.java Thu Mar 21 14:11:13 2013 +0100 @@ -184,7 +184,6 @@ if (trapReasonName[index] == null) { throw new InternalError("missing reason for " + index); } - System.out.println(trapReasonName[index]); } } diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java --- a/agent/src/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java Thu Mar 21 14:11:13 2013 +0100 @@ -335,7 +335,6 @@ } if (obj == null) { //Find the object size using Printezis bits and skip over - System.err.println("Finding object size using Printezis bits and skipping over..."); long size = 0; if ( (cmsSpaceOld != null) && cmsSpaceOld.contains(handle) ){ @@ -467,7 +466,7 @@ liveRegions.add(tlab.start()); liveRegions.add(tlab.start()); liveRegions.add(tlab.top()); - liveRegions.add(tlab.end()); + liveRegions.add(tlab.hardEnd()); } } } diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,6 @@ public static final int JVM_CONSTANT_UnresolvedClassInError = 103; // Error tag due to resolution error public static final int JVM_CONSTANT_MethodHandleInError = 104; // Error tag due to resolution error public static final int JVM_CONSTANT_MethodTypeInError = 105; // Error tag due to resolution error - public static final int JVM_CONSTANT_Object = 106; // Required for BoundMethodHandle arguments. // 1.5 major/minor version numbers from JVM spec. 3rd edition public static final short MAJOR_VERSION = 49; diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/runtime/OSThread.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/OSThread.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/OSThread.java Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ // to the sys_thread_t structure of the classic JVM implementation. public class OSThread extends VMObject { private static JIntField interruptedField; + private static JIntField threadIdField; static { VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { @@ -43,6 +44,7 @@ private static synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("OSThread"); interruptedField = type.getJIntField("_interrupted"); + threadIdField = type.getJIntField("_thread_id"); } public OSThread(Address addr) { @@ -52,4 +54,9 @@ public boolean interrupted() { return ((int)interruptedField.getValue(addr)) != 0; } + + public int threadId() { + return (int)threadIdField.getValue(addr); + } + } diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java Thu Mar 21 14:11:13 2013 +0100 @@ -27,6 +27,7 @@ import java.io.*; import java.util.*; import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.oops.*; import sun.jvm.hotspot.types.*; /**

ThreadLocalAllocBuffer: a descriptor for thread-local storage @@ -62,9 +63,22 @@ super(addr); } - public Address start() { return startField.getValue(addr); } - public Address end() { return endField.getValue(addr); } - public Address top() { return topField.getValue(addr); } + public Address start() { return startField.getValue(addr); } + public Address end() { return endField.getValue(addr); } + public Address top() { return topField.getValue(addr); } + public Address hardEnd() { return end().addOffsetTo(alignmentReserve()); } + + private long alignmentReserve() { + return Oop.alignObjectSize(endReserve()); + } + + private long endReserve() { + long minFillerArraySize = Array.baseOffsetInBytes(BasicType.T_INT); + long reserveForAllocationPrefetch = VM.getVM().getReserveForAllocationPrefetch(); + long heapWordSize = VM.getVM().getHeapWordSize(); + + return Math.max(minFillerArraySize, reserveForAllocationPrefetch * heapWordSize); + } /** Support for iteration over heap -- not sure how this will interact with GC in reflective system, but necessary for the diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Thu Mar 21 14:11:13 2013 +0100 @@ -90,10 +90,6 @@ /** Flags indicating whether we are attached to a core, C1, or C2 build */ private boolean usingClientCompiler; private boolean usingServerCompiler; - /** Flag indicating whether UseTLAB is turned on */ - private boolean useTLAB; - /** Flag indicating whether invokedynamic support is on */ - private boolean enableInvokeDynamic; /** alignment constants */ private boolean isLP64; private int bytesPerLong; @@ -114,6 +110,7 @@ private int invalidOSREntryBCI; private ReversePtrs revPtrs; private VMRegImpl vmregImpl; + private int reserveForAllocationPrefetch; // System.getProperties from debuggee VM private Properties sysProps; @@ -293,6 +290,10 @@ vmRelease = CStringUtilities.getString(releaseAddr); Address vmInternalInfoAddr = vmVersion.getAddressField("_s_internal_vm_info_string").getValue(); vmInternalInfo = CStringUtilities.getString(vmInternalInfoAddr); + + CIntegerType intType = (CIntegerType) db.lookupType("int"); + CIntegerField reserveForAllocationPrefetchField = vmVersion.getCIntegerField("_reserve_for_allocation_prefetch"); + reserveForAllocationPrefetch = (int)reserveForAllocationPrefetchField.getCInteger(intType); } catch (Exception exp) { throw new RuntimeException("can't determine target's VM version : " + exp.getMessage()); } @@ -321,9 +322,6 @@ } } - useTLAB = (db.lookupIntConstant("UseTLAB").intValue() != 0); - enableInvokeDynamic = (db.lookupIntConstant("EnableInvokeDynamic").intValue() != 0); - if (debugger != null) { isLP64 = debugger.getMachineDescription().isLP64(); } @@ -574,15 +572,6 @@ } } - /** Indicates whether Thread-Local Allocation Buffers are used */ - public boolean getUseTLAB() { - return useTLAB; - } - - public boolean getEnableInvokeDynamic() { - return enableInvokeDynamic; - } - public TypeDataBase getTypeDataBase() { return db; } @@ -778,6 +767,10 @@ return vmInternalInfo; } + public int getReserveForAllocationPrefetch() { + return reserveForAllocationPrefetch; + } + public boolean isSharingEnabled() { if (sharingEnabled == null) { Flag flag = getCommandLineFlag("UseSharedSpaces"); @@ -813,6 +806,12 @@ return objectAlignmentInBytes; } + /** Indicates whether Thread-Local Allocation Buffers are used */ + public boolean getUseTLAB() { + Flag flag = getCommandLineFlag("UseTLAB"); + return (flag == null) ? false: flag.getBool(); + } + // returns null, if not available. public Flag[] getCommandLineFlags() { if (commandLineFlags == null) { diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_amd64/BsdAMD64JavaThreadPDAccess.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_amd64/BsdAMD64JavaThreadPDAccess.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/bsd_amd64/BsdAMD64JavaThreadPDAccess.java Thu Mar 21 14:11:13 2013 +0100 @@ -28,6 +28,8 @@ import java.util.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.amd64.*; +import sun.jvm.hotspot.debugger.bsd.BsdDebugger; +import sun.jvm.hotspot.debugger.bsd.BsdDebuggerLocal; import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.runtime.amd64.*; import sun.jvm.hotspot.runtime.x86.*; @@ -38,8 +40,9 @@ private static AddressField lastJavaFPField; private static AddressField osThreadField; - // Field from OSThread + // Fields from OSThread private static CIntegerField osThreadThreadIDField; + private static CIntegerField osThreadUniqueThreadIDField; // This is currently unneeded but is being kept in case we change // the currentFrameGuess algorithm @@ -61,7 +64,8 @@ lastJavaFPField = anchorType.getAddressField("_last_Java_fp"); Type osThreadType = db.lookupType("OSThread"); - osThreadThreadIDField = osThreadType.getCIntegerField("_thread_id"); + osThreadThreadIDField = osThreadType.getCIntegerField("_thread_id"); + osThreadUniqueThreadIDField = osThreadType.getCIntegerField("_unique_thread_id"); } public Address getLastJavaFP(Address addr) { @@ -125,8 +129,9 @@ Address osThreadAddr = osThreadField.getValue(addr); // Get the address of the _thread_id from the OSThread Address threadIdAddr = osThreadAddr.addOffsetTo(osThreadThreadIDField.getOffset()); + Address uniqueThreadIdAddr = osThreadAddr.addOffsetTo(osThreadUniqueThreadIDField.getOffset()); - JVMDebugger debugger = VM.getVM().getDebugger(); - return debugger.getThreadForIdentifierAddress(threadIdAddr); + BsdDebuggerLocal debugger = (BsdDebuggerLocal) VM.getVM().getDebugger(); + return debugger.getThreadForIdentifierAddress(threadIdAddr, uniqueThreadIdAddr); } } diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/runtime/win32_amd64/Win32AMD64JavaThreadPDAccess.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_amd64/Win32AMD64JavaThreadPDAccess.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_amd64/Win32AMD64JavaThreadPDAccess.java Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -43,7 +43,7 @@ private static AddressField osThreadField; // Field from OSThread - private static Field osThreadThreadHandleField; + private static Field osThreadThreadIdField; // This is currently unneeded but is being kept in case we change // the currentFrameGuess algorithm @@ -64,7 +64,7 @@ osThreadField = type.getAddressField("_osthread"); type = db.lookupType("OSThread"); - osThreadThreadHandleField = type.getField("_thread_handle"); + osThreadThreadIdField = type.getField("_thread_id"); } public Address getLastJavaFP(Address addr) { @@ -128,10 +128,10 @@ // Fetch the OSThread (for now and for simplicity, not making a // separate "OSThread" class in this package) Address osThreadAddr = osThreadField.getValue(addr); - // Get the address of the HANDLE within the OSThread - Address threadHandleAddr = - osThreadAddr.addOffsetTo(osThreadThreadHandleField.getOffset()); + // Get the address of the thread_id within the OSThread + Address threadIdAddr = + osThreadAddr.addOffsetTo(osThreadThreadIdField.getOffset()); JVMDebugger debugger = VM.getVM().getDebugger(); - return debugger.getThreadForIdentifierAddress(threadHandleAddr); + return debugger.getThreadForIdentifierAddress(threadIdAddr); } } diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/runtime/win32_x86/Win32X86JavaThreadPDAccess.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_x86/Win32X86JavaThreadPDAccess.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_x86/Win32X86JavaThreadPDAccess.java Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2011, 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,7 +42,7 @@ private static AddressField osThreadField; // Field from OSThread - private static Field osThreadThreadHandleField; + private static Field osThreadThreadIdField; // This is currently unneeded but is being kept in case we change // the currentFrameGuess algorithm @@ -63,7 +63,7 @@ osThreadField = type.getAddressField("_osthread"); type = db.lookupType("OSThread"); - osThreadThreadHandleField = type.getField("_thread_handle"); + osThreadThreadIdField = type.getField("_thread_id"); } public Address getLastJavaFP(Address addr) { @@ -127,10 +127,10 @@ // Fetch the OSThread (for now and for simplicity, not making a // separate "OSThread" class in this package) Address osThreadAddr = osThreadField.getValue(addr); - // Get the address of the HANDLE within the OSThread - Address threadHandleAddr = - osThreadAddr.addOffsetTo(osThreadThreadHandleField.getOffset()); + // Get the address of the thread_id within the OSThread + Address threadIdAddr = + osThreadAddr.addOffsetTo(osThreadThreadIdField.getOffset()); JVMDebugger debugger = VM.getVM().getDebugger(); - return debugger.getThreadForIdentifierAddress(threadHandleAddr); + return debugger.getThreadForIdentifierAddress(threadIdAddr); } } diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,277 @@ +/* + * 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 + * 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 sun.jvm.hotspot.tools; + +import java.io.*; +import java.util.*; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.memory.*; +import sun.jvm.hotspot.oops.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.tools.*; +import sun.jvm.hotspot.utilities.*; + +/** + A command line tool to print class loader statistics. +*/ + +public class ClassLoaderStats extends Tool { + boolean verbose = true; + + public static void main(String[] args) { + ClassLoaderStats cls = new ClassLoaderStats(); + cls.start(args); + cls.stop(); + } + + private static class ClassData { + Klass klass; + long size; + + ClassData(Klass klass, long size) { + this.klass = klass; this.size = size; + } + } + + private static class LoaderData { + long numClasses; + long classSize; + List classDetail = new ArrayList(); // List + } + + public void run() { + printClassLoaderStatistics(); + } + + private void printClassLoaderStatistics() { + final PrintStream out = System.out; + final PrintStream err = System.err; + final Map loaderMap = new HashMap(); + // loader data for bootstrap class loader + final LoaderData bootstrapLoaderData = new LoaderData(); + if (verbose) { + err.print("finding class loader instances .."); + } + + VM vm = VM.getVM(); + ObjectHeap heap = vm.getObjectHeap(); + Klass classLoaderKlass = vm.getSystemDictionary().getClassLoaderKlass(); + try { + heap.iterateObjectsOfKlass(new DefaultHeapVisitor() { + public boolean doObj(Oop oop) { + loaderMap.put(oop, new LoaderData()); + return false; + } + }, classLoaderKlass); + } catch (Exception se) { + se.printStackTrace(); + } + + if (verbose) { + err.println("done."); + err.print("computing per loader stat .."); + } + + SystemDictionary dict = VM.getVM().getSystemDictionary(); + dict.classesDo(new SystemDictionary.ClassAndLoaderVisitor() { + public void visit(Klass k, Oop loader) { + if (! (k instanceof InstanceKlass)) { + return; + } + LoaderData ld = (loader != null) ? (LoaderData)loaderMap.get(loader) + : bootstrapLoaderData; + if (ld != null) { + ld.numClasses++; + long size = computeSize((InstanceKlass)k); + ld.classDetail.add(new ClassData(k, size)); + ld.classSize += size; + } + } + }); + + if (verbose) { + err.println("done."); + err.print("please wait.. computing liveness"); + } + + // compute reverse pointer analysis (takes long time for larger app) + ReversePtrsAnalysis analysis = new ReversePtrsAnalysis(); + + if (verbose) { + analysis.setHeapProgressThunk(new HeapProgressThunk() { + public void heapIterationFractionUpdate(double fractionOfHeapVisited) { + err.print('.'); + } + // This will be called after the iteration is complete + public void heapIterationComplete() { + err.println("done."); + } + }); + } + + try { + analysis.run(); + } catch (Exception e) { + // e.printStackTrace(); + if (verbose) + err.println("liveness analysis may be inaccurate ..."); + } + ReversePtrs liveness = VM.getVM().getRevPtrs(); + + out.println("class_loader\tclasses\tbytes\tparent_loader\talive?\ttype"); + out.println(); + + long numClassLoaders = 1L; + long totalNumClasses = bootstrapLoaderData.numClasses; + long totalClassSize = bootstrapLoaderData.classSize; + long numAliveLoaders = 1L; + long numDeadLoaders = 0L; + + // print bootstrap loader details + out.print(""); + out.print('\t'); + out.print(bootstrapLoaderData.numClasses); + out.print('\t'); + out.print(bootstrapLoaderData.classSize); + out.print('\t'); + out.print(" null "); + out.print('\t'); + // bootstrap loader is always alive + out.print("live"); + out.print('\t'); + out.println(""); + + for (Iterator keyItr = loaderMap.keySet().iterator(); keyItr.hasNext();) { + Oop loader = (Oop) keyItr.next(); + LoaderData data = (LoaderData) loaderMap.get(loader); + numClassLoaders ++; + totalNumClasses += data.numClasses; + totalClassSize += data.classSize; + + out.print(loader.getHandle()); + out.print('\t'); + out.print(data.numClasses); + out.print('\t'); + out.print(data.classSize); + out.print('\t'); + + class ParentFinder extends DefaultOopVisitor { + public void doOop(OopField field, boolean isVMField) { + if (field.getID().getName().equals("parent")) { + parent = field.getValue(getObj()); + } + } + private Oop parent = null; + public Oop getParent() { return parent; } + } + + ParentFinder parentFinder = new ParentFinder(); + loader.iterate(parentFinder, false); + Oop parent = parentFinder.getParent(); + out.print((parent != null)? parent.getHandle().toString() : " null "); + out.print('\t'); + boolean alive = (liveness != null) ? (liveness.get(loader) != null) : true; + out.print(alive? "live" : "dead"); + if (alive) numAliveLoaders++; else numDeadLoaders++; + out.print('\t'); + Klass loaderKlass = loader.getKlass(); + if (loaderKlass != null) { + out.print(loaderKlass.getName().asString()); + out.print('@'); + out.print(loader.getKlass().getAddress()); + } else { + out.print(" null! "); + } + out.println(); + } + + out.println(); + // summary line + out.print("total = "); + out.print(numClassLoaders); + out.print('\t'); + out.print(totalNumClasses); + out.print('\t'); + out.print(totalClassSize); + out.print('\t'); + out.print(" N/A "); + out.print('\t'); + out.print("alive="); + out.print(numAliveLoaders); + out.print(", dead="); + out.print(numDeadLoaders); + out.print('\t'); + out.print(" N/A "); + out.println(); + } + + private static long objectSize(Oop oop) { + return oop == null ? 0L : oop.getObjectSize(); + } + + // Don't count the shared empty arrays + private static long arraySize(GenericArray arr) { + return arr.getLength() != 0L ? arr.getSize() : 0L; + } + + private long computeSize(InstanceKlass k) { + long size = 0L; + // the InstanceKlass object itself + size += k.getSize(); + + // Constant pool + ConstantPool cp = k.getConstants(); + size += cp.getSize(); + if (cp.getCache() != null) { + size += cp.getCache().getSize(); + } + size += arraySize(cp.getTags()); + + // Interfaces + size += arraySize(k.getLocalInterfaces()); + size += arraySize(k.getTransitiveInterfaces()); + + // Inner classes + size += arraySize(k.getInnerClasses()); + + // Fields + size += arraySize(k.getFields()); + + // Methods + MethodArray methods = k.getMethods(); + int nmethods = (int) methods.getLength(); + if (nmethods != 0L) { + size += methods.getSize(); + for (int i = 0; i < nmethods; ++i) { + Method m = methods.at(i); + size += m.getSize(); + size += m.getConstMethod().getSize(); + } + } + + return size; + } +} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/HeapSummary.java Thu Mar 21 14:11:13 2013 +0100 @@ -57,17 +57,18 @@ printGCAlgorithm(flagMap); System.out.println(); System.out.println("Heap Configuration:"); - printValue("MinHeapFreeRatio = ", getFlagValue("MinHeapFreeRatio", flagMap)); - printValue("MaxHeapFreeRatio = ", getFlagValue("MaxHeapFreeRatio", flagMap)); - printValMB("MaxHeapSize = ", getFlagValue("MaxHeapSize", flagMap)); - printValMB("NewSize = ", getFlagValue("NewSize", flagMap)); - printValMB("MaxNewSize = ", getFlagValue("MaxNewSize", flagMap)); - printValMB("OldSize = ", getFlagValue("OldSize", flagMap)); - printValue("NewRatio = ", getFlagValue("NewRatio", flagMap)); - printValue("SurvivorRatio = ", getFlagValue("SurvivorRatio", flagMap)); - printValMB("MetaspaceSize = ", getFlagValue("MetaspaceSize", flagMap)); - printValMB("MaxMetaspaceSize = ", getFlagValue("MaxMetaspaceSize", flagMap)); - printValMB("G1HeapRegionSize = ", HeapRegion.grainBytes()); + printValue("MinHeapFreeRatio = ", getFlagValue("MinHeapFreeRatio", flagMap)); + printValue("MaxHeapFreeRatio = ", getFlagValue("MaxHeapFreeRatio", flagMap)); + printValMB("MaxHeapSize = ", getFlagValue("MaxHeapSize", flagMap)); + printValMB("NewSize = ", getFlagValue("NewSize", flagMap)); + printValMB("MaxNewSize = ", getFlagValue("MaxNewSize", flagMap)); + printValMB("OldSize = ", getFlagValue("OldSize", flagMap)); + printValue("NewRatio = ", getFlagValue("NewRatio", flagMap)); + printValue("SurvivorRatio = ", getFlagValue("SurvivorRatio", flagMap)); + printValMB("MetaspaceSize = ", getFlagValue("MetaspaceSize", flagMap)); + printValMB("ClassMetaspaceSize = ", getFlagValue("ClassMetaspaceSize", flagMap)); + printValMB("MaxMetaspaceSize = ", getFlagValue("MaxMetaspaceSize", flagMap)); + printValMB("G1HeapRegionSize = ", HeapRegion.grainBytes()); System.out.println(); System.out.println("Heap Usage:"); diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ } protected String getCommandFlags() { - return "-heap|-heap:format=b|-histo|-permstat|-finalizerinfo"; + return "-heap|-heap:format=b|-histo|-clstats|-finalizerinfo"; } protected void printFlagsUsage() { @@ -53,14 +53,14 @@ System.out.println(" -heap\tto print java heap summary"); System.out.println(" -heap:format=b\tto dump java heap in hprof binary format"); System.out.println(" -histo\tto print histogram of java object heap"); - System.out.println(" -permstat\tto print permanent generation statistics"); + System.out.println(" -clstats\tto print class loader statistics"); System.out.println(" -finalizerinfo\tto print information on objects awaiting finalization"); super.printFlagsUsage(); } public static final int MODE_HEAP_SUMMARY = 0; public static final int MODE_HISTOGRAM = 1; - public static final int MODE_PERMSTAT = 2; + public static final int MODE_CLSTATS = 2; public static final int MODE_PMAP = 3; public static final int MODE_HEAP_GRAPH_HPROF_BIN = 4; public static final int MODE_HEAP_GRAPH_GXL = 5; @@ -78,8 +78,8 @@ tool = new ObjectHistogram(); break; - case MODE_PERMSTAT: - tool = new PermStat(); + case MODE_CLSTATS: + tool = new ClassLoaderStats(); break; case MODE_PMAP: @@ -118,7 +118,9 @@ } else if (modeFlag.equals("-histo")) { mode = MODE_HISTOGRAM; } else if (modeFlag.equals("-permstat")) { - mode = MODE_PERMSTAT; + mode = MODE_CLSTATS; + } else if (modeFlag.equals("-clstats")) { + mode = MODE_CLSTATS; } else if (modeFlag.equals("-finalizerinfo")) { mode = MODE_FINALIZERINFO; } else { diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/tools/PMap.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/PMap.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/PMap.java Thu Mar 21 14:11:13 2013 +0100 @@ -58,10 +58,6 @@ } } - protected boolean requiresVM() { - return false; - } - public static void main(String[] args) throws Exception { PMap t = new PMap(); t.start(args); diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/PStack.java Thu Mar 21 14:11:13 2013 +0100 @@ -50,29 +50,23 @@ public void run(PrintStream out) { Debugger dbg = getAgent().getDebugger(); - run(out, dbg, getAgent().isJavaMode()); + run(out, dbg); } public void run(PrintStream out, Debugger dbg) { - run(out, dbg, true); - } - - private void run(PrintStream out, Debugger dbg, final boolean isJava) { CDebugger cdbg = dbg.getCDebugger(); if (cdbg != null) { ConcurrentLocksPrinter concLocksPrinter = null; - if (isJava) { - // compute and cache java Vframes. - initJFrameCache(); - if (concurrentLocks) { - concLocksPrinter = new ConcurrentLocksPrinter(); - } - // print Java level deadlocks - try { - DeadlockDetector.print(out); - } catch (Exception exp) { - out.println("can't print deadlock information: " + exp.getMessage()); - } + // compute and cache java Vframes. + initJFrameCache(); + if (concurrentLocks) { + concLocksPrinter = new ConcurrentLocksPrinter(); + } + // print Java level deadlocks + try { + DeadlockDetector.print(out); + } catch (Exception exp) { + out.println("can't print deadlock information: " + exp.getMessage()); } List l = cdbg.getThreadList(); @@ -100,63 +94,59 @@ } out.println(); } else { - if (isJava) { - // look for one or more java frames - String[] names = null; - // check interpreter frame - Interpreter interp = VM.getVM().getInterpreter(); - if (interp.contains(pc)) { - names = getJavaNames(th, f.localVariableBase()); - // print codelet name if we can't determine method - if (names == null || names.length == 0) { - out.print(" "); - InterpreterCodelet ic = interp.getCodeletContaining(pc); - if (ic != null) { - String desc = ic.getDescription(); - if (desc != null) out.print(desc); - } - out.println(); - } - } else { - // look for known code blobs - CodeCache c = VM.getVM().getCodeCache(); - if (c.contains(pc)) { - CodeBlob cb = c.findBlobUnsafe(pc); - if (cb.isNMethod()) { - names = getJavaNames(th, f.localVariableBase()); - // just print compiled code, if can't determine method - if (names == null || names.length == 0) { - out.println(""); - } - } else if (cb.isBufferBlob()) { - out.println(""); - } else if (cb.isRuntimeStub()) { - out.println(""); - } else if (cb.isDeoptimizationStub()) { - out.println(""); - } else if (cb.isUncommonTrapStub()) { - out.println(""); - } else if (cb.isExceptionStub()) { - out.println(""); - } else if (cb.isSafepointStub()) { - out.println(""); - } else { - out.println(""); - } - } else { - printUnknown(out); - } - } - // print java frames, if any - if (names != null && names.length != 0) { - // print java frame(s) - for (int i = 0; i < names.length; i++) { - out.println(names[i]); - } - } - } else { - printUnknown(out); - } + // look for one or more java frames + String[] names = null; + // check interpreter frame + Interpreter interp = VM.getVM().getInterpreter(); + if (interp.contains(pc)) { + names = getJavaNames(th, f.localVariableBase()); + // print codelet name if we can't determine method + if (names == null || names.length == 0) { + out.print(" "); + InterpreterCodelet ic = interp.getCodeletContaining(pc); + if (ic != null) { + String desc = ic.getDescription(); + if (desc != null) out.print(desc); + } + out.println(); + } + } else { + // look for known code blobs + CodeCache c = VM.getVM().getCodeCache(); + if (c.contains(pc)) { + CodeBlob cb = c.findBlobUnsafe(pc); + if (cb.isNMethod()) { + names = getJavaNames(th, f.localVariableBase()); + // just print compiled code, if can't determine method + if (names == null || names.length == 0) { + out.println(""); + } + } else if (cb.isBufferBlob()) { + out.println(""); + } else if (cb.isRuntimeStub()) { + out.println(""); + } else if (cb.isDeoptimizationStub()) { + out.println(""); + } else if (cb.isUncommonTrapStub()) { + out.println(""); + } else if (cb.isExceptionStub()) { + out.println(""); + } else if (cb.isSafepointStub()) { + out.println(""); + } else { + out.println(""); + } + } else { + printUnknown(out); + } + } + // print java frames, if any + if (names != null && names.length != 0) { + // print java frame(s) + for (int i = 0; i < names.length; i++) { + out.println(names[i]); + } + } } f = f.sender(th); } @@ -164,7 +154,7 @@ exp.printStackTrace(); // continue, may be we can do a better job for other threads } - if (isJava && concurrentLocks) { + if (concurrentLocks) { JavaThread jthread = (JavaThread) proxyToThread.get(th); if (jthread != null) { concLocksPrinter.print(jthread, out); @@ -180,10 +170,6 @@ } } - protected boolean requiresVM() { - return false; - } - public static void main(String[] args) throws Exception { PStack t = new PStack(); t.start(args); diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/tools/PermStat.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/PermStat.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,277 +0,0 @@ -/* - * Copyright (c) 2003, 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 sun.jvm.hotspot.tools; - -import java.io.*; -import java.util.*; - -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.memory.*; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.tools.*; -import sun.jvm.hotspot.utilities.*; - -/** - A command line tool to print perm. generation statistics. -*/ - -public class PermStat extends Tool { - boolean verbose = true; - - public static void main(String[] args) { - PermStat ps = new PermStat(); - ps.start(args); - ps.stop(); - } - - private static class ClassData { - Klass klass; - long size; - - ClassData(Klass klass, long size) { - this.klass = klass; this.size = size; - } - } - - private static class LoaderData { - long numClasses; - long classSize; - List classDetail = new ArrayList(); // List - } - - public void run() { - printClassLoaderStatistics(); - } - - private void printClassLoaderStatistics() { - final PrintStream out = System.out; - final PrintStream err = System.err; - final Map loaderMap = new HashMap(); - // loader data for bootstrap class loader - final LoaderData bootstrapLoaderData = new LoaderData(); - if (verbose) { - err.print("finding class loader instances .."); - } - - VM vm = VM.getVM(); - ObjectHeap heap = vm.getObjectHeap(); - Klass classLoaderKlass = vm.getSystemDictionary().getClassLoaderKlass(); - try { - heap.iterateObjectsOfKlass(new DefaultHeapVisitor() { - public boolean doObj(Oop oop) { - loaderMap.put(oop, new LoaderData()); - return false; - } - }, classLoaderKlass); - } catch (Exception se) { - se.printStackTrace(); - } - - if (verbose) { - err.println("done."); - err.print("computing per loader stat .."); - } - - SystemDictionary dict = VM.getVM().getSystemDictionary(); - dict.classesDo(new SystemDictionary.ClassAndLoaderVisitor() { - public void visit(Klass k, Oop loader) { - if (! (k instanceof InstanceKlass)) { - return; - } - LoaderData ld = (loader != null) ? (LoaderData)loaderMap.get(loader) - : bootstrapLoaderData; - if (ld != null) { - ld.numClasses++; - long size = computeSize((InstanceKlass)k); - ld.classDetail.add(new ClassData(k, size)); - ld.classSize += size; - } - } - }); - - if (verbose) { - err.println("done."); - err.print("please wait.. computing liveness"); - } - - // compute reverse pointer analysis (takes long time for larger app) - ReversePtrsAnalysis analysis = new ReversePtrsAnalysis(); - - if (verbose) { - analysis.setHeapProgressThunk(new HeapProgressThunk() { - public void heapIterationFractionUpdate(double fractionOfHeapVisited) { - err.print('.'); - } - // This will be called after the iteration is complete - public void heapIterationComplete() { - err.println("done."); - } - }); - } - - try { - analysis.run(); - } catch (Exception e) { - // e.printStackTrace(); - if (verbose) - err.println("liveness analysis may be inaccurate ..."); - } - ReversePtrs liveness = VM.getVM().getRevPtrs(); - - out.println("class_loader\tclasses\tbytes\tparent_loader\talive?\ttype"); - out.println(); - - long numClassLoaders = 1L; - long totalNumClasses = bootstrapLoaderData.numClasses; - long totalClassSize = bootstrapLoaderData.classSize; - long numAliveLoaders = 1L; - long numDeadLoaders = 0L; - - // print bootstrap loader details - out.print(""); - out.print('\t'); - out.print(bootstrapLoaderData.numClasses); - out.print('\t'); - out.print(bootstrapLoaderData.classSize); - out.print('\t'); - out.print(" null "); - out.print('\t'); - // bootstrap loader is always alive - out.print("live"); - out.print('\t'); - out.println(""); - - for (Iterator keyItr = loaderMap.keySet().iterator(); keyItr.hasNext();) { - Oop loader = (Oop) keyItr.next(); - LoaderData data = (LoaderData) loaderMap.get(loader); - numClassLoaders ++; - totalNumClasses += data.numClasses; - totalClassSize += data.classSize; - - out.print(loader.getHandle()); - out.print('\t'); - out.print(data.numClasses); - out.print('\t'); - out.print(data.classSize); - out.print('\t'); - - class ParentFinder extends DefaultOopVisitor { - public void doOop(OopField field, boolean isVMField) { - if (field.getID().getName().equals("parent")) { - parent = field.getValue(getObj()); - } - } - private Oop parent = null; - public Oop getParent() { return parent; } - } - - ParentFinder parentFinder = new ParentFinder(); - loader.iterate(parentFinder, false); - Oop parent = parentFinder.getParent(); - out.print((parent != null)? parent.getHandle().toString() : " null "); - out.print('\t'); - boolean alive = (liveness != null) ? (liveness.get(loader) != null) : true; - out.print(alive? "live" : "dead"); - if (alive) numAliveLoaders++; else numDeadLoaders++; - out.print('\t'); - Klass loaderKlass = loader.getKlass(); - if (loaderKlass != null) { - out.print(loaderKlass.getName().asString()); - out.print('@'); - out.print(loader.getKlass().getAddress()); - } else { - out.print(" null! "); - } - out.println(); - } - - out.println(); - // summary line - out.print("total = "); - out.print(numClassLoaders); - out.print('\t'); - out.print(totalNumClasses); - out.print('\t'); - out.print(totalClassSize); - out.print('\t'); - out.print(" N/A "); - out.print('\t'); - out.print("alive="); - out.print(numAliveLoaders); - out.print(", dead="); - out.print(numDeadLoaders); - out.print('\t'); - out.print(" N/A "); - out.println(); - } - - private static long objectSize(Oop oop) { - return oop == null ? 0L : oop.getObjectSize(); - } - - // Don't count the shared empty arrays - private static long arraySize(GenericArray arr) { - return arr.getLength() != 0L ? arr.getSize() : 0L; - } - - private long computeSize(InstanceKlass k) { - long size = 0L; - // the InstanceKlass object itself - size += k.getSize(); - - // Constant pool - ConstantPool cp = k.getConstants(); - size += cp.getSize(); - if (cp.getCache() != null) { - size += cp.getCache().getSize(); - } - size += arraySize(cp.getTags()); - - // Interfaces - size += arraySize(k.getLocalInterfaces()); - size += arraySize(k.getTransitiveInterfaces()); - - // Inner classes - size += arraySize(k.getInnerClasses()); - - // Fields - size += arraySize(k.getFields()); - - // Methods - MethodArray methods = k.getMethods(); - int nmethods = (int) methods.getLength(); - if (nmethods != 0L) { - size += methods.getSize(); - for (int i = 0; i < nmethods; ++i) { - Method m = methods.at(i); - size += m.getSize(); - size += m.getConstMethod().getSize(); - } - } - - return size; - } -} diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/tools/Tool.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/Tool.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/Tool.java Thu Mar 21 14:11:13 2013 +0100 @@ -27,7 +27,6 @@ import java.io.PrintStream; import java.util.Hashtable; import sun.jvm.hotspot.*; -import sun.jvm.hotspot.bugspot.*; import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.debugger.*; @@ -35,7 +34,7 @@ // override run & code main as shown below. public abstract class Tool implements Runnable { - private BugSpotAgent agent; + private HotSpotAgent agent; private int debugeeType; // debugeeType is one of constants below @@ -51,12 +50,7 @@ return true; } - // whether this tool requires debuggee to be java process or core? - protected boolean requiresVM() { - return true; - } - - protected void setAgent(BugSpotAgent a) { + protected void setAgent(HotSpotAgent a) { agent = a; } @@ -64,7 +58,7 @@ debugeeType = dt; } - protected BugSpotAgent getAgent() { + protected HotSpotAgent getAgent() { return agent; } @@ -155,7 +149,7 @@ usage(); } - agent = new BugSpotAgent(); + agent = new HotSpotAgent(); try { switch (debugeeType) { case DEBUGEE_PID: @@ -198,33 +192,24 @@ err.println("Debugger attached successfully."); - boolean isJava = agent.isJavaMode(); - if (isJava) { - VM vm = VM.getVM(); - if (vm.isCore()) { - err.println("Core build detected."); - } else if (vm.isClientCompiler()) { - err.println("Client compiler detected."); - } else if (vm.isServerCompiler()) { - err.println("Server compiler detected."); - } else { - throw new RuntimeException("Fatal error: " + - "should have been able to detect core/C1/C2 build"); - } + VM vm = VM.getVM(); + if (vm.isCore()) { + err.println("Core build detected."); + } else if (vm.isClientCompiler()) { + err.println("Client compiler detected."); + } else if (vm.isServerCompiler()) { + err.println("Server compiler detected."); + } else { + throw new RuntimeException("Fatal error: " + + "should have been able to detect core/C1/C2 build"); + } - String version = vm.getVMRelease(); - if (version != null) { - err.print("JVM version is "); - err.println(version); - } + String version = vm.getVMRelease(); + if (version != null) { + err.print("JVM version is "); + err.println(version); + } - run(); - } else { // not a java process or core - if (requiresVM()) { - err.println(getName() + " requires a java VM process/core!"); - } else { - run(); - } - } + run(); } } diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/ui/SAPanel.java --- a/agent/src/share/classes/sun/jvm/hotspot/ui/SAPanel.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/ui/SAPanel.java Thu Mar 21 14:11:13 2013 +0100 @@ -50,7 +50,7 @@ /** * This base class encapsulates many of the events that are fired from * the various panels in this directory so they can easily be plugged - * in to different containing frameworks (HSDB, BugSpot). + * in to different containing frameworks (HSDB). */ public class SAPanel extends JPanel { protected List listeners = new ArrayList(); diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java --- a/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -51,7 +51,6 @@ private static final int JVM_CONSTANT_UnresolvedClassInError = 103; // Resolution failed private static final int JVM_CONSTANT_MethodHandleInError = 104; // Error tag due to resolution error private static final int JVM_CONSTANT_MethodTypeInError = 105; // Error tag due to resolution error - private static final int JVM_CONSTANT_Object = 106; // Required for BoundMethodHandle arguments. // JVM_CONSTANT_MethodHandle subtypes //FIXME: connect these to data structure private static int JVM_REF_getField = 1; @@ -96,8 +95,6 @@ public boolean isKlassIndex() { return tag == JVM_CONSTANT_ClassIndex; } public boolean isStringIndex() { return tag == JVM_CONSTANT_StringIndex; } - public boolean isObject() { return tag == JVM_CONSTANT_Object; } - public boolean isKlassReference() { return isKlassIndex() || isUnresolvedKlass(); } public boolean isFieldOrMethod() { return isField() || isMethod() || isInterfaceMethod(); } public boolean isSymbol() { return isUtf8(); } @@ -123,7 +120,6 @@ case JVM_CONSTANT_StringIndex : case JVM_CONSTANT_MethodHandle : case JVM_CONSTANT_MethodType : - case JVM_CONSTANT_Object : return BasicType.T_OBJECT; default: throw new InternalError("unexpected tag: " + tag); diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js --- a/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js Thu Mar 21 11:30:38 2013 +0100 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js Thu Mar 21 14:11:13 2013 +0100 @@ -31,7 +31,6 @@ sapkg.hotspot = Packages.sun.jvm.hotspot; sapkg.asm = sapkg.hotspot.asm; -sapkg.bugspot = sapkg.hotspot.bugspot; sapkg.c1 = sapkg.hotspot.c1; sapkg.code = sapkg.hotspot.code; sapkg.compiler = sapkg.hotspot.compiler; @@ -40,7 +39,6 @@ // sapkg.debugger = sapkg.hotspot.debugger; sapkg.interpreter = sapkg.hotspot.interpreter; -sapkg.livejvm = sapkg.hotspot.livejvm; sapkg.jdi = sapkg.hotspot.jdi; sapkg.memory = sapkg.hotspot.memory; sapkg.oops = sapkg.hotspot.oops; diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/native/jvmdi/sa.cpp --- a/agent/src/share/native/jvmdi/sa.cpp Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,601 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * 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 -#include "sa.hpp" -#include "jni.h" -#include "jvmdi.h" - -#ifndef WIN32 - #include -#else - typedef int int32_t; -#endif - -#ifdef WIN32 - #include - #define YIELD() Sleep(0) - #define SLEEP() Sleep(10) - #define vsnprintf _vsnprintf -#else - Error: please port YIELD() and SLEEP() macros to your platform -#endif - -using namespace std; - -////////////////////////////////////////////////////////////////////// -// // -// Exported "interface" for Java language-level interaction between // -// the SA and the VM. Note that the SA knows about the layout of // -// certain VM data structures and that knowledge is taken advantage // -// of in this code, although this interfaces with the VM via JVMDI. // -// // -////////////////////////////////////////////////////////////////////// - -extern "C" { - ///////////////////////////////////// - // // - // Events sent by the VM to the SA // - // // - ///////////////////////////////////// - - // Set by the SA when it attaches. Indicates that events should be - // posted via these exported variables, and that the VM should wait - // for those events to be acknowledged by the SA (via its setting - // saEventPending to 0). - JNIEXPORT volatile int32_t saAttached = 0; - - // Set to nonzero value by the VM when an event has been posted; set - // back to 0 by the SA when it has processed that event. - JNIEXPORT volatile int32_t saEventPending = 0; - - // Kind of the event (from jvmdi.h) - JNIEXPORT volatile int32_t saEventKind = 0; - - // - // Exception events - // - JNIEXPORT jthread saExceptionThread; - JNIEXPORT jclass saExceptionClass; - JNIEXPORT jmethodID saExceptionMethod; - JNIEXPORT int32_t saExceptionLocation; - JNIEXPORT jobject saExceptionException; - JNIEXPORT jclass saExceptionCatchClass; - JNIEXPORT jmethodID saExceptionCatchMethod; - JNIEXPORT int32_t saExceptionCatchLocation; - - // - // Breakpoint events - // - JNIEXPORT jthread saBreakpointThread; - JNIEXPORT jclass saBreakpointClass; - JNIEXPORT jmethodID saBreakpointMethod; - JNIEXPORT jlocation saBreakpointLocation; - - /////////////////////////////////////// - // // - // Commands sent by the SA to the VM // - // // - /////////////////////////////////////// - - extern JNIEXPORT const int32_t SA_CMD_SUSPEND_ALL = 0; - extern JNIEXPORT const int32_t SA_CMD_RESUME_ALL = 1; - extern JNIEXPORT const int32_t SA_CMD_TOGGLE_BREAKPOINT = 2; - extern JNIEXPORT const int32_t SA_CMD_BUF_SIZE = 1024; - - // SA sets this to a nonzero value when it is requesting a command - // to be processed; VM sets it back to 0 when the command has been - // executed - JNIEXPORT volatile int32_t saCmdPending = 0; - - // SA sets this to one of the manifest constants above to indicate - // the kind of command to be executed - JNIEXPORT volatile int32_t saCmdType = 0; - - // VM sets this to 0 if the last command succeeded or a nonzero - // value if it failed - JNIEXPORT volatile int32_t saCmdResult = 0; - - // If last command failed, this buffer will contain a descriptive - // error message - JNIEXPORT char saCmdResultErrMsg[SA_CMD_BUF_SIZE]; - - // - // Toggling of breakpoint command arguments. - // - // Originally there were separate set/clear breakpoint commands - // taking a class name, method name and signature, and the iteration - // through the debug information was done in the SA. It turns out - // that doing this work in the target VM is significantly faster, - // and since interactivity when setting and clearing breakpoints is - // important, the solution which resulted in more C/C++ code was used. - // - - // Source file name - JNIEXPORT char saCmdBkptSrcFileName[SA_CMD_BUF_SIZE]; - - // Package name ('/' as separator instead of '.') - JNIEXPORT char saCmdBkptPkgName[SA_CMD_BUF_SIZE]; - - // Line number - JNIEXPORT int32_t saCmdBkptLineNumber; - - // Output back to SA: indicator whether the last failure of a - // breakpoint toggle command was really an error or just a lack of - // debug information covering the requested line. 0 if not error. - // Valid only if saCmdResult != 0. - JNIEXPORT int32_t saCmdBkptResWasError; - - // Output back to SA: resulting line number at which the breakpoint - // was set or cleared (valid only if saCmdResult == 0) - JNIEXPORT int32_t saCmdBkptResLineNumber; - - // Output back to SA: resulting byte code index at which the - // breakpoint was set or cleared (valid only if saCmdResult == 0) - JNIEXPORT int32_t saCmdBkptResBCI; - - // Output back to SA: indicator whether the breakpoint operation - // resulted in a set or cleared breakpoint; nonzero if set, zero if - // cleared (valid only if saCmdResult == 0) - JNIEXPORT int32_t saCmdBkptResWasSet; - - // Output back to SA: method name the breakpoint was set in (valid - // only if saCmdResult == 0) - JNIEXPORT char saCmdBkptResMethodName[SA_CMD_BUF_SIZE]; - - // Output back to SA: method signature (JNI style) the breakpoint - // was set in (valid only if saCmdResult == 0) - JNIEXPORT char saCmdBkptResMethodSig[SA_CMD_BUF_SIZE]; -} - -// Internal state -static JavaVM* jvm = NULL; -static JVMDI_Interface_1* jvmdi = NULL; -static jthread debugThreadObj = NULL; -static bool suspended = false; -static vector suspendedThreads; -static JVMDI_RawMonitor eventLock = NULL; - -class MonitorLocker { -private: - JVMDI_RawMonitor lock; -public: - MonitorLocker(JVMDI_RawMonitor lock) { - this->lock = lock; - if (lock != NULL) { - jvmdi->RawMonitorEnter(lock); - } - } - ~MonitorLocker() { - if (lock != NULL) { - jvmdi->RawMonitorExit(lock); - } - } -}; - -class JvmdiDeallocator { -private: - void* ptr; -public: - JvmdiDeallocator(void* ptr) { - this->ptr = ptr; - } - ~JvmdiDeallocator() { - jvmdi->Deallocate((jbyte*) ptr); - } -}; - -class JvmdiRefListDeallocator { -private: - JNIEnv* env; - jobject* refList; - jint refCount; -public: - JvmdiRefListDeallocator(JNIEnv* env, jobject* refList, jint refCount) { - this->env = env; - this->refList = refList; - this->refCount = refCount; - } - ~JvmdiRefListDeallocator() { - for (int i = 0; i < refCount; i++) { - env->DeleteGlobalRef(refList[i]); - } - jvmdi->Deallocate((jbyte*) refList); - } -}; - -static void -stop(char* msg) { - fprintf(stderr, "%s", msg); - fprintf(stderr, "\n"); - exit(1); -} - -// This fills in the command result error message, sets the command -// result to -1, and clears the pending command flag -static void -reportErrorToSA(const char* str, ...) { - va_list varargs; - va_start(varargs, str); - vsnprintf(saCmdResultErrMsg, sizeof(saCmdResultErrMsg), str, varargs); - va_end(varargs); - saCmdResult = -1; - saCmdPending = 0; -} - -static bool -packageNameMatches(char* clazzName, char* pkg) { - int pkgLen = strlen(pkg); - int clazzNameLen = strlen(clazzName); - - if (pkgLen >= clazzNameLen + 1) { - return false; - } - - if (strncmp(clazzName, pkg, pkgLen)) { - return false; - } - - // Ensure that '/' is the next character if non-empty package name - int l = pkgLen; - if (l > 0) { - if (clazzName[l] != '/') { - return false; - } - l++; - } - // Ensure that there are no more trailing slashes - while (l < clazzNameLen) { - if (clazzName[l++] == '/') { - return false; - } - } - return true; -} - -static void -executeOneCommand(JNIEnv* env) { - switch (saCmdType) { - case SA_CMD_SUSPEND_ALL: { - if (suspended) { - reportErrorToSA("Target process already suspended"); - return; - } - - // We implement this by getting all of the threads and calling - // SuspendThread on each one, except for the thread object - // corresponding to this thread. Each thread for which the call - // succeeded (i.e., did not return JVMDI_ERROR_INVALID_THREAD) - // is added to a list which is remembered for later resumption. - // Note that this currently has race conditions since a thread - // might be started after we call GetAllThreads and since a - // thread for which we got an error earlier might be resumed by - // the VM while we are busy suspending other threads. We could - // solve this by looping until there are no more threads we can - // suspend, but a more robust and scalable solution is to add - // this functionality to the JVMDI interface (i.e., - // "suspendAll"). Probably need to provide an exclude list for - // such a routine. - jint threadCount; - jthread* threads; - if (jvmdi->GetAllThreads(&threadCount, &threads) != JVMDI_ERROR_NONE) { - reportErrorToSA("Error while getting thread list"); - return; - } - - - for (int i = 0; i < threadCount; i++) { - jthread thr = threads[i]; - if (!env->IsSameObject(thr, debugThreadObj)) { - jvmdiError err = jvmdi->SuspendThread(thr); - if (err == JVMDI_ERROR_NONE) { - // Remember this thread and do not free it - suspendedThreads.push_back(thr); - continue; - } else { - fprintf(stderr, " SA: Error %d while suspending thread\n", err); - // FIXME: stop, resume all threads, report error - } - } - env->DeleteGlobalRef(thr); - } - - // Free up threads - jvmdi->Deallocate((jbyte*) threads); - - // Suspension is complete - suspended = true; - break; - } - - case SA_CMD_RESUME_ALL: { - if (!suspended) { - reportErrorToSA("Target process already suspended"); - return; - } - - saCmdResult = 0; - bool errorOccurred = false; - jvmdiError firstError; - for (int i = 0; i < suspendedThreads.size(); i++) { - jthread thr = suspendedThreads[i]; - jvmdiError err = jvmdi->ResumeThread(thr); - env->DeleteGlobalRef(thr); - if (err != JVMDI_ERROR_NONE) { - if (!errorOccurred) { - errorOccurred = true; - firstError = err; - } - } - } - suspendedThreads.clear(); - suspended = false; - if (errorOccurred) { - reportErrorToSA("Error %d while resuming threads", firstError); - return; - } - break; - } - - case SA_CMD_TOGGLE_BREAKPOINT: { - saCmdBkptResWasError = 1; - - // Search line number info for all loaded classes - jint classCount; - jclass* classes; - - jvmdiError glcRes = jvmdi->GetLoadedClasses(&classCount, &classes); - if (glcRes != JVMDI_ERROR_NONE) { - reportErrorToSA("Error %d while getting loaded classes", glcRes); - return; - } - JvmdiRefListDeallocator rld(env, (jobject*) classes, classCount); - - bool done = false; - bool gotOne = false; - jclass targetClass; - jmethodID targetMethod; - jlocation targetLocation; - jint targetLineNumber; - - for (int i = 0; i < classCount && !done; i++) { - fflush(stderr); - jclass clazz = classes[i]; - char* srcName; - jvmdiError sfnRes = jvmdi->GetSourceFileName(clazz, &srcName); - if (sfnRes == JVMDI_ERROR_NONE) { - JvmdiDeallocator de1(srcName); - if (!strcmp(srcName, saCmdBkptSrcFileName)) { - // Got a match. Now see whether the package name of the class also matches - char* clazzName; - jvmdiError sigRes = jvmdi->GetClassSignature(clazz, &clazzName); - if (sigRes != JVMDI_ERROR_NONE) { - reportErrorToSA("Error %d while getting a class's signature", sigRes); - return; - } - JvmdiDeallocator de2(clazzName); - if (packageNameMatches(clazzName + 1, saCmdBkptPkgName)) { - // Iterate through all methods - jint methodCount; - jmethodID* methods; - if (jvmdi->GetClassMethods(clazz, &methodCount, &methods) != JVMDI_ERROR_NONE) { - reportErrorToSA("Error while getting methods of class %s", clazzName); - return; - } - JvmdiDeallocator de3(methods); - for (int j = 0; j < methodCount && !done; j++) { - jmethodID m = methods[j]; - jint entryCount; - JVMDI_line_number_entry* table; - jvmdiError lnRes = jvmdi->GetLineNumberTable(clazz, m, &entryCount, &table); - if (lnRes == JVMDI_ERROR_NONE) { - JvmdiDeallocator de4(table); - // Look for line number greater than or equal to requested line - for (int k = 0; k < entryCount && !done; k++) { - JVMDI_line_number_entry& entry = table[k]; - if (entry.line_number >= saCmdBkptLineNumber && - (!gotOne || entry.line_number < targetLineNumber)) { - gotOne = true; - targetClass = clazz; - targetMethod = m; - targetLocation = entry.start_location; - targetLineNumber = entry.line_number; - done = (targetLineNumber == saCmdBkptLineNumber); - } - } - } else if (lnRes != JVMDI_ERROR_ABSENT_INFORMATION) { - reportErrorToSA("Unexpected error %d while fetching line number table", lnRes); - return; - } - } - } - } - } else if (sfnRes != JVMDI_ERROR_ABSENT_INFORMATION) { - reportErrorToSA("Unexpected error %d while fetching source file name", sfnRes); - return; - } - } - - bool wasSet = true; - if (gotOne) { - // Really toggle this breakpoint - jvmdiError bpRes; - bpRes = jvmdi->SetBreakpoint(targetClass, targetMethod, targetLocation); - if (bpRes == JVMDI_ERROR_DUPLICATE) { - bpRes = jvmdi->ClearBreakpoint(targetClass, targetMethod, targetLocation); - wasSet = false; - } - if (bpRes != JVMDI_ERROR_NONE) { - reportErrorToSA("Unexpected error %d while setting or clearing breakpoint at bci %d, line %d", - bpRes, targetLocation, targetLineNumber); - return; - } - } else { - saCmdBkptResWasError = 0; - reportErrorToSA("No debug information found covering this line"); - return; - } - - // Provide result - saCmdBkptResLineNumber = targetLineNumber; - saCmdBkptResBCI = targetLocation; - saCmdBkptResWasSet = (wasSet ? 1 : 0); - { - char* methodName; - char* methodSig; - if (jvmdi->GetMethodName(targetClass, targetMethod, &methodName, &methodSig) - == JVMDI_ERROR_NONE) { - JvmdiDeallocator mnd(methodName); - JvmdiDeallocator msd(methodSig); - strncpy(saCmdBkptResMethodName, methodName, SA_CMD_BUF_SIZE); - strncpy(saCmdBkptResMethodSig, methodSig, SA_CMD_BUF_SIZE); - } else { - strncpy(saCmdBkptResMethodName, "", SA_CMD_BUF_SIZE); - strncpy(saCmdBkptResMethodSig, "", SA_CMD_BUF_SIZE); - } - } - break; - } - - default: - reportErrorToSA("Command %d not yet supported", saCmdType); - return; - } - - // Successful command execution - saCmdResult = 0; - saCmdPending = 0; -} - -static void -saCommandThread(void *arg) { - JNIEnv* env = NULL; - if (jvm->GetEnv((void **) &env, JNI_VERSION_1_2) != JNI_OK) { - stop("Error while starting Serviceability Agent " - "command thread: could not get JNI environment"); - } - - while (1) { - // Wait for command - while (!saCmdPending) { - SLEEP(); - } - - executeOneCommand(env); - } -} - -static void -saEventHook(JNIEnv *env, JVMDI_Event *event) -{ - MonitorLocker ml(eventLock); - - saEventKind = event->kind; - - if (event->kind == JVMDI_EVENT_VM_INIT) { - // Create event lock - if (jvmdi->CreateRawMonitor("Serviceability Agent Event Lock", &eventLock) - != JVMDI_ERROR_NONE) { - stop("Unable to create Serviceability Agent's event lock"); - } - // Start thread which receives commands from the SA. - jclass threadClass = env->FindClass("java/lang/Thread"); - if (threadClass == NULL) stop("Unable to find class java/lang/Thread"); - jstring threadName = env->NewStringUTF("Serviceability Agent Command Thread"); - if (threadName == NULL) stop("Unable to allocate debug thread name"); - jmethodID ctor = env->GetMethodID(threadClass, "", "(Ljava/lang/String;)V"); - if (ctor == NULL) stop("Unable to find appropriate constructor for java/lang/Thread"); - // Allocate thread object - jthread thr = (jthread) env->NewObject(threadClass, ctor, threadName); - if (thr == NULL) stop("Unable to allocate debug thread's java/lang/Thread instance"); - // Remember which thread this is - debugThreadObj = env->NewGlobalRef(thr); - if (debugThreadObj == NULL) stop("Unable to allocate global ref for debug thread object"); - // Start thread - jvmdiError err; - if ((err = jvmdi->RunDebugThread(thr, &saCommandThread, NULL, JVMDI_THREAD_NORM_PRIORITY)) - != JVMDI_ERROR_NONE) { - char buf[256]; - sprintf(buf, "Error %d while starting debug thread", err); - stop(buf); - } - // OK, initialization is done - return; - } - - if (!saAttached) { - return; - } - - switch (event->kind) { - case JVMDI_EVENT_EXCEPTION: { - fprintf(stderr, "SA: Exception thrown -- ignoring\n"); - saExceptionThread = event->u.exception.thread; - saExceptionClass = event->u.exception.clazz; - saExceptionMethod = event->u.exception.method; - saExceptionLocation = event->u.exception.location; - saExceptionException = event->u.exception.exception; - saExceptionCatchClass = event->u.exception.catch_clazz; - saExceptionCatchClass = event->u.exception.catch_clazz; - saExceptionCatchMethod = event->u.exception.catch_method; - saExceptionCatchLocation = event->u.exception.catch_location; - // saEventPending = 1; - break; - } - - case JVMDI_EVENT_BREAKPOINT: { - saBreakpointThread = event->u.breakpoint.thread; - saBreakpointClass = event->u.breakpoint.clazz; - saBreakpointMethod = event->u.breakpoint.method; - saBreakpointLocation = event->u.breakpoint.location; - saEventPending = 1; - break; - } - - default: - break; - } - - while (saAttached && saEventPending) { - SLEEP(); - } -} - -extern "C" { -JNIEXPORT jint JNICALL -JVM_OnLoad(JavaVM *vm, char *options, void *reserved) -{ - jvm = vm; - if (jvm->GetEnv((void**) &jvmdi, JVMDI_VERSION_1) != JNI_OK) { - return -1; - } - if (jvmdi->SetEventHook(&saEventHook) != JVMDI_ERROR_NONE) { - return -1; - } - return 0; -} -}; diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/native/jvmdi/sa.dsp --- a/agent/src/share/native/jvmdi/sa.dsp Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -# Microsoft Developer Studio Project File - Name="sa" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=sa - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "sa.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "sa.mak" CFG="sa - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "sa - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "sa - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "sa - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SA_EXPORTS" /YX /FD /c -# ADD CPP /nologo /MT /W3 /GX /O2 /I "D:\jdk1.4\include" /I "D:\jdk1.4\include\win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SA_EXPORTS" /YX /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 - -!ELSEIF "$(CFG)" == "sa - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SA_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "D:\jdk1.4\include" /I "D:\jdk1.4\include\win32" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SA_EXPORTS" /YX /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "sa - Win32 Release" -# Name "sa - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\sa.cpp -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/native/jvmdi/sa.dsw --- a/agent/src/share/native/jvmdi/sa.dsw Thu Mar 21 11:30:38 2013 +0100 +++ /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: "sa"=.\sa.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff -r dee7c8b578c7 -r c3657d00e343 agent/src/share/native/jvmdi/sa.hpp --- a/agent/src/share/native/jvmdi/sa.hpp Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * 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 "jni.h" - -extern "C" { -JNIEXPORT jint JNICALL -JVM_OnLoad(JavaVM *vm, char *options, void *reserved); -} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java --- a/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java Thu Mar 21 14:11:13 2013 +0100 @@ -133,7 +133,7 @@ // scheduled. double unscheduledSum = 0.0; for (Block pred : mostLikelySuccessor.getPredecessors()) { - if (!visitedBlocks.get(pred.getId())) { + if (pred.getLinearScanNumber() == -1) { unscheduledSum += pred.getBeginNode().probability(); } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java --- a/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,12 +24,11 @@ import static com.oracle.graal.api.code.MemoryBarriers.*; import static com.oracle.graal.api.code.Register.RegisterFlag.*; -import static com.oracle.graal.api.meta.Kind.*; import java.nio.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.Register.*; +import com.oracle.graal.api.code.Register.RegisterFlag; /** * Represents the AMD64 architecture. @@ -106,8 +105,6 @@ rip }; - public static final RegisterValue RSP = rsp.asValue(Long); - public AMD64() { super("AMD64", 8, diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/AbstractAddress.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/AbstractAddress.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,29 @@ +/* + * 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; + +/** + * Abstract base class that represents a platform specific address. + */ +public abstract class AbstractAddress { +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Address.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Address.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,206 +0,0 @@ -/* - * Copyright (c) 2010, 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.api.code; - -import static com.oracle.graal.api.code.ValueUtil.*; - -import com.oracle.graal.api.meta.*; - -/** - * Represents an address in target machine memory, specified via some combination of a base - * register, an index register, a displacement and a scale. Note that the base and index registers - * may be a variable that will get a register assigned later by the register allocator. - */ -public final class Address extends Value { - - private static final long serialVersionUID = -1003772042519945089L; - - /** - * A sentinel value used as a place holder in an instruction stream for an address that will be - * patched. - */ - public static final Address Placeholder = new Address(Kind.Illegal, Value.ILLEGAL); - - private Value base; - private Value index; - private final Scale scale; - private final int displacement; - - /** - * Creates an {@link Address} with given base register, no scaling and no displacement. - * - * @param kind the kind of the value being addressed - * @param base the base register - */ - public Address(Kind kind, Value base) { - this(kind, base, ILLEGAL, Scale.Times1, 0); - } - - /** - * Creates an {@link Address} with given base register, no scaling and a given displacement. - * - * @param kind the kind of the value being addressed - * @param base the base register - * @param displacement the displacement - */ - public Address(Kind kind, Value base, int displacement) { - this(kind, base, ILLEGAL, Scale.Times1, displacement); - } - - /** - * Creates an {@link Address} with given base and index registers, scaling and displacement. - * This is the most general constructor. - * - * @param kind the kind of the value being addressed - * @param base the base register - * @param index the index register - * @param scale the scaling factor - * @param displacement the displacement - */ - public Address(Kind kind, Value base, Value index, Scale scale, int displacement) { - super(kind); - this.setBase(base); - this.setIndex(index); - this.scale = scale; - this.displacement = displacement; - - assert !isConstant(base) && !isStackSlot(base); - assert !isConstant(index) && !isStackSlot(index); - } - - /** - * A scaling factor used in complex addressing modes such as those supported by x86 platforms. - */ - public enum Scale { - Times1(1, 0), Times2(2, 1), Times4(4, 2), Times8(8, 3); - - private Scale(int value, int log2) { - this.value = value; - this.log2 = log2; - } - - /** - * The value (or multiplier) of this scale. - */ - public final int value; - - /** - * The {@linkplain #value value} of this scale log 2. - */ - public final int log2; - - public static Scale fromInt(int scale) { - switch (scale) { - case 1: - return Times1; - case 2: - return Times2; - case 4: - return Times4; - case 8: - return Times8; - default: - throw new IllegalArgumentException(String.valueOf(scale)); - } - } - } - - @Override - public String toString() { - if (this == Placeholder) { - return "[]"; - } - - StringBuilder s = new StringBuilder(); - s.append(getKind().getJavaName()).append("["); - String sep = ""; - if (isLegal(getBase())) { - s.append(getBase()); - sep = " + "; - } - if (isLegal(getIndex())) { - s.append(sep).append(getIndex()).append(" * ").append(getScale().value); - sep = " + "; - } - if (getDisplacement() < 0) { - s.append(" - ").append(-getDisplacement()); - } else if (getDisplacement() > 0) { - s.append(sep).append(getDisplacement()); - } - s.append("]"); - return s.toString(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof Address) { - Address addr = (Address) obj; - return getKind() == addr.getKind() && getDisplacement() == addr.getDisplacement() && getBase().equals(addr.getBase()) && getScale() == addr.getScale() && - getIndex().equals(addr.getIndex()); - } - return false; - } - - @Override - public int hashCode() { - return getBase().hashCode() ^ getIndex().hashCode() ^ (getDisplacement() << 4) ^ (getScale().value << 8) ^ (getKind().ordinal() << 12); - } - - /** - * @return Base register that defines the start of the address computation. If not present, is - * denoted by {@link Value#ILLEGAL}. - */ - public Value getBase() { - return base; - } - - public void setBase(Value base) { - this.base = base; - } - - /** - * @return Index register, the value of which (possibly scaled by {@link #scale}) is added to - * {@link #base}. If not present, is denoted by {@link Value#ILLEGAL}. - */ - public Value getIndex() { - return index; - } - - public void setIndex(Value index) { - this.index = index; - } - - /** - * @return Scaling factor for indexing, dependent on target operand size. - */ - public Scale getScale() { - return scale; - } - - /** - * @return Optional additive displacement. - */ - public int getDisplacement() { - return displacement; - } -} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/AllocatableValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/AllocatableValue.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,50 @@ +/* + * 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; + +import com.oracle.graal.api.meta.*; + +/** + * Common base class for values that can be manipulated by the register allocator. + */ +public abstract class AllocatableValue extends Value { + + private static final long serialVersionUID = 153019506717492133L; + + /** + * Marker to tell the register allocator that no storage location needs to be allocated for this + * value. + */ + @SuppressWarnings("serial") public static final AllocatableValue UNUSED = new AllocatableValue(Kind.Illegal) { + + @Override + public String toString() { + return "-"; + } + }; + + public AllocatableValue(Kind kind) { + super(kind); + } + +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Architecture.java Thu Mar 21 14:11:13 2013 +0100 @@ -23,9 +23,6 @@ package com.oracle.graal.api.code; import java.nio.*; -import java.util.*; - -import com.oracle.graal.api.code.Register.RegisterFlag; /** * Represents a CPU architecture, including information such as its endianness, CPU registers, word @@ -79,22 +76,6 @@ */ private final int returnAddressSize; - private final EnumMap registersByTypeAndEncoding; - - /** - * Gets the register for a given {@linkplain Register#encoding encoding} and type. - * - * @param encoding a register value as used in a machine instruction - * @param type the type of the register - */ - public Register registerFor(int encoding, RegisterFlag type) { - Register[] regs = registersByTypeAndEncoding.get(type); - assert encoding >= 0 && encoding < regs.length; - Register reg = regs[encoding]; - assert reg != null; - return reg; - } - protected Architecture(String name, int wordSize, ByteOrder byteOrder, Register[] registers, int implicitMemoryBarriers, int nativeCallDisplacementOffset, int registerReferenceMapBitCount, int returnAddressSize) { this.name = name; @@ -105,18 +86,6 @@ this.machineCodeCallDisplacementOffset = nativeCallDisplacementOffset; this.registerReferenceMapBitCount = registerReferenceMapBitCount; this.returnAddressSize = returnAddressSize; - - registersByTypeAndEncoding = new EnumMap<>(RegisterFlag.class); - EnumMap categorizedRegs = Register.categorize(registers); - for (RegisterFlag type : RegisterFlag.values()) { - Register[] regs = categorizedRegs.get(type); - int max = Register.maxRegisterEncoding(regs); - Register[] regsByEnc = new Register[max + 1]; - for (Register reg : regs) { - regsByEnc[reg.encoding] = reg; - } - registersByTypeAndEncoding.put(type, regsByEnc); - } } /** @@ -161,14 +130,6 @@ } /** - * Gets a mask of the barrier constants denoting the barriers that are not required to be - * explicitly inserted under this architecture. - */ - public int getImplicitMemoryBarriers() { - return implicitMemoryBarriers; - } - - /** * Gets the size of the return address pushed to the stack by a call instruction. A value of 0 * denotes that call linkage uses registers instead. */ diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeCacheProvider.java Thu Mar 21 14:11:13 2013 +0100 @@ -37,12 +37,10 @@ * * @param method a method to which the executable code is begin added * @param compResult the compilation result to be added - * @param info the object into which details of the installed code will be written. Ignored if - * null, otherwise the info is written to index 0 of this array. * @return a reference to the compiled and ready-to-run code or null if the code installation * failed */ - InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, CodeInfo[] info); + InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult); /** * Returns the size in bytes for locking information on the stack. @@ -50,20 +48,21 @@ int getSizeOfLockData(); /** - * Returns a disassembly of the given installed code. + * Returns a disassembly of some compiled code. * - * @param code the code that should be disassembled + * @param compResult some compiled code + * @param installedCode the result of installing the code in {@code compResult} or null if the + * code has not yet been installed + * * @return a disassembly. This will be of length 0 if the runtime does not support * disassembling. */ - String disassemble(CodeInfo code, CompilationResult tm); + String disassemble(CompilationResult compResult, InstalledCode installedCode); /** * Gets the register configuration to use when compiling a given method. - * - * @param method the top level method of a compilation */ - RegisterConfig lookupRegisterConfig(ResolvedJavaMethod method); + RegisterConfig lookupRegisterConfig(); /** * Custom area on the stack of each compiled method that the VM can use for its own purposes. @@ -81,11 +80,6 @@ int getMinimumOutgoingSize(); /** - * Performs any runtime-specific conversion on the object used to describe the target of a call. - */ - Object lookupCallTarget(Object callTarget); - - /** * Gets the signature and linkage information for a runtime call. */ RuntimeCallTarget lookupRuntimeCall(Descriptor descriptor); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeInfo.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeInfo.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +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.api.code; - -import com.oracle.graal.api.meta.*; - -/** - * Represents some code installed in the code cache of the runtime. This encapsulated details are - * only for informational purposes. At any time, the runtime may invalidate the underlying code - * (e.g. due to deopt etc). - */ -public interface CodeInfo { - - /** - * Returns the start address of this installed code. - */ - long getStart(); - - /** - * Returns a copy of this installed code. - */ - byte[] getCode(); - - /** - * Returns the method (if any) from which this installed code was compiled. - */ - ResolvedJavaMethod getMethod(); -} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CodeUtil.java Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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,6 +22,7 @@ */ package com.oracle.graal.api.code; +import java.lang.reflect.*; import java.util.*; import com.oracle.graal.api.meta.*; @@ -310,4 +311,19 @@ } return sb; } + + /** + * Create a calling convention from a {@link ResolvedJavaMethod}. + */ + public static CallingConvention getCallingConvention(CodeCacheProvider codeCache, CallingConvention.Type type, ResolvedJavaMethod method, boolean stackOnly) { + Signature sig = method.getSignature(); + JavaType retType = sig.getReturnType(null); + JavaType[] argTypes = new JavaType[sig.getParameterCount(!Modifier.isStatic(method.getModifiers()))]; + for (int i = 0; i < argTypes.length; i++) { + argTypes[i] = sig.getParameterType(i, null); + } + + RegisterConfig registerConfig = codeCache.lookupRegisterConfig(); + return registerConfig.getCallingConvention(type, retType, argTypes, codeCache.getTarget(), stackOnly); + } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java Thu Mar 21 14:11:13 2013 +0100 @@ -94,7 +94,7 @@ /** * The target of the call. */ - public final Object target; + public final InvokeTarget target; /** * The size of the call instruction. @@ -108,7 +108,7 @@ */ public final boolean direct; - public Call(Object target, int pcOffset, int size, boolean direct, DebugInfo debugInfo) { + public Call(InvokeTarget target, int pcOffset, int size, boolean direct, DebugInfo debugInfo) { super(pcOffset, debugInfo); this.size = size; this.target = target; @@ -196,25 +196,6 @@ } /** - * Labels some inline data in the code. - */ - public static final class InlineData extends CodeAnnotation { - - private static final long serialVersionUID = 305997507263827108L; - public final int size; - - public InlineData(int position, int size) { - super(position); - this.size = size; - } - - @Override - public String toString() { - return getClass().getSimpleName() + "@" + position + ": size=" + size; - } - } - - /** * Describes a table of signed offsets embedded in the code. The offsets are relative to the * starting address of the table. This type of table maybe generated when translating a * multi-way branch based on a key value from a dense value set (e.g. the {@code tableswitch} @@ -256,43 +237,6 @@ } /** - * Describes a table of key and offset pairs. The offset in each table entry is relative to the - * address of the table. This type of table maybe generated when translating a multi-way branch - * based on a key value from a sparse value set (e.g. the {@code lookupswitch} JVM instruction). - */ - public static final class LookupTable extends CodeAnnotation { - - private static final long serialVersionUID = 8367952567559116160L; - - /** - * The number of entries in the table. - */ - public final int npairs; - - /** - * The size (in bytes) of entry's key. - */ - public final int keySize; - - /** - * The size (in bytes) of entry's offset value. - */ - public final int offsetSize; - - public LookupTable(int position, int npairs, int keySize, int offsetSize) { - super(position); - this.npairs = npairs; - this.keySize = keySize; - this.offsetSize = offsetSize; - } - - @Override - public String toString() { - return getClass().getSimpleName() + "@" + position + ": [npairs=" + npairs + ", keySize=" + keySize + ", offsetSize=" + offsetSize + "]"; - } - } - - /** * Represents exception handler information for a specific code position. It includes the catch * code position as well as the caught exception type. */ @@ -349,8 +293,6 @@ private int customStackAreaOffset = -1; private int registerRestoreEpilogueOffset = -1; - private CalleeSaveLayout calleeSaveLayout; - /** * The buffer containing the emitted machine code. */ @@ -410,15 +352,6 @@ } /** - * Sets the info on callee-saved registers used by this method. - * - * @param csl the register-saving info. - */ - public void setCalleeSaveLayout(CalleeSaveLayout csl) { - calleeSaveLayout = csl; - } - - /** * Records a reference to the data section in the code section (e.g. to load an integer or * floating point constant). * @@ -438,11 +371,11 @@ * * @param codePos the position of the call in the code array * @param size the size of the call instruction - * @param target the {@link CodeCacheProvider#lookupCallTarget(Object) target} being called + * @param target the being called * @param debugInfo the debug info for the call * @param direct specifies if this is a {@linkplain Call#direct direct} call */ - public void recordCall(int codePos, int size, Object target, DebugInfo debugInfo, boolean direct) { + 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); } @@ -537,13 +470,6 @@ } /** - * @return the layout information for callee-saved registers used by this method. - */ - public CalleeSaveLayout getCalleeSaveLayout() { - return calleeSaveLayout; - } - - /** * @return the machine code generated for this method */ public byte[] getTargetCode() { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java Thu Mar 21 14:11:13 2013 +0100 @@ -36,6 +36,7 @@ private final BytecodePosition bytecodePosition; private final BitSet registerRefMap; private final BitSet frameRefMap; + private final short deoptimizationReason; /** * Creates a new {@link DebugInfo} from the given values. @@ -45,10 +46,11 @@ * @param registerRefMap the register map * @param frameRefMap the reference map for {@code frame}, which may be {@code null} */ - public DebugInfo(BytecodePosition codePos, BitSet registerRefMap, BitSet frameRefMap) { + public DebugInfo(BytecodePosition codePos, BitSet registerRefMap, BitSet frameRefMap, short deoptimizationReason) { this.bytecodePosition = codePos; this.registerRefMap = registerRefMap; this.frameRefMap = frameRefMap; + this.deoptimizationReason = deoptimizationReason; } /** @@ -114,4 +116,13 @@ public BitSet getFrameRefMap() { return frameRefMap; } + + /** + * Identifies the reason in case a deoptimization happens at this program counter. + * + * @return the reason of the deoptimization + */ + public short getDeoptimizationReason() { + return deoptimizationReason; + } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DisassemblerProvider.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DisassemblerProvider.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DisassemblerProvider.java Thu Mar 21 14:11:13 2013 +0100 @@ -29,6 +29,10 @@ /** * Gets a textual disassembly of some given installed code. + * + * @return a non-zero length string containing a disassembly of {@code code} or null if + * {@code code} is {@link InstalledCode#isValid() invalid} or it could not be + * disassembled for some other reason */ String disassemble(InstalledCode code); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/InstalledCode.java Thu Mar 21 14:11:13 2013 +0100 @@ -39,11 +39,22 @@ } /** - * Returns the method to which the compiled code belongs. + * Returns the method (if any) to which the installed code belongs. */ ResolvedJavaMethod getMethod(); /** + * Returns the start address of this installed code if it is {@linkplain #isValid() valid}, 0 + * otherwise. + */ + long getStart(); + + /** + * Returns a copy of this installed code if it is {@linkplain #isValid() valid}, null otherwise. + */ + byte[] getCode(); + + /** * @return true if the code represented by this object is still valid, false otherwise (may * happen due to deopt, etc.) */ diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Register.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Register.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Register.java Thu Mar 21 14:11:13 2013 +0100 @@ -65,6 +65,13 @@ public final int encoding; /** + * The assembler calls this method to get the register's encoding. + */ + public int encoding() { + return encoding; + } + + /** * The size of the stack slot used to spill the value of this register. */ public final int spillSlotSize; diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterConfig.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterConfig.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterConfig.java Thu Mar 21 14:11:13 2013 +0100 @@ -44,8 +44,6 @@ */ Register getFrameRegister(); - Register getScratchRegister(); - /** * Gets the calling convention describing how arguments are passed. * diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterValue.java Thu Mar 21 14:11:13 2013 +0100 @@ -30,7 +30,7 @@ * {@link Register#asValue(Kind)} to retrieve the canonical {@link RegisterValue} instance for a * given (register,kind) pair. */ -public final class RegisterValue extends Value { +public final class RegisterValue extends AllocatableValue { private static final long serialVersionUID = 7999341472196897163L; diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RuntimeCallTarget.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,11 +24,13 @@ import java.util.*; +import com.oracle.graal.api.meta.*; + /** * The name, signature and calling convention of a call from compiled code to the runtime. The * target of such a call may be a leaf stub or a call into the runtime code proper. */ -public interface RuntimeCallTarget { +public interface RuntimeCallTarget extends InvokeTarget { /** * The name and signature of a runtime call. diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/SpeculationLog.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/SpeculationLog.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,74 @@ +/* + * 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.api.code; + +import java.util.*; + +import com.oracle.graal.api.meta.*; + +/** + * Manages a list of unique deoptimization reasons and returns a unique index for each reason. This + * class is not thread safe and assumes that at every point in time there is only a single Graal + * compilation accessing this object. + * + */ +public final class SpeculationLog { + + public static final int MAX_CACHE_SIZE = 1 << 15; + + private List speculations = new ArrayList<>(); + private boolean[] map = new boolean[10]; + private Set snapshot = new HashSet<>(); + + public short addSpeculation(DeoptimizationReason reason) { + short index = (short) speculations.indexOf(reason); + if (index != -1) { + // Nothing to add, reason already registered. + return index; + } + if (speculations.size() >= MAX_CACHE_SIZE) { + throw new BailoutException("Too many deoptimization reasons recorded"); + } + speculations.add(reason); + if (map.length < speculations.size()) { + map = Arrays.copyOf(map, map.length * 2); + } + return (short) (speculations.size() - 1); + } + + public boolean[] getRawMap() { + return map; + } + + public void snapshot() { + for (int i = 0; i < speculations.size(); ++i) { + if (map[i]) { + snapshot.add(speculations.get(i)); + } + } + } + + public boolean maySpeculate(DeoptimizationReason reason) { + return !snapshot.contains(reason); + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackSlot.java Thu Mar 21 14:11:13 2013 +0100 @@ -30,7 +30,7 @@ * Represents a compiler spill slot or an outgoing stack-based argument in a method's frame or an * incoming stack-based argument in a method's {@linkplain #isInCallerFrame() caller's frame}. */ -public final class StackSlot extends Value { +public final class StackSlot extends AllocatableValue { private static final long serialVersionUID = -7725071921307318433L; @@ -165,7 +165,7 @@ private static StackSlot[][] makeCache(int cachePerKindSize, int sign, boolean addFrameSize) { StackSlot[][] cache = new StackSlot[Kind.values().length][]; - for (Kind kind : new Kind[]{Illegal, Int, Long, Float, Double, Object, Jsr}) { + for (Kind kind : new Kind[]{Illegal, Int, Long, Float, Double, Object}) { StackSlot[] slots = new StackSlot[cachePerKindSize]; for (int i = 0; i < cachePerKindSize; i++) { slots[i] = new StackSlot(kind, sign * i * CACHE_GRANULARITY, addFrameSize); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TargetDescription.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TargetDescription.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TargetDescription.java Thu Mar 21 14:11:13 2013 +0100 @@ -33,11 +33,6 @@ public final Architecture arch; /** - * The OS page size. - */ - public final int pageSize; - - /** * Specifies if this is a multi-processor system. */ public final boolean isMP; @@ -72,44 +67,19 @@ public final int stackAlignment; /** - * @see "http://docs.oracle.com/cd/E19455-01/806-0477/overview-4/index.html" - */ - public final int stackBias; - - /** - * The cache alignment. - */ - public final int cacheAlignment; - - /** * Maximum constant displacement at which a memory access can no longer be an implicit null * check. */ public final int implicitNullCheckLimit; - /** - * Specifies how {@code long} and {@code double} constants are to be stored in - * {@linkplain BytecodeFrame frames}. This is useful for VMs such as HotSpot where convention - * the interpreter uses is that the second local holds the first raw word of the native long or - * double representation. This is actually reasonable, since locals and stack arrays grow - * downwards in all implementations. If, on some machine, the interpreter's Java locals or stack - * were to grow upwards, the embedded doubles would be word-swapped.) - */ - public final boolean debugInfoDoubleWordsInSecondSlot; - - public TargetDescription(Architecture arch, boolean isMP, int stackAlignment, int stackBias, int implicitNullCheckLimit, int pageSize, int cacheAlignment, boolean inlineObjects, - boolean debugInfoDoubleWordsInSecondSlot) { + public TargetDescription(Architecture arch, boolean isMP, int stackAlignment, int implicitNullCheckLimit, boolean inlineObjects) { this.arch = arch; - this.pageSize = pageSize; this.isMP = isMP; this.wordSize = arch.getWordSize(); this.wordKind = Kind.fromWordSize(wordSize); this.stackAlignment = stackAlignment; - this.stackBias = stackBias; this.implicitNullCheckLimit = implicitNullCheckLimit; - this.cacheAlignment = cacheAlignment; this.inlineObjects = inlineObjects; - this.debugInfoDoubleWordsInSecondSlot = debugInfoDoubleWordsInSecondSlot; } /** @@ -139,8 +109,6 @@ return 8; case Object: return wordSize; - case Jsr: - return 4; default: return 0; } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java Thu Mar 21 14:11:13 2013 +0100 @@ -58,6 +58,16 @@ return (Constant) value; } + public static boolean isAllocatableValue(Value value) { + assert value != null; + return value instanceof AllocatableValue; + } + + public static AllocatableValue asAllocatableValue(Value value) { + assert value != null; + return (AllocatableValue) value; + } + public static boolean isStackSlot(Value value) { assert value != null; return value instanceof StackSlot; @@ -68,16 +78,6 @@ return (StackSlot) value; } - public static boolean isAddress(Value value) { - assert value != null; - return value instanceof Address; - } - - public static Address asAddress(Value value) { - assert value != null; - return (Address) value; - } - public static boolean isRegister(Value value) { assert value != null; return value instanceof RegisterValue; @@ -89,7 +89,7 @@ } public static Register asIntReg(Value value) { - assert value.getKind() == Kind.Int || value.getKind() == Kind.Jsr; + assert value.getKind() == Kind.Int; return asRegister(value); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.api.code; +import static com.oracle.graal.api.meta.MetaUtil.*; + import java.util.*; import com.oracle.graal.api.meta.*; @@ -65,31 +67,48 @@ this.id = id; } + private static StringBuilder appendValue(StringBuilder buf, Value value, Set visited) { + if (value instanceof VirtualObject) { + VirtualObject vo = (VirtualObject) value; + buf.append("vobject:").append(toJavaName(vo.type, false)).append(':').append(vo.id); + if (!visited.contains(vo)) { + visited.add(vo); + buf.append('{'); + if (vo.values == null) { + buf.append(""); + } else { + if (vo.type.isArray()) { + for (int i = 0; i < vo.values.length; i++) { + if (i != 0) { + buf.append(','); + } + buf.append(i).append('='); + appendValue(buf, vo.values[i], visited); + } + } else { + ResolvedJavaField[] fields = vo.type.getInstanceFields(true); + assert fields.length == vo.values.length : vo.type + ", fields=" + Arrays.toString(fields) + ", values=" + vo.values; + for (int i = 0; i < vo.values.length; i++) { + if (i != 0) { + buf.append(','); + } + buf.append(fields[i].getName()).append('='); + appendValue(buf, vo.values[i], visited); + } + } + } + buf.append('}'); + } + } else { + buf.append(value); + } + return buf; + } + @Override public String toString() { - StringBuilder buf = new StringBuilder("vobject:").append(MetaUtil.toJavaName(type, false)).append(':').append(id).append('{'); - if (values == null) { - buf.append(""); - } else { - if (type.isArray()) { - for (int i = 0; i < values.length; i++) { - if (i != 0) { - buf.append(','); - } - buf.append(i).append('=').append(values[i]); - } - } else { - ResolvedJavaField[] fields = type.getInstanceFields(true); - assert fields.length == values.length : type + ", fields=" + Arrays.toString(fields) + ", values=" + values; - for (int i = 0; i < values.length; i++) { - if (i != 0) { - buf.append(','); - } - buf.append(fields[i].getName()).append('=').append(values[i]); - } - } - } - return buf.append('}').toString(); + Set visited = Collections.newSetFromMap(new IdentityHashMap()); + return appendValue(new StringBuilder(), this, visited).toString(); } /** diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/package-info.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/package-info.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/package-info.java Thu Mar 21 14:11:13 2013 +0100 @@ -23,7 +23,7 @@ /** * Package that defines the interface between a Java application that wants to install code and the runtime. * The runtime provides in implementation of the {@link com.oracle.graal.api.code.CodeCacheProvider} interface. - * The method {@link com.oracle.graal.api.code.CodeCacheProvider#addMethod(com.oracle.graal.api.meta.ResolvedJavaMethod, CompilationResult, CodeInfo[])} + * The method {@link com.oracle.graal.api.code.CodeCacheProvider#addMethod(com.oracle.graal.api.meta.ResolvedJavaMethod, CompilationResult)} * can be used to install code for a given method. */ package com.oracle.graal.api.code; diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestBytecodeDisassemblerProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestBytecodeDisassemblerProvider.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,61 @@ +/* + * 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.api.meta.test; + +import org.junit.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; + +/** + * Tests for {@link BytecodeDisassemblerProvider}. + */ +public class TestBytecodeDisassemblerProvider { + + public TestBytecodeDisassemblerProvider() { + } + + /** + * Tests that successive disassembling of the same method produces the same result. + */ + @Test + public void disassembleTest() { + BytecodeDisassemblerProvider dis = Graal.getRuntime().getCapability(BytecodeDisassemblerProvider.class); + if (dis != null) { + int count = 0; + for (ResolvedJavaMethod m : TestJavaMethod.methods.values()) { + String disasm1 = dis.disassemble(m); + String disasm2 = dis.disassemble(m); + if (disasm1 == null) { + Assert.assertTrue(disasm2 == null); + } else { + Assert.assertTrue(String.valueOf(m), disasm1.length() > 0); + Assert.assertEquals(String.valueOf(m), disasm1, disasm2); + } + if (count++ > 20) { + break; + } + } + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java --- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java Thu Mar 21 14:11:13 2013 +0100 @@ -49,11 +49,14 @@ for (Map.Entry e : methods.entrySet()) { ResolvedJavaMethod m = e.getValue(); byte[] code = m.getCode(); - assertNotNull(code); - if (isAbstract(m.getModifiers())) { - assertTrue(code.length == 0); - } else if (!isNative(m.getModifiers())) { - assertTrue(code.length > 0); + if (code == null) { + assertTrue(m.getCodeSize() == 0); + } else { + if (isAbstract(m.getModifiers())) { + assertTrue(code.length == 0); + } else if (!isNative(m.getModifiers())) { + assertTrue(code.length > 0); + } } } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaType.java Thu Mar 21 14:11:13 2013 +0100 @@ -29,6 +29,7 @@ import java.lang.annotation.*; import java.lang.reflect.*; +import java.net.*; import java.util.*; import org.junit.*; @@ -541,4 +542,36 @@ } } } + + @Test + public void memberClassesTest() { + for (Class c : classes) { + ResolvedJavaType type = runtime.lookupJavaType(c); + assertEquals(c.isLocalClass(), type.isLocal()); + assertEquals(c.isMemberClass(), type.isMember()); + Class enclc = c.getEnclosingClass(); + ResolvedJavaType enclt = type.getEnclosingType(); + assertFalse(enclc == null ^ enclt == null); + if (enclc != null) { + assertEquals(enclt, runtime.lookupJavaType(enclc)); + } + } + } + + @Test + public void classFilePathTest() { + for (Class c : classes) { + ResolvedJavaType type = runtime.lookupJavaType(c); + URL path = type.getClassFilePath(); + if (type.isPrimitive() || type.isArray()) { + assertEquals(null, path); + } else { + assertNotNull(path); + String pathString = path.getPath(); + if (type.isLocal() || type.isMember()) { + assertTrue(pathString.indexOf('$') > 0); + } + } + } + } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/BytecodeDisassemblerProvider.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/BytecodeDisassemblerProvider.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/BytecodeDisassemblerProvider.java Thu Mar 21 14:11:13 2013 +0100 @@ -28,7 +28,11 @@ public interface BytecodeDisassemblerProvider { /** - * Gets a textual disassembly of the bytecode for a given method. + * Gets a textual disassembly of the bytecode for a given method. In the absence of bytecode + * rewriting, disassembling a method will produce the same result. + * + * @return a non-zero length string containing a disassembly of {@code method}'s bytecode or + * null if {@code method} has no bytecode (i.e., {@code method.getCodeSize() == 0}) */ String disassemble(ResolvedJavaMethod method); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java Thu Mar 21 14:11:13 2013 +0100 @@ -134,8 +134,6 @@ return (short) primitive; case Char: return (char) primitive; - case Jsr: - return (int) primitive; case Int: return (int) primitive; case Long: @@ -163,12 +161,12 @@ /** * Returns the primitive int value this constant represents. The constant must have a - * {@link Kind#getStackKind()} of {@link Kind#Int}, or kind {@link Kind#Jsr}. + * {@link Kind#getStackKind()} of {@link Kind#Int}. * * @return the constant value */ public int asInt() { - assert getKind().getStackKind() == Kind.Int || getKind() == Kind.Jsr; + assert getKind().getStackKind() == Kind.Int; return (int) primitive; } @@ -185,13 +183,12 @@ /** * Returns the primitive long value this constant represents. The constant must have kind - * {@link Kind#Long}, a {@link Kind#getStackKind()} of {@link Kind#Int}, or kind - * {@link Kind#Jsr}. + * {@link Kind#Long}, a {@link Kind#getStackKind()} of {@link Kind#Int}. * * @return the constant value */ public long asLong() { - assert getKind() == Kind.Long || getKind().getStackKind() == Kind.Int || getKind() == Kind.Jsr; + assert getKind() == Kind.Long || getKind().getStackKind() == Kind.Int; return primitive; } @@ -365,16 +362,6 @@ } /** - * Creates a boxed address (jsr/ret address) constant. - * - * @param i the address value to box - * @return a boxed copy of {@code value} - */ - public static Constant forJsr(int i) { - return new Constant(Kind.Jsr, null, i); - } - - /** * Creates a boxed object constant. * * @param o the object value to box diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/InvokeTarget.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/InvokeTarget.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,29 @@ +/* + * 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.api.meta; + +/** + * Represents the resolved target of an invocation. + */ +public interface InvokeTarget { +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Kind.java Thu Mar 21 14:11:13 2013 +0100 @@ -60,9 +60,6 @@ /** The void float kind. */ Void('v', "void", false, java.lang.Void.TYPE, java.lang.Void.class), - /** Denote a bytecode address in a {@code JSR} bytecode. */ - Jsr('r', "jsr", false, null, null), - /** The non-type. */ Illegal('-', "illegal", false, null, null); @@ -318,7 +315,6 @@ return java.lang.Character.MIN_VALUE; case Short: return java.lang.Short.MIN_VALUE; - case Jsr: case Int: return java.lang.Integer.MIN_VALUE; case Long: @@ -343,7 +339,6 @@ return java.lang.Character.MAX_VALUE; case Short: return java.lang.Short.MAX_VALUE; - case Jsr: case Int: return java.lang.Integer.MAX_VALUE; case Long: @@ -367,7 +362,6 @@ case Char: case Short: return 16; - case Jsr: case Int: return 32; case Long: diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaAccessProvider.java Thu Mar 21 14:11:13 2013 +0100 @@ -87,10 +87,11 @@ /** * Reads a value of this kind using a base address and a displacement. - * + * * @param base the base address from which the value is read * @param displacement the displacement within the object in bytes - * @return the read value encapsulated in a {@link Constant} object, or {@code null} if the value cannot be read. + * @return the read value encapsulated in a {@link Constant} object, or {@code null} if the + * value cannot be read. */ Constant readUnsafeConstant(Kind kind, Object base, long displacement); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/MetaUtil.java Thu Mar 21 14:11:13 2013 +0100 @@ -135,7 +135,7 @@ String prefix = ""; Class enclosingClass = clazz; while ((enclosingClass = enclosingClass.getEnclosingClass()) != null) { - prefix = prefix + enclosingClass.getSimpleName() + "."; + prefix = enclosingClass.getSimpleName() + "." + prefix; } return prefix + simpleName; } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -31,21 +31,21 @@ * Represents a resolved Java method. Methods, like fields and types, are resolved through * {@link ConstantPool constant pools}. */ -public interface ResolvedJavaMethod extends JavaMethod { +public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget { /** - * Returns the bytecodes of this method, if the method has code. The returned byte array does - * not contain breakpoints or non-Java bytecodes. + * Returns the bytecode of this method, if the method has code. The returned byte array does not + * contain breakpoints or non-Java bytecodes. * - * @return the bytecodes of the method, or {@code null} if none is available + * @return the bytecode of the method, or {@code null} if {@code getCodeSize() == 0} */ byte[] getCode(); /** - * Returns the size of the bytecodes of this method, if the method has code. This is equivalent + * Returns the size of the bytecode of this method, if the method has code. This is equivalent * to {@link #getCode()}. {@code length} if the method has code. * - * @return the size of the bytecodes in bytes, or 0 if no bytecodes is available + * @return the size of the bytecode in bytes, or 0 if no bytecode is available */ int getCodeSize(); @@ -175,5 +175,4 @@ * Returns the localvariable table of this method. */ LocalVariableTable getLocalVariableTable(); - } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -24,6 +24,7 @@ import java.lang.annotation.*; import java.lang.reflect.*; +import java.net.*; /** * Represents a resolved Java type. Types include primitives, objects, {@code void}, and arrays @@ -253,4 +254,24 @@ * Returns name of source file of this type. */ String getSourceFileName(); + + /** + * Returns the class file path - if available - of this type, or {@code null}. + */ + URL getClassFilePath(); + + /** + * Returns {@code true} if the type is a local type. + */ + boolean isLocal(); + + /** + * Returns {@code true} if the type is a member type. + */ + boolean isMember(); + + /** + * Returns the enclosing type of this type, if it exists, or {@code null}. + */ + ResolvedJavaType getEnclosingType(); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/SimpleAssemblerTest.java --- a/graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/SimpleAssemblerTest.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/SimpleAssemblerTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -57,7 +57,7 @@ AMD64MacroAssembler asm = new AMD64MacroAssembler(target, registerConfig); Register ret = registerConfig.getReturnRegister(Kind.Double); compResult.recordDataReference(asm.codeBuffer.position(), Constant.forDouble(84.72), 8, false); - asm.movdbl(ret, Address.Placeholder); + asm.movdbl(ret, asm.getPlaceholder()); asm.ret(0); return asm.codeBuffer; } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Address.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Address.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2010, 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.asm.amd64; + +import com.oracle.graal.api.code.*; + +/** + * Represents an address in target machine memory, specified via some combination of a base + * register, an index register, a displacement and a scale. Note that the base and index registers + * may be a variable that will get a register assigned later by the register allocator. + */ +public final class AMD64Address extends AbstractAddress { + + private final Register base; + private final Register index; + private final Scale scale; + private final int displacement; + + /** + * Creates an {@link AMD64Address} with given base register, no scaling and no displacement. + * + * @param base the base register + */ + public AMD64Address(Register base) { + this(base, Register.None, Scale.Times1, 0); + } + + /** + * Creates an {@link AMD64Address} with given base register, no scaling and a given + * displacement. + * + * @param base the base register + * @param displacement the displacement + */ + public AMD64Address(Register base, int displacement) { + this(base, Register.None, Scale.Times1, displacement); + } + + /** + * Creates an {@link AMD64Address} with given base and index registers, scaling and + * displacement. This is the most general constructor. + * + * @param base the base register + * @param index the index register + * @param scale the scaling factor + * @param displacement the displacement + */ + public AMD64Address(Register base, Register index, Scale scale, int displacement) { + this.base = base; + this.index = index; + this.scale = scale; + this.displacement = displacement; + } + + /** + * A scaling factor used in the SIB addressing mode. + */ + public enum Scale { + Times1(1, 0), Times2(2, 1), Times4(4, 2), Times8(8, 3); + + private Scale(int value, int log2) { + this.value = value; + this.log2 = log2; + } + + /** + * The value (or multiplier) of this scale. + */ + public final int value; + + /** + * The {@linkplain #value value} of this scale log 2. + */ + public final int log2; + + public static Scale fromInt(int scale) { + switch (scale) { + case 1: + return Times1; + case 2: + return Times2; + case 4: + return Times4; + case 8: + return Times8; + default: + throw new IllegalArgumentException(String.valueOf(scale)); + } + } + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder(); + s.append("["); + String sep = ""; + if (getBase() != Register.None) { + s.append(getBase()); + sep = " + "; + } + if (getIndex() != Register.None) { + s.append(sep).append(getIndex()).append(" * ").append(getScale().value); + sep = " + "; + } + if (getDisplacement() < 0) { + s.append(" - ").append(-getDisplacement()); + } else if (getDisplacement() > 0) { + s.append(sep).append(getDisplacement()); + } + s.append("]"); + return s.toString(); + } + + /** + * @return Base register that defines the start of the address computation. If not present, is + * denoted by {@link Register#None}. + */ + public Register getBase() { + return base; + } + + /** + * @return Index register, the value of which (possibly scaled by {@link #getScale}) is added to + * {@link #getBase}. If not present, is denoted by {@link Register#None}. + */ + public Register getIndex() { + return index; + } + + /** + * @return Scaling factor for indexing, dependent on target operand size. + */ + public Scale getScale() { + return scale; + } + + /** + * @return Optional additive displacement. + */ + public int getDisplacement() { + return displacement; + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java --- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -24,13 +24,11 @@ import static com.oracle.graal.amd64.AMD64.*; import static com.oracle.graal.api.code.MemoryBarriers.*; -import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.asm.NumUtil.*; import static com.oracle.graal.asm.amd64.AMD64AsmOptions.*; import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; /** @@ -38,24 +36,41 @@ */ public class AMD64Assembler extends AbstractAssembler { + private static final int MinEncodingNeedsRex = 8; + /** - * The kind for pointers and raw registers. Since we know we are 64 bit here, we can hardcode - * it. + * A sentinel value used as a place holder in an instruction stream for an address that will be + * patched. */ - private static final Kind Word = Kind.Long; - - private static final int MinEncodingNeedsRex = 8; + private static final AMD64Address Placeholder = new AMD64Address(rip); /** * The x86 condition codes used for conditional jumps/moves. */ public enum ConditionFlag { - zero(0x4, "|zero|"), notZero(0x5, "|nzero|"), equal(0x4, "="), notEqual(0x5, "!="), less(0xc, "<"), lessEqual(0xe, "<="), greater(0xf, ">"), greaterEqual(0xd, ">="), below(0x2, "|<|"), belowEqual( - 0x6, "|<=|"), above(0x7, "|>|"), aboveEqual(0x3, "|>=|"), overflow(0x0, "|of|"), noOverflow(0x1, "|nof|"), carrySet(0x2, "|carry|"), carryClear(0x3, "|ncarry|"), negative(0x8, - "|neg|"), positive(0x9, "|pos|"), parity(0xa, "|par|"), noParity(0xb, "|npar|"); + Zero(0x4, "|zero|"), + NotZero(0x5, "|nzero|"), + Equal(0x4, "="), + NotEqual(0x5, "!="), + Less(0xc, "<"), + LessEqual(0xe, "<="), + Greater(0xf, ">"), + GreaterEqual(0xd, ">="), + Below(0x2, "|<|"), + BelowEqual(0x6, "|<=|"), + Above(0x7, "|>|"), + AboveEqual(0x3, "|>=|"), + Overflow(0x0, "|of|"), + NoOverflow(0x1, "|nof|"), + CarrySet(0x2, "|carry|"), + CarryClear(0x3, "|ncarry|"), + Negative(0x8, "|neg|"), + Positive(0x9, "|pos|"), + Parity(0xa, "|par|"), + NoParity(0xb, "|npar|"); - public final int value; - public final String operator; + private final int value; + private final String operator; private ConditionFlag(int value, String operator) { this.value = value; @@ -64,49 +79,58 @@ public ConditionFlag negate() { switch (this) { - case zero: - return notZero; - case notZero: - return zero; - case equal: - return notEqual; - case notEqual: - return equal; - case less: - return greaterEqual; - case lessEqual: - return greater; - case greater: - return lessEqual; - case greaterEqual: - return less; - case below: - return aboveEqual; - case belowEqual: - return above; - case above: - return belowEqual; - case aboveEqual: - return below; - case overflow: - return noOverflow; - case noOverflow: - return overflow; - case carrySet: - return carryClear; - case carryClear: - return carrySet; - case negative: - return positive; - case positive: - return negative; - case parity: - return noParity; - case noParity: - return parity; + case Zero: + return NotZero; + case NotZero: + return Zero; + case Equal: + return NotEqual; + case NotEqual: + return Equal; + case Less: + return GreaterEqual; + case LessEqual: + return Greater; + case Greater: + return LessEqual; + case GreaterEqual: + return Less; + case Below: + return AboveEqual; + case BelowEqual: + return Above; + case Above: + return BelowEqual; + case AboveEqual: + return Below; + case Overflow: + return NoOverflow; + case NoOverflow: + return Overflow; + case CarrySet: + return CarryClear; + case CarryClear: + return CarrySet; + case Negative: + return Positive; + case Positive: + return Negative; + case Parity: + return NoParity; + case NoParity: + return Parity; } throw new IllegalArgumentException(); } + + public int getValue() { + return value; + } + + @Override + public String toString() { + return operator; + } } /** @@ -155,16 +179,6 @@ return r.encoding & 0x7; } - private void emitArithB(int op1, int op2, Register dst, int imm8) { - assert dst.isByte() : "must have byte register"; - assert isUByte(op1) && isUByte(op2) : "wrong opcode"; - assert isUByte(imm8) : "not a byte"; - assert (op1 & 0x01) == 0 : "should be 8bit operation"; - emitByte(op1); - emitByte(op2 | encode(dst)); - emitByte(imm8); - } - private void emitArith(int op1, int op2, Register dst, int imm32) { assert isUByte(op1) && isUByte(op2) : "wrong opcode"; assert (op1 & 0x01) == 1 : "should be 32bit operation"; @@ -181,16 +195,16 @@ } // immediate-to-memory forms - private void emitArithOperand(int op1, Register rm, Address adr, int imm32) { + private void emitArithOperand(int op1, int op2, AMD64Address adr, int imm32) { assert (op1 & 0x01) == 1 : "should be 32bit operation"; assert (op1 & 0x02) == 0 : "sign-extension bit should not be set"; if (isByte(imm32)) { emitByte(op1 | 0x02); // set sign bit - emitOperandHelper(rm, adr); + emitOperandHelper(op2, adr); emitByte(imm32 & 0xFF); } else { emitByte(op1); - emitOperandHelper(rm, adr); + emitOperandHelper(op2, adr); emitInt(imm32); } } @@ -201,37 +215,31 @@ emitByte(op2 | encode(dst) << 3 | encode(src)); } - protected void emitOperandHelper(Register reg, Address addr) { - Register base = isLegal(addr.getBase()) ? asRegister(addr.getBase()) : Register.None; - Register index = isLegal(addr.getIndex()) ? asRegister(addr.getIndex()) : Register.None; + protected void emitOperandHelper(Register reg, AMD64Address addr) { + assert reg != Register.None; + emitOperandHelper(encode(reg), addr); + } - Address.Scale scale = addr.getScale(); + protected void emitOperandHelper(int reg, AMD64Address addr) { + assert (reg & 0x07) == reg; + int regenc = reg << 3; + + Register base = addr.getBase(); + Register index = addr.getIndex(); + + AMD64Address.Scale scale = addr.getScale(); int disp = addr.getDisplacement(); if (base == Register.Frame) { assert frameRegister != null : "cannot use register " + Register.Frame + " in assembler with null register configuration"; base = frameRegister; - // } else if (base == Register.CallerFrame) { - // assert frameRegister != null : "cannot use register " + Register.Frame + - // " in assembler with null register configuration"; - // base = frameRegister; - // disp += targetMethod.frameSize() + 8; } - // Encode the registers as needed in the fields they are used in - - assert reg != Register.None; - int regenc = encode(reg) << 3; - - if (base == AMD64.rip) { + if (base == AMD64.rip) { // also matches Placeholder // [00 000 101] disp32 + assert index == Register.None : "cannot use RIP relative addressing with index register"; emitByte(0x05 | regenc); emitInt(disp); - } else if (addr == Address.Placeholder) { - // [00 000 101] disp32 - emitByte(0x05 | regenc); - emitInt(0); - } else if (base.isValid()) { int baseenc = base.isValid() ? encode(base) : 0; if (index.isValid()) { @@ -316,15 +324,9 @@ } } - public final void addl(Address dst, int imm32) { + public final void addl(AMD64Address dst, int imm32) { prefix(dst); - emitArithOperand(0x81, rax, dst, imm32); - } - - public final void addl(Address dst, Register src) { - prefix(dst, src); - emitByte(0x01); - emitOperandHelper(src, dst); + emitArithOperand(0x81, 0, dst, imm32); } public final void addl(Register dst, int imm32) { @@ -332,7 +334,7 @@ emitArith(0x81, 0xC0, dst, imm32); } - public final void addl(Register dst, Address src) { + public final void addl(Register dst, AMD64Address src) { prefix(src, dst); emitByte(0x03); emitOperandHelper(dst, src); @@ -386,7 +388,7 @@ emitByte(0xC0 | encode); } - public final void addsd(Register dst, Address src) { + public final void addsd(Register dst, AMD64Address src) { assert dst.isFpu(); emitByte(0xF2); prefix(src, dst); @@ -404,7 +406,7 @@ emitByte(0xC0 | encode); } - public final void addss(Register dst, Address src) { + public final void addss(Register dst, AMD64Address src) { assert dst.isFpu(); emitByte(0xF3); prefix(src, dst); @@ -418,7 +420,7 @@ emitArith(0x81, 0xE0, dst, imm32); } - public final void andl(Register dst, Address src) { + public final void andl(Register dst, AMD64Address src) { prefix(src, dst); emitByte(0x23); emitOperandHelper(dst, src); @@ -436,8 +438,9 @@ emitByte(0xC0 | encode); } - public final void bsfq(Register dst, Address src) { + public final void bsfq(Register dst, AMD64Address src) { prefixq(src, dst); + emitByte(0x0F); emitByte(0xBC); emitOperandHelper(dst, src); } @@ -449,8 +452,9 @@ emitByte(0xC0 | encode); } - public final void bsrq(Register dst, Address src) { + public final void bsrq(Register dst, AMD64Address src) { prefixq(src, dst); + emitByte(0x0F); emitByte(0xBD); emitOperandHelper(dst, src); } @@ -462,26 +466,19 @@ emitByte(0xC0 | encode); } - public final void bsrl(Register dst, Address src) { + public final void bsrl(Register dst, AMD64Address src) { prefix(src, dst); + emitByte(0x0F); emitByte(0xBD); emitOperandHelper(dst, src); } - public final void bswapl(Register reg) { // bswap + public final void bswapl(Register reg) { int encode = prefixAndEncode(reg.encoding); emitByte(0x0F); emitByte(0xC8 | encode); } - public final void btli(Address src, int imm8) { - prefixq(src); - emitByte(0x0F); - emitByte(0xBA); - emitOperandHelper(rsp, src); - emitByte(imm8); - } - public final void cdql() { emitByte(0x99); } @@ -489,31 +486,17 @@ public final void cmovl(ConditionFlag cc, Register dst, Register src) { int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); - emitByte(0x40 | cc.value); + emitByte(0x40 | cc.getValue()); emitByte(0xC0 | encode); } - public final void cmovl(ConditionFlag cc, Register dst, Address src) { + public final void cmovl(ConditionFlag cc, Register dst, AMD64Address src) { prefix(src, dst); emitByte(0x0F); - emitByte(0x40 | cc.value); + emitByte(0x40 | cc.getValue()); emitOperandHelper(dst, src); } - public final void cmpb(Address dst, int imm8) { - prefix(dst); - emitByte(0x80); - emitOperandHelper(rdi, dst); - emitByte(imm8); - } - - public final void cmpl(Address dst, int imm32) { - prefix(dst); - emitByte(0x81); - emitOperandHelper(rdi, dst); - emitInt(imm32); - } - public final void cmpl(Register dst, int imm32) { prefix(dst); emitArith(0x81, 0xF8, dst, imm32); @@ -524,7 +507,7 @@ emitArith(0x3B, 0xC0, dst, src); } - public final void cmpl(Register dst, Address src) { + public final void cmpl(Register dst, AMD64Address src) { prefix(src, dst); emitByte(0x3B); emitOperandHelper(dst, src); @@ -533,7 +516,7 @@ // The 32-bit cmpxchg compares the value at adr with the contents of X86.rax, // and stores reg into adr if so; otherwise, the value at adr is loaded into X86.rax,. // The ZF is set if the compared values were equal, and cleared otherwise. - public final void cmpxchgl(Register reg, Address adr) { // cmpxchg + public final void cmpxchgl(Register reg, AMD64Address adr) { // cmpxchg if ((Atomics & 2) != 0) { // caveat: no instructionmark, so this isn't relocatable. // Emit a synthetic, non-atomic, CAS equivalent. @@ -543,7 +526,7 @@ movl(rax, adr); if (reg != rax) { Label l = new Label(); - jcc(ConditionFlag.notEqual, l); + jccb(ConditionFlag.NotEqual, l); movl(adr, reg); bind(l); } @@ -556,43 +539,15 @@ } } - public final void comisd(Register dst, Address src) { + public final void cvtsd2ss(Register dst, AMD64Address src) { assert dst.isFpu(); - // NOTE: dbx seems to decode this as comiss even though the - // 0x66 is there. Strangly ucomisd comes out correct - emitByte(0x66); - comiss(dst, src); - } - - public final void comiss(Register dst, Address src) { - assert dst.isFpu(); - + emitByte(0xF2); prefix(src, dst); emitByte(0x0F); - emitByte(0x2F); + emitByte(0x5A); emitOperandHelper(dst, src); } - public final void cvtdq2pd(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); - - emitByte(0xF3); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xE6); - emitByte(0xC0 | encode); - } - - public final void cvtdq2ps(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x5B); - emitByte(0xC0 | encode); - } - public final void cvtsd2ss(Register dst, Register src) { assert dst.isFpu(); assert src.isFpu(); @@ -603,6 +558,15 @@ emitByte(0xC0 | encode); } + public final void cvtsi2sdl(Register dst, AMD64Address src) { + assert dst.isFpu(); + emitByte(0xF2); + prefix(src, dst); + emitByte(0x0F); + emitByte(0x2A); + emitOperandHelper(dst, src); + } + public final void cvtsi2sdl(Register dst, Register src) { assert dst.isFpu(); emitByte(0xF2); @@ -612,6 +576,15 @@ emitByte(0xC0 | encode); } + public final void cvtsi2ssl(Register dst, AMD64Address src) { + assert dst.isFpu(); + emitByte(0xF3); + prefix(src, dst); + emitByte(0x0F); + emitByte(0x2A); + emitOperandHelper(dst, src); + } + public final void cvtsi2ssl(Register dst, Register src) { assert dst.isFpu(); emitByte(0xF3); @@ -621,6 +594,15 @@ emitByte(0xC0 | encode); } + public final void cvtss2sd(Register dst, AMD64Address src) { + assert dst.isFpu(); + emitByte(0xF3); + prefix(src, dst); + emitByte(0x0F); + emitByte(0x5A); + emitOperandHelper(dst, src); + } + public final void cvtss2sd(Register dst, Register src) { assert dst.isFpu(); assert src.isFpu(); @@ -631,6 +613,14 @@ emitByte(0xC0 | encode); } + public final void cvttsd2sil(Register dst, AMD64Address src) { + emitByte(0xF2); + prefix(src, dst); + emitByte(0x0F); + emitByte(0x2C); + emitOperandHelper(dst, src); + } + public final void cvttsd2sil(Register dst, Register src) { assert src.isFpu(); emitByte(0xF2); @@ -640,6 +630,14 @@ emitByte(0xC0 | encode); } + public final void cvttss2sil(Register dst, AMD64Address src) { + emitByte(0xF3); + prefix(src, dst); + emitByte(0x0F); + emitByte(0x2C); + emitOperandHelper(dst, src); + } + public final void cvttss2sil(Register dst, Register src) { assert src.isFpu(); emitByte(0xF3); @@ -649,14 +647,13 @@ emitByte(0xC0 | encode); } - public final void decl(Address dst) { - // Don't use it directly. Use Macrodecrement() instead. + protected final void decl(AMD64Address dst) { prefix(dst); emitByte(0xFF); - emitOperandHelper(rcx, dst); + emitOperandHelper(1, dst); } - public final void divsd(Register dst, Address src) { + public final void divsd(Register dst, AMD64Address src) { assert dst.isFpu(); emitByte(0xF2); prefix(src, dst); @@ -675,7 +672,7 @@ emitByte(0xC0 | encode); } - public final void divss(Register dst, Address src) { + public final void divss(Register dst, AMD64Address src) { assert dst.isFpu(); emitByte(0xF3); prefix(src, dst); @@ -717,6 +714,13 @@ emitByte(0xC0 | encode); } + public final void imull(Register dst, AMD64Address src) { + prefix(src, dst); + emitByte(0x0F); + emitByte(0xAF); + emitOperandHelper(dst, src); + } + public final void imull(Register dst, Register src, int value) { int encode = prefixAndEncode(dst.encoding, src.encoding); if (isByte(value)) { @@ -730,32 +734,31 @@ } } - public final void incl(Address dst) { - // Don't use it directly. Use Macroincrement() instead. + protected final void incl(AMD64Address dst) { prefix(dst); emitByte(0xFF); - emitOperandHelper(rax, dst); + emitOperandHelper(0, dst); } - public final void jcc(ConditionFlag cc, int jumpTarget, boolean forceDisp32) { + private void jcc(ConditionFlag cc, int jumpTarget, boolean forceDisp32) { int shortSize = 2; int longSize = 6; long disp = jumpTarget - codeBuffer.position(); if (!forceDisp32 && isByte(disp - shortSize)) { // 0111 tttn #8-bit disp - emitByte(0x70 | cc.value); + emitByte(0x70 | cc.getValue()); emitByte((int) ((disp - shortSize) & 0xFF)); } else { // 0000 1111 1000 tttn #32-bit disp assert isInt(disp - longSize) : "must be 32bit offset (call4)"; emitByte(0x0F); - emitByte(0x80 | cc.value); + emitByte(0x80 | cc.getValue()); emitInt((int) (disp - longSize)); } } public final void jcc(ConditionFlag cc, Label l) { - assert (0 <= cc.value) && (cc.value < 16) : "illegal cc"; + assert (0 <= cc.getValue()) && (cc.getValue() < 16) : "illegal cc"; if (l.isBound()) { jcc(cc, l.position(), false); } else { @@ -765,7 +768,7 @@ // an 8-bit displacement l.addPatchAt(codeBuffer.position()); emitByte(0x0F); - emitByte(0x80 | cc.value); + emitByte(0x80 | cc.getValue()); emitInt(0); } @@ -778,22 +781,16 @@ assert isByte(entry - (codeBuffer.position() + shortSize)) : "Dispacement too large for a short jmp"; long disp = entry - codeBuffer.position(); // 0111 tttn #8-bit disp - emitByte(0x70 | cc.value); + emitByte(0x70 | cc.getValue()); emitByte((int) ((disp - shortSize) & 0xFF)); } else { l.addPatchAt(codeBuffer.position()); - emitByte(0x70 | cc.value); + emitByte(0x70 | cc.getValue()); emitByte(0); } } - public final void jmp(Address adr) { - prefix(adr); - emitByte(0xFF); - emitOperandHelper(rsp, adr); - } - public final void jmp(int jumpTarget, boolean forceDisp32) { int shortSize = 2; int longSize = 5; @@ -845,18 +842,12 @@ } } - public final void leaq(Register dst, Address src) { + public final void leaq(Register dst, AMD64Address src) { prefixq(src, dst); emitByte(0x8D); emitOperandHelper(dst, src); } - public final void enter(int imm16, int imm8) { - emitByte(0xC8); - emitShort(imm16); - emitByte(imm8); - } - public final void leave() { emitByte(0xC9); } @@ -870,17 +861,6 @@ } } - // Emit mfence instruction - public final void mfence() { - emitByte(0x0F); - emitByte(0xAE); - emitByte(0xF0); - } - - public final void mov(Register dst, Register src) { - movq(dst, src); - } - public final void movapd(Register dst, Register src) { assert dst.isFpu(); assert src.isFpu(); @@ -930,20 +910,14 @@ emitByte(0xC0 | dstenc << 3 | srcenc); } - public final void movb(Register dst, Address src) { - prefix(src, dst); // , true) - emitByte(0x8A); - emitOperandHelper(dst, src); - } - - public final void movb(Address dst, int imm8) { + public final void movb(AMD64Address dst, int imm8) { prefix(dst); emitByte(0xC6); - emitOperandHelper(rax, dst); + emitOperandHelper(0, dst); emitByte(imm8); } - public final void movb(Address dst, Register src) { + public final void movb(AMD64Address dst, Register src) { assert src.isByte() : "must have byte register"; prefix(dst, src); // , true) emitByte(0x88); @@ -969,63 +943,6 @@ } } - public final void movdqa(Register dst, Address src) { - assert dst.isFpu(); - emitByte(0x66); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x6F); - emitOperandHelper(dst, src); - } - - public final void movdqa(Register dst, Register src) { - assert dst.isFpu(); - emitByte(0x66); - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x6F); - emitByte(0xC0 | encode); - } - - public final void movdqa(Address dst, Register src) { - assert src.isFpu(); - emitByte(0x66); - prefix(dst, src); - emitByte(0x0F); - emitByte(0x7F); - emitOperandHelper(src, dst); - } - - public final void movdqu(Register dst, Address src) { - assert dst.isFpu(); - emitByte(0xF3); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x6F); - emitOperandHelper(dst, src); - } - - public final void movdqu(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); - - emitByte(0xF3); - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x6F); - emitByte(0xC0 | encode); - } - - public final void movdqu(Address dst, Register src) { - assert src.isFpu(); - - emitByte(0xF3); - prefix(dst, src); - emitByte(0x0F); - emitByte(0x7F); - emitOperandHelper(src, dst); - } - public final void movl(Register dst, int imm32) { int encode = prefixAndEncode(dst.encoding); emitByte(0xB8 | encode); @@ -1038,20 +955,20 @@ emitByte(0xC0 | encode); } - public final void movl(Register dst, Address src) { + public final void movl(Register dst, AMD64Address src) { prefix(src, dst); emitByte(0x8B); emitOperandHelper(dst, src); } - public final void movl(Address dst, int imm32) { + public final void movl(AMD64Address dst, int imm32) { prefix(dst); emitByte(0xC7); - emitOperandHelper(rax, dst); + emitOperandHelper(0, dst); emitInt(imm32); } - public final void movl(Address dst, Register src) { + public final void movl(AMD64Address dst, Register src) { prefix(dst, src); emitByte(0x89); emitOperandHelper(src, dst); @@ -1060,10 +977,10 @@ /** * New CPUs require use of movsd and movss to avoid partial register stall when loading from * memory. But for old Opteron use movlpd instead of movsd. The selection is done in - * {@link AMD64MacroAssembler#movdbl(Register, Address)} and + * {@link AMD64MacroAssembler#movdbl(Register, AMD64Address)} and * {@link AMD64MacroAssembler#movflt(Register, Register)}. */ - public final void movlpd(Register dst, Address src) { + public final void movlpd(Register dst, AMD64Address src) { assert dst.isFpu(); emitByte(0x66); prefix(src, dst); @@ -1072,16 +989,7 @@ emitOperandHelper(dst, src); } - public final void movlpd(Address dst, Register src) { - assert src.isFpu(); - emitByte(0x66); - prefix(dst, src); - emitByte(0x0F); - emitByte(0x13); - emitOperandHelper(src, dst); - } - - public final void movq(Register dst, Address src) { + public final void movq(Register dst, AMD64Address src) { if (dst.isFpu()) { emitByte(0xF3); prefixq(src, dst); @@ -1101,7 +1009,7 @@ emitByte(0xC0 | encode); } - public final void movq(Address dst, Register src) { + public final void movq(AMD64Address dst, Register src) { if (src.isFpu()) { emitByte(0x66); prefixq(dst, src); @@ -1115,14 +1023,14 @@ } } - public final void movsxb(Register dst, Address src) { // movsxb + public final void movsxb(Register dst, AMD64Address src) { prefix(src, dst); emitByte(0x0F); emitByte(0xBE); emitOperandHelper(dst, src); } - public final void movsxb(Register dst, Register src) { // movsxb + public final void movsxb(Register dst, Register src) { int encode = prefixAndEncode(dst.encoding, src.encoding, true); emitByte(0x0F); emitByte(0xBE); @@ -1139,7 +1047,7 @@ emitByte(0xC0 | encode); } - public final void movsd(Register dst, Address src) { + public final void movsd(Register dst, AMD64Address src) { assert dst.isFpu(); emitByte(0xF2); prefix(src, dst); @@ -1148,7 +1056,7 @@ emitOperandHelper(dst, src); } - public final void movsd(Address dst, Register src) { + public final void movsd(AMD64Address dst, Register src) { assert src.isFpu(); emitByte(0xF2); prefix(dst, src); @@ -1167,7 +1075,7 @@ emitByte(0xC0 | encode); } - public final void movss(Register dst, Address src) { + public final void movss(Register dst, AMD64Address src) { assert dst.isFpu(); emitByte(0xF3); prefix(src, dst); @@ -1176,7 +1084,7 @@ emitOperandHelper(dst, src); } - public final void movss(Address dst, Register src) { + public final void movss(AMD64Address dst, Register src) { assert src.isFpu(); emitByte(0xF3); prefix(dst, src); @@ -1185,96 +1093,50 @@ emitOperandHelper(src, dst); } - public final void movswl(Register dst, Address src) { + public final void movswl(Register dst, AMD64Address src) { prefix(src, dst); emitByte(0x0F); emitByte(0xBF); emitOperandHelper(dst, src); } - public final void movsxw(Register dst, Register src) { // movsxw + public final void movsxw(Register dst, Register src) { int encode = prefixAndEncode(dst.encoding, src.encoding); emitByte(0x0F); emitByte(0xBF); emitByte(0xC0 | encode); } - public final void movsxw(Register dst, Address src) { // movsxw + public final void movsxw(Register dst, AMD64Address src) { prefix(src, dst); emitByte(0x0F); emitByte(0xBF); emitOperandHelper(dst, src); } - public final void movzxd(Register dst, Register src) { // movzxd - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x63); - emitByte(0xC0 | encode); - } - - public final void movzxd(Register dst, Address src) { // movzxd - prefix(src, dst); - emitByte(0x63); - emitOperandHelper(dst, src); - } - - public final void movw(Address dst, int imm16) { + public final void movw(AMD64Address dst, int imm16) { emitByte(0x66); // switch to 16-bit mode prefix(dst); emitByte(0xC7); - emitOperandHelper(rax, dst); + emitOperandHelper(0, dst); emitShort(imm16); } - public final void movw(Register dst, Address src) { - emitByte(0x66); - prefix(src, dst); - emitByte(0x8B); - emitOperandHelper(dst, src); - } - - public final void movw(Address dst, Register src) { + public final void movw(AMD64Address dst, Register src) { emitByte(0x66); prefix(dst, src); emitByte(0x89); emitOperandHelper(src, dst); } - public final void movzxb(Register dst, Address src) { // movzxb - prefix(src, dst); - emitByte(0x0F); - emitByte(0xB6); - emitOperandHelper(dst, src); - } - - public final void movzxb(Register dst, Register src) { // movzxb - int encode = prefixAndEncode(dst.encoding, src.encoding, true); - emitByte(0x0F); - emitByte(0xB6); - emitByte(0xC0 | encode); - } - - public final void movzxl(Register dst, Address src) { // movzxw + public final void movzxl(Register dst, AMD64Address src) { prefix(src, dst); emitByte(0x0F); emitByte(0xB7); emitOperandHelper(dst, src); } - public final void movzxl(Register dst, Register src) { // movzxw - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xB7); - emitByte(0xC0 | encode); - } - - public final void mull(Address src) { - prefix(src); - emitByte(0xF7); - emitOperandHelper(rsp, src); - } - - public final void mulsd(Register dst, Address src) { + public final void mulsd(Register dst, AMD64Address src) { assert dst.isFpu(); emitByte(0xF2); prefix(src, dst); @@ -1294,7 +1156,7 @@ emitByte(0xC0 | encode); } - public final void mulss(Register dst, Address src) { + public final void mulss(Register dst, AMD64Address src) { assert dst.isFpu(); emitByte(0xF3); @@ -1530,25 +1392,12 @@ } } - public final void notl(Register dst) { - int encode = prefixAndEncode(dst.encoding); - emitByte(0xF7); - emitByte(0xD0 | encode); - } - - public final void orl(Address dst, int imm32) { - prefix(dst); - emitByte(0x81); - emitOperandHelper(rcx, dst); - emitInt(imm32); - } - public final void orl(Register dst, int imm32) { prefix(dst); emitArith(0x81, 0xC8, dst, imm32); } - public final void orl(Register dst, Address src) { + public final void orl(Register dst, AMD64Address src) { prefix(src, dst); emitByte(0x0B); emitOperandHelper(dst, src); @@ -1559,7 +1408,7 @@ emitArith(0x0B, 0xC0, dst, src); } - public final void popcntl(Register dst, Address src) { + public final void popcntl(Register dst, AMD64Address src) { emitByte(0xF3); prefix(src, dst); emitByte(0x0F); @@ -1575,7 +1424,7 @@ emitByte(0xC0 | encode); } - public final void popcntq(Register dst, Address src) { + public final void popcntq(Register dst, AMD64Address src) { emitByte(0xF3); prefixq(src, dst); emitByte(0x0F); @@ -1591,223 +1440,16 @@ emitByte(0xC0 | encode); } - // generic public final void pop(Register dst) { int encode = prefixAndEncode(dst.encoding); emitByte(0x58 | encode); } - public final void prefetchPrefix(Address src) { - prefix(src); - emitByte(0x0F); - } - - public final void prefetchnta(Address src) { - prefetchPrefix(src); - emitByte(0x18); - emitOperandHelper(rax, src); // 0, src - } - - public final void prefetchr(Address src) { - prefetchPrefix(src); - emitByte(0x0D); - emitOperandHelper(rax, src); // 0, src - } - - public final void prefetcht0(Address src) { - prefetchPrefix(src); - emitByte(0x18); - emitOperandHelper(rcx, src); // 1, src - - } - - public final void prefetcht1(Address src) { - prefetchPrefix(src); - emitByte(0x18); - emitOperandHelper(rdx, src); // 2, src - } - - public final void prefetcht2(Address src) { - prefetchPrefix(src); - emitByte(0x18); - emitOperandHelper(rbx, src); // 3, src - } - - public final void prefetchw(Address src) { - prefetchPrefix(src); - emitByte(0x0D); - emitOperandHelper(rcx, src); // 1, src - } - - public final void pshufd(Register dst, Register src, int mode) { - assert dst.isFpu(); - assert src.isFpu(); - assert isUByte(mode) : "invalid value"; - - emitByte(0x66); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x70); - emitByte(0xC0 | encode); - emitByte(mode & 0xFF); - } - - public final void pshufd(Register dst, Address src, int mode) { - assert dst.isFpu(); - assert isUByte(mode) : "invalid value"; - - emitByte(0x66); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x70); - emitOperandHelper(dst, src); - emitByte(mode & 0xFF); - - } - - public final void pshuflw(Register dst, Register src, int mode) { - assert dst.isFpu(); - assert src.isFpu(); - assert isUByte(mode) : "invalid value"; - - emitByte(0xF2); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x70); - emitByte(0xC0 | encode); - emitByte(mode & 0xFF); - } - - public final void pshuflw(Register dst, Address src, int mode) { - assert dst.isFpu(); - assert isUByte(mode) : "invalid value"; - - emitByte(0xF2); - prefix(src, dst); // QQ new - emitByte(0x0F); - emitByte(0x70); - emitOperandHelper(dst, src); - emitByte(mode & 0xFF); - } - - public final void psrlq(Register dst, int shift) { - assert dst.isFpu(); - // HMM Table D-1 says sse2 or mmx - - int encode = prefixqAndEncode(xmm2.encoding, dst.encoding); - emitByte(0x66); - emitByte(0x0F); - emitByte(0x73); - emitByte(0xC0 | encode); - emitByte(shift); - } - - public final void punpcklbw(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); - emitByte(0x66); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0x60); - emitByte(0xC0 | encode); - } - - public final void push(int imm32) { - // in 64bits we push 64bits onto the stack but only - // take a 32bit immediate - emitByte(0x68); - emitInt(imm32); - } - public final void push(Register src) { int encode = prefixAndEncode(src.encoding); emitByte(0x50 | encode); } - public final void pushf() { - emitByte(0x9C); - } - - public final void pxor(Register dst, Address src) { - assert dst.isFpu(); - - emitByte(0x66); - prefix(src, dst); - emitByte(0x0F); - emitByte(0xEF); - emitOperandHelper(dst, src); - } - - public final void pxor(Register dst, Register src) { - assert dst.isFpu(); - assert src.isFpu(); - - emitByte(0x66); - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xEF); - emitByte(0xC0 | encode); - - } - - public final void rcll(Register dst, int imm8) { - assert isShiftCount(imm8) : "illegal shift count"; - int encode = prefixAndEncode(dst.encoding); - if (imm8 == 1) { - emitByte(0xD1); - emitByte(0xD0 | encode); - } else { - emitByte(0xC1); - emitByte(0xD0 | encode); - emitByte(imm8); - } - } - - public final void pause() { - emitByte(0xF3); - emitByte(0x90); - } - - // Copies data from [X86.rsi] to [X86.rdi] using X86.rcx heap words. - public final void repeatMoveWords() { - emitByte(0xF3); - emitByte(Prefix.REXW); - emitByte(0xA5); - } - - // Copies data from [X86.rsi] to [X86.rdi] using X86.rcx bytes. - public final void repeatMoveBytes() { - emitByte(0xF3); - emitByte(Prefix.REXW); - emitByte(0xA4); - } - - // sets X86.rcx pointer sized words with X86.rax, value at [edi] - // generic - public final void repSet() { // repSet - emitByte(0xF3); - // STOSQ - emitByte(Prefix.REXW); - emitByte(0xAB); - } - - // scans X86.rcx pointer sized words at [edi] for occurance of X86.rax, - // generic - public final void repneScan() { // repneScan - emitByte(0xF2); - // SCASQ - emitByte(Prefix.REXW); - emitByte(0xAF); - } - - // scans X86.rcx 4 byte words at [edi] for occurance of X86.rax, - // generic - public final void repneScanl() { // repneScan - emitByte(0xF2); - // SCASL - emitByte(0xAF); - } - public final void ret(int imm16) { if (imm16 == 0) { emitByte(0xC3); @@ -1836,35 +1478,6 @@ emitByte(0xF8 | encode); } - public final void sbbl(Address dst, int imm32) { - prefix(dst); - emitArithOperand(0x81, rbx, dst, imm32); - } - - public final void sbbl(Register dst, int imm32) { - prefix(dst); - emitArith(0x81, 0xD8, dst, imm32); - } - - public final void sbbl(Register dst, Address src) { - prefix(src, dst); - emitByte(0x1B); - emitOperandHelper(dst, src); - } - - public final void sbbl(Register dst, Register src) { - prefixAndEncode(dst.encoding, src.encoding); - emitArith(0x1B, 0xC0, dst, src); - } - - public final void setb(ConditionFlag cc, Register dst) { - assert 0 <= cc.value && cc.value < 16 : "illegal cc"; - int encode = prefixAndEncode(dst.encoding, true); - emitByte(0x0F); - emitByte(0x90 | cc.value); - emitByte(0xC0 | encode); - } - public final void shll(Register dst, int imm8) { assert isShiftCount(imm8) : "illegal shift count"; int encode = prefixAndEncode(dst.encoding); @@ -1898,11 +1511,6 @@ emitByte(0xE8 | encode); } - // copies a single word from [esi] to [edi] - public final void smovl() { - emitByte(0xA5); - } - public final void sqrtsd(Register dst, Register src) { assert dst.isFpu(); assert src.isFpu(); @@ -1915,17 +1523,9 @@ emitByte(0xC0 | encode); } - public final void subl(Address dst, int imm32) { + public final void subl(AMD64Address dst, int imm32) { prefix(dst); - if (isByte(imm32)) { - emitByte(0x83); - emitOperandHelper(rbp, dst); - emitByte(imm32 & 0xFF); - } else { - emitByte(0x81); - emitOperandHelper(rbp, dst); - emitInt(imm32); - } + emitArithOperand(0x81, 5, dst, imm32); } public final void subl(Register dst, int imm32) { @@ -1933,13 +1533,7 @@ emitArith(0x81, 0xE8, dst, imm32); } - public final void subl(Address dst, Register src) { - prefix(dst, src); - emitByte(0x29); - emitOperandHelper(src, dst); - } - - public final void subl(Register dst, Address src) { + public final void subl(Register dst, AMD64Address src) { prefix(src, dst); emitByte(0x2B); emitOperandHelper(dst, src); @@ -1960,7 +1554,7 @@ emitByte(0xC0 | encode); } - public final void subsd(Register dst, Address src) { + public final void subsd(Register dst, AMD64Address src) { assert dst.isFpu(); emitByte(0xF2); @@ -1980,7 +1574,7 @@ emitByte(0xC0 | encode); } - public final void subss(Register dst, Address src) { + public final void subss(Register dst, AMD64Address src) { assert dst.isFpu(); emitByte(0xF3); @@ -1990,11 +1584,6 @@ emitOperandHelper(dst, src); } - public final void testb(Register dst, int imm8) { - prefixAndEncode(dst.encoding, true); - emitArithB(0xF6, 0xC0, dst, imm8); - } - public final void testl(Register dst, int imm32) { // not using emitArith because test // doesn't support sign-extension of @@ -2015,13 +1604,13 @@ emitArith(0x85, 0xC0, dst, src); } - public final void testl(Register dst, Address src) { + public final void testl(Register dst, AMD64Address src) { prefix(src, dst); emitByte(0x85); emitOperandHelper(dst, src); } - public final void ucomisd(Register dst, Address src) { + public final void ucomisd(Register dst, AMD64Address src) { assert dst.isFpu(); emitByte(0x66); ucomiss(dst, src); @@ -2034,7 +1623,7 @@ ucomiss(dst, src); } - public final void ucomiss(Register dst, Address src) { + public final void ucomiss(Register dst, AMD64Address src) { assert dst.isFpu(); prefix(src, dst); @@ -2052,33 +1641,12 @@ emitByte(0xC0 | encode); } - public final void xaddl(Address dst, Register src) { - assert src.isFpu(); - - prefix(dst, src); - emitByte(0x0F); - emitByte(0xC1); - emitOperandHelper(src, dst); - } - - public final void xchgl(Register dst, Address src) { // xchg - prefix(src, dst); - emitByte(0x87); - emitOperandHelper(dst, src); - } - - public final void xchgl(Register dst, Register src) { - int encode = prefixAndEncode(dst.encoding, src.encoding); - emitByte(0x87); - emitByte(0xc0 | encode); - } - public final void xorl(Register dst, int imm32) { prefix(dst); emitArith(0x81, 0xF0, dst, imm32); } - public final void xorl(Register dst, Address src) { + public final void xorl(Register dst, AMD64Address src) { prefix(src, dst); emitByte(0x33); emitOperandHelper(dst, src); @@ -2094,7 +1662,7 @@ andps(dst, src); } - public final void andpd(Register dst, Address src) { + public final void andpd(Register dst, AMD64Address src) { emitByte(0x66); andps(dst, src); } @@ -2107,7 +1675,7 @@ emitByte(0xC0 | encode); } - public final void andps(Register dst, Address src) { + public final void andps(Register dst, AMD64Address src) { assert dst.isFpu(); prefix(src, dst); emitByte(0x0F); @@ -2120,7 +1688,7 @@ orps(dst, src); } - public final void orpd(Register dst, Address src) { + public final void orpd(Register dst, AMD64Address src) { emitByte(0x66); orps(dst, src); } @@ -2133,7 +1701,7 @@ emitByte(0xC0 | encode); } - public final void orps(Register dst, Address src) { + public final void orps(Register dst, AMD64Address src) { assert dst.isFpu(); prefix(src, dst); emitByte(0x0F); @@ -2146,7 +1714,7 @@ xorps(dst, src); } - public final void xorpd(Register dst, Address src) { + public final void xorpd(Register dst, AMD64Address src) { emitByte(0x66); xorps(dst, src); } @@ -2159,7 +1727,7 @@ emitByte(0xC0 | encode); } - public final void xorps(Register dst, Address src) { + public final void xorps(Register dst, AMD64Address src) { assert dst.isFpu(); prefix(src, dst); emitByte(0x0F); @@ -2167,29 +1735,25 @@ emitOperandHelper(dst, src); } - // 32bit only pieces of the assembler - - public final void decl(Register dst) { - // Don't use it directly. Use Macrodecrementl() instead. + protected final void decl(Register dst) { // Use two-byte form (one-byte form is a REX prefix in 64-bit mode) int encode = prefixAndEncode(dst.encoding); emitByte(0xFF); emitByte(0xC8 | encode); } - public final void incl(Register dst) { - // Don't use it directly. Use Macroincrementl() instead. + protected final void incl(Register dst) { // Use two-byte form (one-byte from is a REX prefix in 64-bit mode) int encode = prefixAndEncode(dst.encoding); emitByte(0xFF); emitByte(0xC0 | encode); } - int prefixAndEncode(int regEnc) { + private int prefixAndEncode(int regEnc) { return prefixAndEncode(regEnc, false); } - int prefixAndEncode(int regEnc, boolean byteinst) { + private int prefixAndEncode(int regEnc, boolean byteinst) { if (regEnc >= 8) { emitByte(Prefix.REXB); return regEnc - 8; @@ -2199,7 +1763,7 @@ return regEnc; } - int prefixqAndEncode(int regEnc) { + private int prefixqAndEncode(int regEnc) { if (regEnc < 8) { emitByte(Prefix.REXW); return regEnc; @@ -2209,11 +1773,11 @@ } } - int prefixAndEncode(int dstEnc, int srcEnc) { + private int prefixAndEncode(int dstEnc, int srcEnc) { return prefixAndEncode(dstEnc, srcEnc, false); } - int prefixAndEncode(int dstEncoding, int srcEncoding, boolean byteinst) { + private int prefixAndEncode(int dstEncoding, int srcEncoding, boolean byteinst) { int srcEnc = srcEncoding; int dstEnc = dstEncoding; if (dstEnc < 8) { @@ -2271,11 +1835,11 @@ } } - private static boolean needsRex(Value value) { - return isRegister(value) && asRegister(value).encoding >= MinEncodingNeedsRex; + private static boolean needsRex(Register reg) { + return reg.encoding >= MinEncodingNeedsRex; } - private void prefix(Address adr) { + private void prefix(AMD64Address adr) { if (needsRex(adr.getBase())) { if (needsRex(adr.getIndex())) { emitByte(Prefix.REXXB); @@ -2289,7 +1853,7 @@ } } - private void prefixq(Address adr) { + private void prefixq(AMD64Address adr) { if (needsRex(adr.getBase())) { if (needsRex(adr.getIndex())) { emitByte(Prefix.REXWXB); @@ -2305,7 +1869,7 @@ } } - private void prefix(Address adr, Register reg) { + private void prefix(AMD64Address adr, Register reg) { if (reg.encoding < 8) { if (needsRex(adr.getBase())) { if (needsRex(adr.getIndex())) { @@ -2337,7 +1901,7 @@ } } - private void prefixq(Address adr, Register src) { + private void prefixq(AMD64Address adr, Register src) { if (src.encoding < 8) { if (needsRex(adr.getBase())) { if (needsRex(adr.getIndex())) { @@ -2369,23 +1933,12 @@ } } - public final void addq(Address dst, int imm32) { - prefixq(dst); - emitArithOperand(0x81, rax, dst, imm32); - } - - public final void addq(Address dst, Register src) { - prefixq(dst, src); - emitByte(0x01); - emitOperandHelper(src, dst); - } - public final void addq(Register dst, int imm32) { prefixqAndEncode(dst.encoding); emitArith(0x81, 0xC0, dst, imm32); } - public final void addq(Register dst, Address src) { + public final void addq(Register dst, AMD64Address src) { prefixq(src, dst); emitByte(0x03); emitOperandHelper(dst, src); @@ -2401,7 +1954,7 @@ emitArith(0x81, 0xE0, dst, imm32); } - public final void andq(Register dst, Address src) { + public final void andq(Register dst, AMD64Address src) { prefixq(src, dst); emitByte(0x23); emitOperandHelper(dst, src); @@ -2426,53 +1979,49 @@ public final void cmovq(ConditionFlag cc, Register dst, Register src) { int encode = prefixqAndEncode(dst.encoding, src.encoding); emitByte(0x0F); - emitByte(0x40 | cc.value); + emitByte(0x40 | cc.getValue()); emitByte(0xC0 | encode); } - public final void cmovq(ConditionFlag cc, Register dst, Address src) { + public final void cmovq(ConditionFlag cc, Register dst, AMD64Address src) { prefixq(src, dst); emitByte(0x0F); - emitByte(0x40 | cc.value); + emitByte(0x40 | cc.getValue()); emitOperandHelper(dst, src); } - public final void cmpq(Address dst, int imm32) { - prefixq(dst); - emitByte(0x81); - emitOperandHelper(rdi, dst); - emitInt(imm32); - } - public final void cmpq(Register dst, int imm32) { prefixqAndEncode(dst.encoding); emitArith(0x81, 0xF8, dst, imm32); } - public final void cmpq(Address dst, Register src) { - prefixq(dst, src); - emitByte(0x3B); - emitOperandHelper(src, dst); - } - public final void cmpq(Register dst, Register src) { prefixqAndEncode(dst.encoding, src.encoding); emitArith(0x3B, 0xC0, dst, src); } - public final void cmpq(Register dst, Address src) { + public final void cmpq(Register dst, AMD64Address src) { prefixq(src, dst); emitByte(0x3B); emitOperandHelper(dst, src); } - public final void cmpxchgq(Register reg, Address adr) { + public final void cmpxchgq(Register reg, AMD64Address adr) { prefixq(adr, reg); emitByte(0x0F); emitByte(0xB1); emitOperandHelper(reg, adr); } + public final void cvtsi2sdq(Register dst, AMD64Address src) { + assert dst.isFpu(); + emitByte(0xF2); + prefixq(src, dst); + emitByte(0x0F); + emitByte(0x2A); + emitOperandHelper(dst, src); + } + public final void cvtsi2sdq(Register dst, Register src) { assert dst.isFpu(); emitByte(0xF2); @@ -2482,6 +2031,15 @@ emitByte(0xC0 | encode); } + public final void cvtsi2ssq(Register dst, AMD64Address src) { + assert dst.isFpu(); + emitByte(0xF3); + prefixq(src, dst); + emitByte(0x0F); + emitByte(0x2A); + emitOperandHelper(dst, src); + } + public final void cvtsi2ssq(Register dst, Register src) { assert dst.isFpu(); emitByte(0xF3); @@ -2491,6 +2049,14 @@ emitByte(0xC0 | encode); } + public final void cvttsd2siq(Register dst, AMD64Address src) { + emitByte(0xF2); + prefixq(src, dst); + emitByte(0x0F); + emitByte(0x2C); + emitOperandHelper(dst, src); + } + public final void cvttsd2siq(Register dst, Register src) { assert src.isFpu(); emitByte(0xF2); @@ -2500,6 +2066,14 @@ emitByte(0xC0 | encode); } + public final void cvttss2siq(Register dst, AMD64Address src) { + emitByte(0xF3); + prefixq(src, dst); + emitByte(0x0F); + emitByte(0x2C); + emitOperandHelper(dst, src); + } + public final void cvttss2siq(Register dst, Register src) { assert src.isFpu(); emitByte(0xF3); @@ -2509,19 +2083,17 @@ emitByte(0xC0 | encode); } - public final void decq(Register dst) { - // Don't use it directly. Use Macrodecrementq() instead. + protected final void decq(Register dst) { // Use two-byte form (one-byte from is a REX prefix in 64-bit mode) int encode = prefixqAndEncode(dst.encoding); emitByte(0xFF); emitByte(0xC8 | encode); } - public final void decq(Address dst) { - // Don't use it directly. Use Macrodecrementq() instead. + protected final void decq(AMD64Address dst) { prefixq(dst); emitByte(0xFF); - emitOperandHelper(rcx, dst); + emitOperandHelper(1, dst); } public final void divq(Register src) { @@ -2543,6 +2115,13 @@ emitByte(0xC0 | encode); } + public final void imulq(Register dst, AMD64Address src) { + prefixq(src, dst); + emitByte(0x0F); + emitByte(0xAF); + emitOperandHelper(dst, src); + } + public final void imulq(Register dst, Register src, int value) { int encode = prefixqAndEncode(dst.encoding, src.encoding); if (isByte(value)) { @@ -2564,13 +2143,6 @@ emitByte(0xC0 | encode); } - public final void incq(Address dst) { - // Don't use it directly. Use Macroincrementq() instead. - prefixq(dst); - emitByte(0xFF); - emitOperandHelper(rax, dst); - } - public final void movq(Register dst, long imm64) { int encode = prefixqAndEncode(dst.encoding); emitByte(0xB8 | encode); @@ -2600,38 +2172,14 @@ } } - public final void movsbq(Register dst, Address src) { - prefixq(src, dst); - emitByte(0x0F); - emitByte(0xBE); - emitOperandHelper(dst, src); - } - - public final void movsbq(Register dst, Register src) { - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xBE); - emitByte(0xC0 | encode); - } - - public final void movslq(Register dst, int imm32) { - int encode = prefixqAndEncode(dst.encoding); - emitByte(0xC7 | encode); - emitInt(imm32); - // dbx shows movslq(X86.rcx, 3) as movq $0x0000000049000000,(%X86.rbx) - // and movslq(X86.r8, 3); as movl $0x0000000048000000,(%X86.rbx) - // as a result we shouldn't use until tested at runtime... - throw new InternalError("untested"); - } - - public final void movslq(Address dst, int imm32) { + public final void movslq(AMD64Address dst, int imm32) { prefixq(dst); emitByte(0xC7); - emitOperandHelper(rax, dst); + emitOperandHelper(0, dst); emitInt(imm32); } - public final void movslq(Register dst, Address src) { + public final void movslq(Register dst, AMD64Address src) { prefixq(src, dst); emitByte(0x63); emitOperandHelper(dst, src); @@ -2643,73 +2191,18 @@ emitByte(0xC0 | encode); } - public final void movswq(Register dst, Address src) { - prefixq(src, dst); - emitByte(0x0F); - emitByte(0xBF); - emitOperandHelper(dst, src); - } - - public final void movswq(Register dst, Register src) { - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xBF); - emitByte(0xC0 | encode); - } - - public final void movzbq(Register dst, Address src) { - prefixq(src, dst); - emitByte(0x0F); - emitByte(0xB6); - emitOperandHelper(dst, src); - } - - public final void movzbq(Register dst, Register src) { - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xB6); - emitByte(0xC0 | encode); - } - - public final void movzwq(Register dst, Address src) { - prefixq(src, dst); - emitByte(0x0F); - emitByte(0xB7); - emitOperandHelper(dst, src); - } - - public final void movzwq(Register dst, Register src) { - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x0F); - emitByte(0xB7); - emitByte(0xC0 | encode); - } - public final void negq(Register dst) { int encode = prefixqAndEncode(dst.encoding); emitByte(0xF7); emitByte(0xD8 | encode); } - public final void notq(Register dst) { - int encode = prefixqAndEncode(dst.encoding); - emitByte(0xF7); - emitByte(0xD0 | encode); - } - - public final void orq(Address dst, int imm32) { - prefixq(dst); - emitByte(0x81); - emitOperandHelper(rcx, dst); - emitInt(imm32); - } - public final void orq(Register dst, int imm32) { prefixqAndEncode(dst.encoding); emitArith(0x81, 0xC8, dst, imm32); } - public final void orq(Register dst, Address src) { + public final void orq(Register dst, AMD64Address src) { prefixq(src, dst); emitByte(0x0B); emitOperandHelper(dst, src); @@ -2720,31 +2213,6 @@ emitArith(0x0B, 0xC0, dst, src); } - public final void popq(Address dst) { - prefixq(dst); - emitByte(0x8F); - emitOperandHelper(rax, dst); - } - - public final void pushq(Address src) { - prefixq(src); - emitByte(0xFF); - emitOperandHelper(rsi, src); - } - - public final void rclq(Register dst, int imm8) { - assert isShiftCount(imm8 >> 1) : "illegal shift count"; - int encode = prefixqAndEncode(dst.encoding); - if (imm8 == 1) { - emitByte(0xD1); - emitByte(0xD0 | encode); - } else { - emitByte(0xC1); - emitByte(0xD0 | encode); - emitByte(imm8); - } - } - public final void sarq(Register dst, int imm8) { assert isShiftCount(imm8 >> 1) : "illegal shift count"; int encode = prefixqAndEncode(dst.encoding); @@ -2797,41 +2265,12 @@ emitByte(0xE8 | encode); } - public final void sqrtsd(Register dst, Address src) { - assert dst.isFpu(); - - emitByte(0xF2); - prefix(src, dst); - emitByte(0x0F); - emitByte(0x51); - emitOperandHelper(dst, src); - } - - public final void subq(Address dst, int imm32) { - prefixq(dst); - if (isByte(imm32)) { - emitByte(0x83); - emitOperandHelper(rbp, dst); - emitByte(imm32 & 0xFF); - } else { - emitByte(0x81); - emitOperandHelper(rbp, dst); - emitInt(imm32); - } - } - public final void subq(Register dst, int imm32) { prefixqAndEncode(dst.encoding); emitArith(0x81, 0xE8, dst, imm32); } - public final void subq(Address dst, Register src) { - prefixq(dst, src); - emitByte(0x29); - emitOperandHelper(src, dst); - } - - public final void subq(Register dst, Address src) { + public final void subq(Register dst, AMD64Address src) { prefixq(src, dst); emitByte(0x2B); emitOperandHelper(dst, src); @@ -2863,31 +2302,12 @@ emitArith(0x85, 0xC0, dst, src); } - public final void testq(Register dst, Address src) { + public final void testq(Register dst, AMD64Address src) { prefixq(src, dst); emitByte(0x85); emitOperandHelper(dst, src); } - public final void xaddq(Address dst, Register src) { - prefixq(dst, src); - emitByte(0x0F); - emitByte(0xC1); - emitOperandHelper(src, dst); - } - - public final void xchgq(Register dst, Address src) { - prefixq(src, dst); - emitByte(0x87); - emitOperandHelper(dst, src); - } - - public final void xchgq(Register dst, Register src) { - int encode = prefixqAndEncode(dst.encoding, src.encoding); - emitByte(0x87); - emitByte(0xc0 | encode); - } - public final void xorq(Register dst, int imm32) { prefixqAndEncode(dst.encoding); emitArith(0x81, 0xF0, dst, imm32); @@ -2898,12 +2318,10 @@ emitArith(0x33, 0xC0, dst, src); } - public final void xorq(Register dst, Address src) { - + public final void xorq(Register dst, AMD64Address src) { prefixq(src, dst); emitByte(0x33); emitOperandHelper(dst, src); - } public final void membar(int barriers) { @@ -2919,7 +2337,7 @@ // the code where this idiom is used, in particular the // orderAccess code. lock(); - addl(new Address(Word, RSP, 0), 0); // Assert the lock# signal here + addl(new AMD64Address(rsp, 0), 0); // Assert the lock# signal here } } } @@ -2960,7 +2378,7 @@ } public void nullCheck(Register r) { - testl(AMD64.rax, new Address(Word, r.asValue(Word), 0)); + testl(AMD64.rax, new AMD64Address(r, 0)); } @Override @@ -2970,26 +2388,6 @@ } } - public void pushfq() { - emitByte(0x9c); - } - - public void popfq() { - emitByte(0x9D); - } - - /** - * Makes sure that a subsequent {@linkplain #call} does not fail the alignment check. - */ - public final void alignForPatchableDirectCall() { - int dispStart = codeBuffer.position() + 1; - int mask = target.wordSize - 1; - if ((dispStart & ~mask) != ((dispStart + 3) & ~mask)) { - nop(target.wordSize - (dispStart & mask)); - assert ((codeBuffer.position() + 1) & mask) == 0; - } - } - /** * Emits a direct call instruction. Note that the actual call target is not specified, because * all calls need patching anyway. Therefore, 0 is emitted as the call target, and the user is @@ -3006,74 +2404,67 @@ emitByte(0xD0 | encode); } - public void int3() { + public final void int3() { emitByte(0xCC); } - public void enter(short imm16, byte imm8) { - emitByte(0xC8); - // appended: - emitByte(imm16 & 0xff); - emitByte((imm16 >> 8) & 0xff); - emitByte(imm8); - } - private void emitx87(int b1, int b2, int i) { assert 0 <= i && i < 8 : "illegal stack offset"; emitByte(b1); emitByte(b2 + i); } - public void fld(Address src) { + public final void fld(AMD64Address src) { emitByte(0xDD); - emitOperandHelper(rax, src); + emitOperandHelper(0, src); } - public void fld(int i) { - emitx87(0xD9, 0xC0, i); - } - - public void fldln2() { + public final void fldln2() { emitByte(0xD9); emitByte(0xED); } - public void fldlg2() { + public final void fldlg2() { emitByte(0xD9); emitByte(0xEC); } - public void fyl2x() { + public final void fyl2x() { emitByte(0xD9); emitByte(0xF1); } - public void fstp(Address src) { + public final void fstp(AMD64Address src) { emitByte(0xDD); - emitOperandHelper(rbx, src); + emitOperandHelper(3, src); } - public void fsin() { + public final void fsin() { emitByte(0xD9); emitByte(0xFE); } - public void fcos() { + public final void fcos() { emitByte(0xD9); emitByte(0xFF); } - public void fptan() { + public final void fptan() { emitByte(0xD9); emitByte(0xF2); } - public void fstp(int i) { + public final void fstp(int i) { emitx87(0xDD, 0xD8, i); } @Override - public void bangStack(int disp) { - movq(new Address(target.wordKind, AMD64.RSP, -disp), AMD64.rax); + public AMD64Address makeAddress(Register base, int displacement) { + return new AMD64Address(base, displacement); + } + + @Override + public AMD64Address getPlaceholder() { + return Placeholder; } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java --- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -26,8 +26,6 @@ import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.*; /** * This class implements commonly used X86 code patterns. @@ -38,25 +36,11 @@ super(target, registerConfig); } - public void pushptr(Address src) { - pushq(src); - } - - public void popptr(Address src) { - popq(src); - } - - public void xorptr(Register dst, Register src) { + public final void xorptr(Register dst, Register src) { xorq(dst, src); } - public void xorptr(Register dst, Address src) { - xorq(dst, src); - } - - // 64 bit versions - - public void decrementq(Register reg, int value) { + public final void decrementq(Register reg, int value) { if (value == Integer.MIN_VALUE) { subq(reg, value); return; @@ -94,83 +78,19 @@ } } - // These are mostly for initializing null - public void movptr(Address dst, int src) { + public final void movptr(AMD64Address dst, int src) { movslq(dst, src); } - public final void cmp32(Register src1, int imm) { - cmpl(src1, imm); - } - - public final void cmp32(Register src1, Address src2) { - cmpl(src1, src2); - } - - public void cmpsd2int(Register opr1, Register opr2, Register dst, boolean unorderedIsLess) { - assert opr1.isFpu() && opr2.isFpu(); - ucomisd(opr1, opr2); - - Label l = new Label(); - if (unorderedIsLess) { - movl(dst, -1); - jcc(AMD64Assembler.ConditionFlag.parity, l); - jcc(AMD64Assembler.ConditionFlag.below, l); - movl(dst, 0); - jcc(AMD64Assembler.ConditionFlag.equal, l); - incrementl(dst, 1); - } else { // unordered is greater - movl(dst, 1); - jcc(AMD64Assembler.ConditionFlag.parity, l); - jcc(AMD64Assembler.ConditionFlag.above, l); - movl(dst, 0); - jcc(AMD64Assembler.ConditionFlag.equal, l); - decrementl(dst, 1); - } - bind(l); - } - - public void cmpss2int(Register opr1, Register opr2, Register dst, boolean unorderedIsLess) { - assert opr1.isFpu(); - assert opr2.isFpu(); - ucomiss(opr1, opr2); - - Label l = new Label(); - if (unorderedIsLess) { - movl(dst, -1); - jcc(AMD64Assembler.ConditionFlag.parity, l); - jcc(AMD64Assembler.ConditionFlag.below, l); - movl(dst, 0); - jcc(AMD64Assembler.ConditionFlag.equal, l); - incrementl(dst, 1); - } else { // unordered is greater - movl(dst, 1); - jcc(AMD64Assembler.ConditionFlag.parity, l); - jcc(AMD64Assembler.ConditionFlag.above, l); - movl(dst, 0); - jcc(AMD64Assembler.ConditionFlag.equal, l); - decrementl(dst, 1); - } - bind(l); - } - - public void cmpptr(Register src1, Register src2) { + public final void cmpptr(Register src1, Register src2) { cmpq(src1, src2); } - public void cmpptr(Register src1, Address src2) { + public final void cmpptr(Register src1, AMD64Address src2) { cmpq(src1, src2); } - public void cmpptr(Register src1, int src2) { - cmpq(src1, src2); - } - - public void cmpptr(Address src1, int src2) { - cmpq(src1, src2); - } - - public void decrementl(Register reg, int value) { + public final void decrementl(Register reg, int value) { if (value == Integer.MIN_VALUE) { subl(reg, value); return; @@ -189,7 +109,7 @@ } } - public void decrementl(Address dst, int value) { + public final void decrementl(AMD64Address dst, int value) { if (value == Integer.MIN_VALUE) { subl(dst, value); return; @@ -208,7 +128,7 @@ } } - public void incrementl(Register reg, int value) { + public final void incrementl(Register reg, int value) { if (value == Integer.MIN_VALUE) { addl(reg, value); return; @@ -227,7 +147,7 @@ } } - public void incrementl(Address dst, int value) { + public final void incrementl(AMD64Address dst, int value) { if (value == Integer.MIN_VALUE) { addl(dst, value); return; @@ -246,21 +166,20 @@ } } - public void signExtendByte(Register reg) { + public final void signExtendByte(Register reg) { if (reg.isByte()) { - movsxb(reg, reg); // movsxb + movsxb(reg, reg); } else { shll(reg, 24); sarl(reg, 24); } } - public void signExtendShort(Register reg) { - movsxw(reg, reg); // movsxw + public final void signExtendShort(Register reg) { + movsxw(reg, reg); } - // Support optimal SSE move instructions. - public void movflt(Register dst, Register src) { + public final void movflt(Register dst, Register src) { assert dst.isFpu() && src.isFpu(); if (UseXmmRegToRegMoveAll) { movaps(dst, src); @@ -269,17 +188,17 @@ } } - public void movflt(Register dst, Address src) { + public final void movflt(Register dst, AMD64Address src) { assert dst.isFpu(); movss(dst, src); } - public void movflt(Address dst, Register src) { + public final void movflt(AMD64Address dst, Register src) { assert src.isFpu(); movss(dst, src); } - public void movdbl(Register dst, Register src) { + public final void movdbl(Register dst, Register src) { assert dst.isFpu() && src.isFpu(); if (UseXmmRegToRegMoveAll) { movapd(dst, src); @@ -288,7 +207,7 @@ } } - public void movdbl(Register dst, Address src) { + public final void movdbl(Register dst, AMD64Address src) { assert dst.isFpu(); if (UseXmmLoadAndClearUpper) { movsd(dst, src); @@ -297,75 +216,65 @@ } } - public void movdbl(Address dst, Register src) { - assert src.isFpu(); - movsd(dst, src); - } - /** * Non-atomic write of a 64-bit constant to memory. Do not use if the address might be a * volatile field! */ - public void movlong(Address dst, long src) { - Address high = new Address(dst.getKind(), dst.getBase(), dst.getIndex(), dst.getScale(), dst.getDisplacement() + 4); + public final void movlong(AMD64Address dst, long src) { + AMD64Address high = new AMD64Address(dst.getBase(), dst.getIndex(), dst.getScale(), dst.getDisplacement() + 4); movl(dst, (int) (src & 0xFFFFFFFF)); movl(high, (int) (src >> 32)); } - public void xchgptr(Register src1, Register src2) { - xchgq(src1, src2); - } + public final void flog(Register dest, Register value, boolean base10) { + assert dest.isFpu() && value.isFpu(); - public void flog(Register dest, Register value, boolean base10) { - assert value.spillSlotSize == dest.spillSlotSize; - - Address tmp = new Address(Kind.Double, AMD64.RSP); + AMD64Address tmp = new AMD64Address(AMD64.rsp); if (base10) { fldlg2(); } else { fldln2(); } - subq(AMD64.rsp, value.spillSlotSize); + subq(AMD64.rsp, 8); movsd(tmp, value); fld(tmp); fyl2x(); - fstp(tmp); - movsd(dest, tmp); - addq(AMD64.rsp, dest.spillSlotSize); + trigEpilogue(dest, tmp); } - public void fsin(Register dest, Register value) { - ftrig(dest, value, 's'); + public final void fsin(Register dest, Register value) { + AMD64Address tmp = trigPrologue(value); + fsin(); + trigEpilogue(dest, tmp); } - public void fcos(Register dest, Register value) { - ftrig(dest, value, 'c'); - } - - public void ftan(Register dest, Register value) { - ftrig(dest, value, 't'); + public final void fcos(Register dest, Register value) { + AMD64Address tmp = trigPrologue(value); + fcos(); + trigEpilogue(dest, tmp); } - private void ftrig(Register dest, Register value, char op) { - assert value.spillSlotSize == dest.spillSlotSize; + public final void ftan(Register dest, Register value) { + AMD64Address tmp = trigPrologue(value); + fptan(); + fstp(0); // ftan pushes 1.0 in addition to the actual result, pop + trigEpilogue(dest, tmp); + } - Address tmp = new Address(Kind.Double, AMD64.RSP); - subq(AMD64.rsp, value.spillSlotSize); + private AMD64Address trigPrologue(Register value) { + assert value.isFpu(); + AMD64Address tmp = new AMD64Address(AMD64.rsp); + subq(AMD64.rsp, 8); movsd(tmp, value); fld(tmp); - if (op == 's') { - fsin(); - } else if (op == 'c') { - fcos(); - } else if (op == 't') { - fptan(); - fstp(0); // ftan pushes 1.0 in addition to the actual result, pop - } else { - throw new InternalError("should not reach here"); - } + return tmp; + } + + private void trigEpilogue(Register dest, AMD64Address tmp) { + assert dest.isFpu(); fstp(tmp); movsd(dest, tmp); - addq(AMD64.rsp, dest.spillSlotSize); + addq(AMD64.rsp, 8); } /** @@ -375,19 +284,17 @@ * @param csl the description of the CSA * @param frameToCSA offset from the frame pointer to the CSA */ - public void save(CalleeSaveLayout csl, int frameToCSA) { - RegisterValue frame = frameRegister.asValue(); + public final void save(CalleeSaveLayout csl, int frameToCSA) { for (Register r : csl.registers) { int offset = csl.offsetOf(r); - movq(new Address(target.wordKind, frame, frameToCSA + offset), r); + movq(new AMD64Address(frameRegister, frameToCSA + offset), r); } } - public void restore(CalleeSaveLayout csl, int frameToCSA) { - RegisterValue frame = frameRegister.asValue(); + public final void restore(CalleeSaveLayout csl, int frameToCSA) { for (Register r : csl.registers) { int offset = csl.offsetOf(r); - movq(r, new Address(target.wordKind, frame, frameToCSA + offset)); + movq(r, new AMD64Address(frameRegister, frameToCSA + offset)); } } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/AbstractPTXAssembler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/AbstractPTXAssembler.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,63 @@ +/* + * 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.asm.ptx; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.asm.*; + +/** + * The platform-dependent base class for the PTX assembler. + */ +public abstract class AbstractPTXAssembler extends AbstractAssembler { + + public AbstractPTXAssembler(TargetDescription target) { + super(target); + } + + public static final String UNBOUND_TARGET = "L" + Integer.MAX_VALUE; + + @Override + public final void bind(Label l) { + super.bind(l); + emitString0("L" + l.toString() + ":\n"); + } + + @Override + public void align(int modulus) { + // TODO Auto-generated method stub + } + + @Override + public void jmp(Label l) { + // TODO Auto-generated method stub + } + + @Override + protected void patchJumpTarget(int branch, int jumpTarget) { + final int spaces = UNBOUND_TARGET.length(); + String targetString = String.format("L%-" + spaces + "s", jumpTarget + ";"); + int offset = "\tbra ".length(); // XXX we need a better way to figure this out + codeBuffer.emitString(targetString, branch + offset); + } + +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAddress.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAddress.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,72 @@ +/* + * 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.asm.ptx; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; + +/** + * Represents an address in target machine memory, specified via some combination of a base register + * and a displacement. + */ +public final class PTXAddress extends AbstractAddress { + + private final Register base; + private final long displacement; + + /** + * Creates an {@link PTXAddress} with given base register and no displacement. + * + * @param base the base register + */ + public PTXAddress(Register base) { + this(base, 0); + } + + /** + * Creates an {@link PTXAddress} with given base register and a displacement. This is the most + * general constructor. + * + * @param base the base register + * @param displacement the displacement + */ + public PTXAddress(Register base, long displacement) { + this.base = base; + this.displacement = displacement; + } + + /** + * @return Base register that defines the start of the address computation. If not present, is + * denoted by {@link Value#ILLEGAL}. + */ + public Register getBase() { + return base; + } + + /** + * @return Optional additive displacement. + */ + public long getDisplacement() { + return displacement; + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAsmOptions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAsmOptions.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,27 @@ +/* + * 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.asm.ptx; + +public class PTXAsmOptions { + // Nothing for now +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,752 @@ +/* + * 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.asm.ptx; + +import com.oracle.graal.api.code.*; + +public class PTXAssembler extends AbstractPTXAssembler { + + @SuppressWarnings("unused") + public PTXAssembler(TargetDescription target, RegisterConfig registerConfig) { + super(target); + } + + public final void at() { + emitString("@%p" + " " + ""); + } + + public final void add_s16(Register d, Register a, Register b) { + emitString("add.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void add_s32(Register d, Register a, Register b) { + emitString("add.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void add_s64(Register d, Register a, Register b) { + emitString("add.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void add_s16(Register d, Register a, short s16) { + emitString("add.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s16 + ";" + ""); + } + + public final void add_s32(Register d, Register a, int s32) { + emitString("add.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s32 + ";" + ""); + } + + public final void add_s64(Register d, Register a, long s64) { + emitString("add.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s64 + ";" + ""); + } + + public final void add_u16(Register d, Register a, Register b) { + emitString("add.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void add_u32(Register d, Register a, Register b) { + emitString("add.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void add_u64(Register d, Register a, Register b) { + emitString("add.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void add_u16(Register d, Register a, short u16) { + emitString("add.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u16 + ";" + ""); + } + + public final void add_u32(Register d, Register a, int u32) { + emitString("add.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void add_u64(Register d, Register a, long u64) { + emitString("add.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u64 + ";" + ""); + } + + public final void add_sat_s32(Register d, Register a, Register b) { + emitString("add.sat.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void add_sat_s32(Register d, Register a, int s32) { + emitString("add.sat.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s32 + ";" + ""); + } + + public final void and_b16(Register d, Register a, Register b) { + emitString("and.b16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void and_b32(Register d, Register a, Register b) { + emitString("and.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void and_b64(Register d, Register a, Register b) { + emitString("and.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void and_b16(Register d, Register a, short b16) { + emitString("and.b16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b16 + ";" + ""); + } + + public final void and_b32(Register d, Register a, int b32) { + emitString("and.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b32 + ";" + ""); + } + + public final void and_b64(Register d, Register a, long b64) { + emitString("and.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + b64 + ";" + ""); + } + + public final void bra(String tgt) { + emitString("bra" + " " + tgt + ";" + ""); + } + + public final void bra_uni(String tgt) { + emitString("bra.uni" + " " + tgt + ";" + ""); + } + + public final void div_s16(Register d, Register a, Register b) { + emitString("div.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void div_s32(Register d, Register a, Register b) { + emitString("div.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void div_s64(Register d, Register a, Register b) { + emitString("div.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void div_s16(Register d, Register a, short s16) { + emitString("div.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s16 + ";" + ""); + } + + public final void div_s32(Register d, Register a, int s32) { + emitString("div.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s32 + ";" + ""); + } + + 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_u16(Register d, Register a, Register b) { + emitString("div.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void div_u32(Register d, Register a, Register b) { + emitString("div.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void div_u64(Register d, Register a, Register b) { + emitString("div.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void div_u16(Register d, Register a, short u16) { + emitString("div.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u16 + ";" + ""); + } + + public final void div_u32(Register d, Register a, int u32) { + emitString("div.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void div_u64(Register d, Register a, long u64) { + emitString("div.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u64 + ";" + ""); + } + + public final void exit() { + emitString("exit;" + " " + ""); + } + + public final void ld_global_b8(Register d, Register a, long immOff) { + emitString("ld.global.b8" + " " + "%r" + d.encoding() + ", [%r" + a.encoding() + " + " + immOff + "]" + ";" + ""); + } + + public final void ld_global_b16(Register d, Register a, long immOff) { + emitString("ld.global.b16" + " " + "%r" + d.encoding() + ", [%r" + a.encoding() + " + " + immOff + "]" + ";" + ""); + } + + public final void ld_global_b32(Register d, Register a, long immOff) { + emitString("ld.global.b32" + " " + "%r" + d.encoding() + ", [%r" + a.encoding() + " + " + immOff + "]" + ";" + ""); + } + + public final void ld_global_b64(Register d, Register a, long immOff) { + emitString("ld.global.b64" + " " + "%r" + d.encoding() + ", [%r" + a.encoding() + " + " + immOff + "]" + ";" + ""); + } + + public final void ld_global_u8(Register d, Register a, long immOff) { + emitString("ld.global.u8" + " " + "%r" + d.encoding() + ", [%r" + a.encoding() + " + " + immOff + "]" + ";" + ""); + } + + public final void ld_global_u16(Register d, Register a, long immOff) { + emitString("ld.global.u16" + " " + "%r" + d.encoding() + ", [%r" + a.encoding() + " + " + immOff + "]" + ";" + ""); + } + + public final void ld_global_u32(Register d, Register a, long immOff) { + emitString("ld.global.u32" + " " + "%r" + d.encoding() + ", [%r" + a.encoding() + " + " + immOff + "]" + ";" + ""); + } + + public final void ld_global_u64(Register d, Register a, long immOff) { + emitString("ld.global.u64" + " " + "%r" + d.encoding() + ", [%r" + a.encoding() + " + " + immOff + "]" + ";" + ""); + } + + public final void ld_global_s8(Register d, Register a, long immOff) { + emitString("ld.global.s8" + " " + "%r" + d.encoding() + ", [%r" + a.encoding() + " + " + immOff + "]" + ";" + ""); + } + + public final void ld_global_s16(Register d, Register a, long immOff) { + emitString("ld.global.s16" + " " + "%r" + d.encoding() + ", [%r" + a.encoding() + " + " + immOff + "]" + ";" + ""); + } + + public final void ld_global_s32(Register d, Register a, long immOff) { + emitString("ld.global.s32" + " " + "%r" + d.encoding() + ", [%r" + a.encoding() + " + " + immOff + "]" + ";" + ""); + } + + public final void ld_global_s64(Register d, Register a, long immOff) { + emitString("ld.global.s64" + " " + "%r" + d.encoding() + ", [%r" + a.encoding() + " + " + immOff + "]" + ";" + ""); + } + + public final void ld_global_f32(Register d, Register a, long immOff) { + emitString("ld.global.f32" + " " + "%r" + d.encoding() + ", [%r" + a.encoding() + " + " + immOff + "]" + ";" + ""); + } + + public final void ld_global_f64(Register d, Register a, long immOff) { + emitString("ld.global.f64" + " " + "%r" + d.encoding() + ", [%r" + a.encoding() + " + " + immOff + "]" + ";" + ""); + } + + public final void mov_b16(Register d, Register a) { + emitString("mov.b16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void mov_b32(Register d, Register a) { + emitString("mov.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void mov_b64(Register d, Register a) { + emitString("mov.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void mov_u16(Register d, Register a) { + emitString("mov.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void mov_u32(Register d, Register a) { + emitString("mov.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void mov_u64(Register d, Register 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() + ";" + ""); + } + + public final void mov_s32(Register d, Register a) { + emitString("mov.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void mov_s64(Register d, Register a) { + emitString("mov.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void mov_f32(Register d, Register a) { + emitString("mov.f32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void mov_f64(Register d, Register a) { + emitString("mov.f64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void mov_b16(Register d, short b16) { + emitString("mov.b16" + " " + "%r" + d.encoding() + ", " + b16 + ";" + ""); + } + + public final void mov_b32(Register d, int b32) { + emitString("mov.b32" + " " + "%r" + d.encoding() + ", " + b32 + ";" + ""); + } + + public final void mov_b64(Register d, long b64) { + emitString("mov.b64" + " " + "%r" + d.encoding() + ", " + b64 + ";" + ""); + } + + public final void mov_u16(Register d, short u16) { + emitString("mov.u16" + " " + "%r" + d.encoding() + ", " + u16 + ";" + ""); + } + + public final void mov_u32(Register d, int u32) { + emitString("mov.u32" + " " + "%r" + d.encoding() + ", " + u32 + ";" + ""); + } + + public final void mov_u64(Register d, long u64) { + emitString("mov.u64" + " " + "%r" + d.encoding() + ", " + u64 + ";" + ""); + } + + public final void mov_s16(Register d, short s16) { + emitString("mov.s16" + " " + "%r" + d.encoding() + ", " + s16 + ";" + ""); + } + + public final void mov_s32(Register d, int s32) { + emitString("mov.s32" + " " + "%r" + d.encoding() + ", " + s32 + ";" + ""); + } + + public final void mov_s64(Register d, long s64) { + emitString("mov.s64" + " " + "%r" + d.encoding() + ", " + s64 + ";" + ""); + } + + public final void mov_f32(Register d, float f32) { + emitString("mov.f32" + " " + "%r" + d.encoding() + ", " + f32 + ";" + ""); + } + + public final void mov_f64(Register d, double f64) { + emitString("mov.f64" + " " + "%r" + d.encoding() + ", " + f64 + ";" + ""); + } + + public final void mul_s16(Register d, Register a, Register b) { + emitString("mul.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void mul_s32(Register d, Register a, Register b) { + emitString("mul.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void mul_s64(Register d, Register a, Register b) { + emitString("mul.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void mul_s16(Register d, Register a, short s16) { + emitString("mul.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s16 + ";" + ""); + } + + public final void mul_s32(Register d, Register a, int s32) { + emitString("mul.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s32 + ";" + ""); + } + + public final void mul_s64(Register d, Register a, long s64) { + emitString("mul.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s64 + ";" + ""); + } + + public final void mul_u16(Register d, Register a, Register b) { + emitString("mul.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void mul_u32(Register d, Register a, Register b) { + emitString("mul.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void mul_u64(Register d, Register a, Register b) { + emitString("mul.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void mul_u16(Register d, Register a, short u16) { + emitString("mul.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u16 + ";" + ""); + } + + public final void mul_u32(Register d, Register a, int u32) { + emitString("mul.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void mul_u64(Register d, Register a, long u64) { + emitString("mul.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u64 + ";" + ""); + } + + public final void neg_s16(Register d, Register a) { + emitString("neg.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void neg_s32(Register d, Register a) { + emitString("neg.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void neg_s64(Register d, Register a) { + emitString("neg.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void popc_b32(Register d, Register a) { + emitString("popc.b32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void popc_b64(Register d, Register a) { + emitString("popc.b64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ";" + ""); + } + + public final void rem_s16(Register d, Register a, Register b) { + emitString("rem.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void rem_s32(Register d, Register a, Register b) { + emitString("rem.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void rem_s64(Register d, Register a, Register b) { + emitString("rem.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void rem_s16(Register d, Register a, short s16) { + emitString("rem.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s16 + ";" + ""); + } + + public final void rem_s32(Register d, Register a, int s32) { + emitString("rem.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s32 + ";" + ""); + } + + public final void rem_s64(Register d, Register a, long s64) { + emitString("rem.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s64 + ";" + ""); + } + + public final void rem_u16(Register d, Register a, Register b) { + emitString("rem.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void rem_u32(Register d, Register a, Register b) { + emitString("rem.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void rem_u64(Register d, Register a, Register b) { + emitString("rem.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void rem_u16(Register d, Register a, short u16) { + emitString("rem.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u16 + ";" + ""); + } + + public final void rem_u32(Register d, Register a, int u32) { + emitString("rem.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void rem_u64(Register d, Register a, long u64) { + emitString("rem.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u64 + ";" + ""); + } + + public final void ret() { + emitString("ret;" + " " + ""); + } + + public final void ret_uni() { + emitString("ret.uni;" + " " + ""); + } + + public final void setp_eq_s32(Register a, Register b) { + emitString("setp.eq.s32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_ne_s32(Register a, Register b) { + emitString("setp.ne.s32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_lt_s32(Register a, Register b) { + emitString("setp.lt.s32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_le_s32(Register a, Register b) { + emitString("setp.le.s32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_gt_s32(Register a, Register b) { + emitString("setp.gt.s32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_ge_s32(Register a, Register b) { + emitString("setp.ge.s32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_eq_s32(Register a, int s32) { + emitString("setp.eq.s32" + " " + "%p" + ", %r" + a.encoding() + ", " + s32 + ";" + ""); + } + + public final void setp_ne_s32(Register a, int s32) { + emitString("setp.ne.s32" + " " + "%p" + ", %r" + a.encoding() + ", " + s32 + ";" + ""); + } + + public final void setp_lt_s32(Register a, int s32) { + emitString("setp.lt.s32" + " " + "%p" + ", %r" + a.encoding() + ", " + s32 + ";" + ""); + } + + public final void setp_le_s32(Register a, int s32) { + emitString("setp.le.s32" + " " + "%p" + ", %r" + a.encoding() + ", " + s32 + ";" + ""); + } + + public final void setp_gt_s32(Register a, int s32) { + emitString("setp.gt.s32" + " " + "%p" + ", %r" + a.encoding() + ", " + s32 + ";" + ""); + } + + public final void setp_ge_s32(Register a, int s32) { + emitString("setp.ge.s32" + " " + "%p" + ", %r" + a.encoding() + ", " + s32 + ";" + ""); + } + + public final void setp_eq_s32(int s32, Register b) { + emitString("setp.eq.s32" + " " + "%p" + ", " + s32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_ne_s32(int s32, Register b) { + emitString("setp.ne.s32" + " " + "%p" + ", " + s32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_lt_s32(int s32, Register b) { + emitString("setp.lt.s32" + " " + "%p" + ", " + s32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_le_s32(int s32, Register b) { + emitString("setp.le.s32" + " " + "%p" + ", " + s32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_gt_s32(int s32, Register b) { + emitString("setp.gt.s32" + " " + "%p" + ", " + s32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_ge_s32(int s32, Register b) { + emitString("setp.ge.s32" + " " + "%p" + ", " + s32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_eq_u32(Register a, Register b) { + emitString("setp.eq.u32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_ne_u32(Register a, Register b) { + emitString("setp.ne.u32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_lt_u32(Register a, Register b) { + emitString("setp.lt.u32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_le_u32(Register a, Register b) { + emitString("setp.le.u32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_gt_u32(Register a, Register b) { + emitString("setp.gt.u32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_ge_u32(Register a, Register b) { + emitString("setp.ge.u32" + " " + "%p" + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_eq_u32(Register a, int u32) { + emitString("setp.eq.u32" + " " + "%p" + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void setp_ne_u32(Register a, int u32) { + emitString("setp.ne.u32" + " " + "%p" + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void setp_lt_u32(Register a, int u32) { + emitString("setp.lt.u32" + " " + "%p" + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void setp_le_u32(Register a, int u32) { + emitString("setp.le.u32" + " " + "%p" + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void setp_gt_u32(Register a, int u32) { + emitString("setp.gt.u32" + " " + "%p" + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void setp_ge_u32(Register a, int u32) { + emitString("setp.ge.u32" + " " + "%p" + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void setp_eq_u32(int u32, Register b) { + emitString("setp.eq.u32" + " " + "%p" + ", " + u32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_ne_u32(int u32, Register b) { + emitString("setp.ne.u32" + " " + "%p" + ", " + u32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_lt_u32(int u32, Register b) { + emitString("setp.lt.u32" + " " + "%p" + ", " + u32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_le_u32(int u32, Register b) { + emitString("setp.le.u32" + " " + "%p" + ", " + u32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_gt_u32(int u32, Register b) { + emitString("setp.gt.u32" + " " + "%p" + ", " + u32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void setp_ge_u32(int u32, Register b) { + emitString("setp.ge.u32" + " " + "%p" + ", " + u32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void shr_s16(Register d, Register a, Register b) { + emitString("shr.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void shr_s32(Register d, Register a, Register b) { + emitString("shr.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void shr_s64(Register d, Register a, Register b) { + emitString("shr.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void shr_s16(Register d, Register a, int u32) { + emitString("shr.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void shr_s32(Register d, Register a, int u32) { + emitString("shr.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void shr_s64(Register d, Register a, int u32) { + emitString("shr.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void shr_u16(Register d, Register a, Register b) { + emitString("shr.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void shr_u32(Register d, Register a, Register b) { + emitString("shr.u32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void shr_u64(Register d, Register a, Register b) { + emitString("shr.u64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void shr_u16(Register d, Register a, int u32) { + emitString("shr.u16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + u32 + ";" + ""); + } + + public final void shr_u32(Register d, Register a, int u32) { + 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 st_global_b8(Register a, long immOff, Register b) { + emitString("st.global.b8" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + ""); + } + + public final void st_global_b16(Register a, long immOff, Register b) { + emitString("st.global.b16" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + ""); + } + + public final void st_global_b32(Register a, long immOff, Register b) { + emitString("st.global.b32" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + ""); + } + + public final void st_global_b64(Register a, long immOff, Register b) { + emitString("st.global.b64" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + ""); + } + + public final void st_global_u8(Register a, long immOff, Register b) { + emitString("st.global.u8" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + ""); + } + + public final void st_global_u16(Register a, long immOff, Register b) { + emitString("st.global.u16" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + ""); + } + + public final void st_global_u32(Register a, long immOff, Register b) { + emitString("st.global.u32" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + ""); + } + + public final void st_global_u64(Register a, long immOff, Register b) { + emitString("st.global.u64" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + ""); + } + + public final void st_global_s8(Register a, long immOff, Register b) { + emitString("st.global.s8" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + ""); + } + + public final void st_global_s16(Register a, long immOff, Register b) { + emitString("st.global.s16" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + ""); + } + + public final void st_global_s32(Register a, long immOff, Register b) { + emitString("st.global.s32" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + ""); + } + + public final void st_global_s64(Register a, long immOff, Register b) { + emitString("st.global.s64" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + ""); + } + + public final void st_global_f32(Register a, long immOff, Register b) { + emitString("st.global.f32" + " " + "[%r" + a.encoding() + " + " + immOff + "], %r" + b.encoding() + ";" + ""); + } + + public final void st_global_f64(Register a, long immOff, Register b) { + emitString("st.global.f64" + " " + "[%r" + a.encoding() + " + " + immOff + "], %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() + ";" + ""); + } + + public final void sub_s32(Register d, Register a, Register b) { + emitString("sub.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void sub_s64(Register d, Register a, Register b) { + emitString("sub.s64" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", %r" + b.encoding() + ";" + ""); + } + + public final void sub_s16(Register d, Register a, short s16) { + emitString("sub.s16" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s16 + ";" + ""); + } + + public final void sub_s32(Register d, Register a, int s32) { + emitString("sub.s32" + " " + "%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_s16(Register d, short s16, Register b) { + emitString("sub.s16" + " " + "%r" + d.encoding() + ", " + s16 + ", %r" + b.encoding() + ";" + ""); + } + + public final void sub_s32(Register d, int s32, Register b) { + emitString("sub.s32" + " " + "%r" + d.encoding() + ", " + s32 + ", %r" + b.encoding() + ";" + ""); + } + + public final void sub_s64(Register d, long s64, Register b) { + emitString("sub.s64" + " " + "%r" + d.encoding() + ", " + s64 + ", %r" + b.encoding() + ";" + ""); + } + + 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() + ";" + ""); + } + + public final void sub_sat_s32(Register d, Register a, int s32) { + emitString("sub.sat.s32" + " " + "%r" + d.encoding() + ", %r" + a.encoding() + ", " + s32 + ";" + ""); + } + + public final void sub_sat_s32(Register d, int s32, Register b) { + emitString("sub.sat.s32" + " " + "%r" + d.encoding() + ", " + s32 + ", %r" + b.encoding() + ";" + ""); + } + + @Override + public PTXAddress makeAddress(Register base, int displacement) { + return new PTXAddress(base, displacement); + } + + @Override + public PTXAddress getPlaceholder() { + // TODO Auto-generated method stub + return null; + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java --- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java Thu Mar 21 14:11:13 2013 +0100 @@ -54,7 +54,14 @@ } @Override - public void bangStack(int disp) { - // SPARC: Implement stack banging. + public AbstractAddress makeAddress(Register base, int displacement) { + // SPARC: Implement address calculation. + return null; + } + + @Override + public AbstractAddress getPlaceholder() { + // SPARC: Implement address patching. + return null; } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.asm.test/src/com/oracle/graal/asm/test/AssemblerTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -47,22 +47,21 @@ protected InstalledCode assembleMethod(Method m, CodeGenTest test) { ResolvedJavaMethod method = codeCache.lookupJavaMethod(m); - RegisterConfig registerConfig = codeCache.lookupRegisterConfig(method); + RegisterConfig registerConfig = codeCache.lookupRegisterConfig(); + CallingConvention cc = CodeUtil.getCallingConvention(codeCache, CallingConvention.Type.JavaCallee, method, false); CompilationResult compResult = new CompilationResult(); - - Signature sig = method.getSignature(); - JavaType retType = sig.getReturnType(null); - JavaType[] argTypes = new JavaType[sig.getParameterCount(false)]; - for (int i = 0; i < argTypes.length; i++) { - argTypes[i] = sig.getParameterType(i, null); - } - CallingConvention cc = registerConfig.getCallingConvention(CallingConvention.Type.JavaCallee, retType, argTypes, codeCache.getTarget(), false); - Buffer codeBuffer = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc); compResult.setTargetCode(codeBuffer.close(true), codeBuffer.position()); - return codeCache.addMethod(method, compResult, null); + InstalledCode code = codeCache.addMethod(method, compResult); + + DisassemblerProvider dis = Graal.getRuntime().getCapability(DisassemblerProvider.class); + if (dis != null) { + String disasm = dis.disassemble(code); + Assert.assertTrue(String.valueOf(code.getMethod()), disasm == null || disasm.length() > 0); + } + return code; } protected Object runTest(String methodName, CodeGenTest test, Object... args) { @@ -73,6 +72,6 @@ protected void assertReturn(String methodName, CodeGenTest test, Object expected, Object... args) { Object actual = runTest(methodName, test, args); - Assert.assertEquals("unexpected return value: " + actual, actual, expected); + Assert.assertEquals("unexpected return value", expected, actual); } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.asm/src/com/oracle/graal/asm/AbstractAssembler.java --- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/AbstractAssembler.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/AbstractAssembler.java Thu Mar 21 14:11:13 2013 +0100 @@ -44,7 +44,7 @@ } } - public final void bind(Label l) { + public void bind(Label l) { assert !l.isBound() : "can bind label only once"; l.bind(codeBuffer.position()); l.patchInstructions(this); @@ -56,14 +56,6 @@ protected abstract void patchJumpTarget(int branch, int jumpTarget); - /** - * Emits instruction(s) that access an address specified by a given displacement from the stack - * pointer in the direction that the stack grows (which is down on most architectures). - * - * @param disp the displacement from the stack pointer at which the stack should be accessed - */ - public abstract void bangStack(int disp); - protected final void emitByte(int x) { codeBuffer.emitByte(x); } @@ -79,4 +71,27 @@ protected final void emitLong(long x) { codeBuffer.emitLong(x); } + + /** + * Some GPU architectures have a text based encoding. + */ + protected final void emitString(String x) { + codeBuffer.emitString(x); + } + + // XXX for pretty-printing + protected final void emitString0(String x) { + codeBuffer.emitString0(x); + } + + /** + * This is used by the TargetMethodAssembler to convert a {@link StackSlot} to an + * {@link AbstractAddress}. + */ + public abstract AbstractAddress makeAddress(Register base, int displacement); + + /** + * Returns a target specific placeholder address that can be used for code patching. + */ + public abstract AbstractAddress getPlaceholder(); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Buffer.java --- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Buffer.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Buffer.java Thu Mar 21 14:11:13 2013 +0100 @@ -37,10 +37,6 @@ data = new byte[AsmOptions.InitialCodeBufferSize]; } - public void reset() { - position = 0; - } - public int position() { return position; } @@ -106,6 +102,27 @@ position = emitLong(b, position); } + private static final String NEWLINE = System.getProperty("line.separator"); + + public void emitString(String s) { + position = emitString("\t", position); // XXX REMOVE ME pretty-printing + position = emitString(s, position); + position = emitString(NEWLINE, position); + } + + // XXX for pretty-printing + public void emitString0(String s) { + emitBytes(s.getBytes(), 0, s.length()); + } + + public int emitBytes(byte[] arr, int pos) { + final int len = arr.length; + final int newPos = pos + len; + ensureSize(newPos); + System.arraycopy(arr, 0, data, pos, len); + return newPos; + } + public int emitByte(int b, int pos) { assert NumUtil.isUByte(b); int newPos = pos + 1; @@ -120,6 +137,10 @@ public abstract int emitLong(long b, int pos); + public int emitString(String s, int pos) { + return emitBytes(s.getBytes(), pos); + } + public int getByte(int pos) { return data[pos] & 0xff; } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/Bytecodes.java --- a/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/Bytecodes.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/Bytecodes.java Thu Mar 21 14:11:13 2013 +0100 @@ -226,7 +226,7 @@ public static final int INVOKESPECIAL = 183; // 0xB7 public static final int INVOKESTATIC = 184; // 0xB8 public static final int INVOKEINTERFACE = 185; // 0xB9 - public static final int XXXUNUSEDXXX = 186; // 0xBA + public static final int INVOKEDYNAMIC = 186; // 0xBA public static final int NEW = 187; // 0xBB public static final int NEWARRAY = 188; // 0xBC public static final int ANEWARRAY = 189; // 0xBD @@ -552,7 +552,7 @@ def(INVOKESPECIAL , "invokespecial" , "bjj" , 5, TRAP | INVOKE); def(INVOKESTATIC , "invokestatic" , "bjj" , 5, TRAP | INVOKE); def(INVOKEINTERFACE , "invokeinterface" , "bjja_", 7, TRAP | INVOKE); - def(XXXUNUSEDXXX , "xxxunusedxxx" , "" , 0); + def(INVOKEDYNAMIC , "invokedynamic" , "bjjjj", 7, TRAP | INVOKE); def(NEW , "new" , "bii" , 6, TRAP); def(NEWARRAY , "newarray" , "bc" , 6, TRAP); def(ANEWARRAY , "anewarray" , "bii" , 6, TRAP); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.compiler.amd64.test/src/com/oracle/graal/compiler/amd64/test/AMD64AllocatorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.amd64.test/src/com/oracle/graal/compiler/amd64/test/AMD64AllocatorTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.amd64.test; + +import org.junit.*; + +import com.oracle.graal.compiler.test.backend.*; + +public class AMD64AllocatorTest extends AllocatorTest { + + @Test + public void test1() { + test("test1snippet", 3, 1, 0); + } + + public static long test1snippet(long x) { + return x + 5; + } + + @Test + public void test2() { + test("test2snippet", 3, 0, 0); + } + + public static long test2snippet(long x) { + return x * 5; + } + + @Ignore + @Test + public void test3() { + test("test3snippet", 4, 1, 0); + } + + public static long test3snippet(long x) { + return x / 3 + x % 3; + } + +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64DeoptimizationStub.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64DeoptimizationStub.java Thu Mar 21 11:30:38 2013 +0100 +++ /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.compiler.amd64; - -import java.util.*; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.*; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.asm.*; -import com.oracle.graal.phases.*; - -public class AMD64DeoptimizationStub extends AMD64Code { - - public static final Descriptor DEOPTIMIZE = new Descriptor("deoptimize", true, void.class); - public static final Descriptor SET_DEOPT_INFO = new Descriptor("setDeoptInfo", true, void.class, Object.class); - - public final Label label = new Label(); - public final LIRFrameState info; - public final DeoptimizationAction action; - public final DeoptimizationReason reason; - public final Object deoptInfo; - - public AMD64DeoptimizationStub(DeoptimizationAction action, DeoptimizationReason reason, LIRFrameState info, Object deoptInfo) { - this.action = action; - this.reason = reason; - this.info = info; - this.deoptInfo = deoptInfo; - } - - private static ArrayList keepAlive = new ArrayList<>(); - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - Register scratch = tasm.frameMap.registerConfig.getScratchRegister(); - - masm.bind(label); - if (GraalOptions.CreateDeoptInfo && deoptInfo != null) { - masm.nop(); - keepAlive.add(deoptInfo.toString()); - AMD64Move.move(tasm, masm, scratch.asValue(), Constant.forObject(deoptInfo)); - AMD64Call.directCall(tasm, masm, tasm.runtime.lookupRuntimeCall(SET_DEOPT_INFO), info); - } - - masm.movl(scratch, tasm.runtime.encodeDeoptActionAndReason(action, reason)); - AMD64Call.directCall(tasm, masm, tasm.runtime.lookupRuntimeCall(DEOPTIMIZE), info); - AMD64Call.shouldNotReachHere(tasm, masm); - } - - @Override - public String description() { - return "deopt stub[reason=" + reason + ", action=" + action + "]"; - } -} diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Thu Mar 21 14:11:13 2013 +0100 @@ -25,8 +25,8 @@ import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.lir.amd64.AMD64Arithmetic.*; +import static com.oracle.graal.lir.amd64.AMD64BitManipulationOp.IntrinsicOpcode.*; import static com.oracle.graal.lir.amd64.AMD64Compare.*; -import static com.oracle.graal.lir.amd64.AMD64BitManipulationOp.IntrinsicOpcode.*; import static com.oracle.graal.lir.amd64.AMD64MathIntrinsicOp.IntrinsicOpcode.*; import com.oracle.graal.amd64.*; @@ -34,21 +34,22 @@ import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; +import com.oracle.graal.asm.amd64.AMD64Address.Scale; import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag; 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.lir.StandardOp.JumpOp; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.DivOp; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.Op1Reg; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.Op1Stack; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.Op2Reg; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.Op2Stack; -import com.oracle.graal.lir.amd64.AMD64Arithmetic.ShiftOp; import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.amd64.AMD64Call.DirectCallOp; -import com.oracle.graal.lir.amd64.AMD64Call.IndirectCallOp; +import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryCommutative; +import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegConst; +import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegReg; +import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegStack; +import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegStackConst; +import com.oracle.graal.lir.amd64.AMD64Arithmetic.DivRemOp; +import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary1Op; +import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2Op; import com.oracle.graal.lir.amd64.AMD64Compare.CompareOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp; @@ -64,12 +65,11 @@ import com.oracle.graal.lir.amd64.AMD64Move.MembarOp; import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp; import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp; -import com.oracle.graal.lir.amd64.AMD64Move.NullCheckOp; -import com.oracle.graal.lir.amd64.AMD64Move.SpillMoveOp; +import com.oracle.graal.lir.amd64.AMD64Move.StackLeaOp; +import com.oracle.graal.lir.amd64.AMD64Move.StoreConstantOp; import com.oracle.graal.lir.amd64.AMD64Move.StoreOp; 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.phases.util.*; @@ -91,7 +91,7 @@ @Override public LIRInstruction createMove(Value result, Value input) { - return new SpillMoveOp(result, input); + return AMD64LIRGenerator.createMove(result, input); } } @@ -137,110 +137,138 @@ } @Override - public Address makeAddress(LocationNode location, ValueNode object) { - Value base = operand(object); - Value index = Value.ILLEGAL; - int scale = 1; - int displacement = location.displacement(); + public Variable emitMove(Value input) { + Variable result = newVariable(input.getKind()); + emitMove(result, input); + return result; + } + private static AMD64LIRInstruction createMove(Value dst, Value src) { + if (isRegister(src) || isStackSlot(dst)) { + return new MoveFromRegOp(dst, src); + } else { + return new MoveToRegOp(dst, src); + } + } + + @Override + public void emitMove(Value dst, Value src) { + append(createMove(dst, src)); + } + + private AMD64AddressValue prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) { + AllocatableValue baseRegister; + int finalDisp = displacement; if (isConstant(base)) { if (asConstant(base).isNull()) { - base = Value.ILLEGAL; + baseRegister = AllocatableValue.UNUSED; } else if (asConstant(base).getKind() != Kind.Object) { long newDisplacement = displacement + asConstant(base).asLong(); if (NumUtil.isInt(newDisplacement)) { assert !runtime.needsDataPatch(asConstant(base)); - displacement = (int) newDisplacement; - base = Value.ILLEGAL; + finalDisp = (int) newDisplacement; + baseRegister = AllocatableValue.UNUSED; } else { - Value newBase = newVariable(Kind.Long); - emitMove(base, newBase); - base = newBase; + Variable newBase = newVariable(Kind.Long); + emitMove(newBase, base); + baseRegister = newBase; } + } else { + baseRegister = load(base); } + } else if (base == Value.ILLEGAL) { + baseRegister = AllocatableValue.UNUSED; + } else { + baseRegister = asAllocatable(base); } - if (location instanceof IndexedLocationNode) { - IndexedLocationNode indexedLoc = (IndexedLocationNode) location; - - index = operand(indexedLoc.index()); - if (indexedLoc.indexScalingEnabled()) { - scale = target().sizeInBytes(location.getValueKind()); - } + AllocatableValue indexRegister; + Scale scaleEnum; + if (index != Value.ILLEGAL && scale != 0) { + scaleEnum = Scale.fromInt(scale); if (isConstant(index)) { - long newDisplacement = displacement + asConstant(index).asLong() * scale; + long newDisplacement = finalDisp + asConstant(index).asLong() * scale; // only use the constant index if the resulting displacement fits into a 32 bit // offset if (NumUtil.isInt(newDisplacement)) { - displacement = (int) newDisplacement; - index = Value.ILLEGAL; + finalDisp = (int) newDisplacement; + indexRegister = AllocatableValue.UNUSED; } else { // create a temporary variable for the index, the pointer load cannot handle a // constant index - Value newIndex = newVariable(Kind.Long); - emitMove(index, newIndex); - index = newIndex; + Variable newIndex = newVariable(Kind.Long); + emitMove(newIndex, index); + indexRegister = newIndex; } + } else { + indexRegister = asAllocatable(index); } + } else { + indexRegister = AllocatableValue.UNUSED; + scaleEnum = Scale.Times1; } - return new Address(location.getValueKind(), base, index, Address.Scale.fromInt(scale), displacement); + return new AMD64AddressValue(kind, baseRegister, indexRegister, scaleEnum, finalDisp); } @Override - public Variable emitMove(Value input) { - Variable result = newVariable(input.getKind()); - emitMove(input, result); - return result; - } - - @Override - public void emitMove(Value src, Value dst) { - if (isRegister(src) || isStackSlot(dst)) { - append(new MoveFromRegOp(dst, src)); - } else { - append(new MoveToRegOp(dst, src)); - } - } - - @Override - public Variable emitLoad(Value loadAddress, boolean canTrap) { + public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap) { + AMD64AddressValue loadAddress = prepareAddress(kind, base, displacement, index, scale); Variable result = newVariable(loadAddress.getKind()); append(new LoadOp(result, loadAddress, canTrap ? state() : null)); return result; } @Override - public void emitStore(Value storeAddress, Value inputVal, boolean canTrap) { - Value input = loadForStore(inputVal, storeAddress.getKind()); - append(new StoreOp(storeAddress, input, canTrap ? state() : null)); + public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, boolean canTrap) { + AMD64AddressValue storeAddress = prepareAddress(kind, base, displacement, index, scale); + LIRFrameState state = canTrap ? state() : null; + + if (isConstant(inputVal)) { + Constant c = asConstant(inputVal); + if (canStoreConstant(c)) { + append(new StoreConstantOp(storeAddress, c, state)); + return; + } + } + + Variable input = load(inputVal); + append(new StoreOp(storeAddress, input, state)); } @Override - public Variable emitLea(Value address) { + public Variable emitLea(Value base, int displacement, Value index, int scale) { Variable result = newVariable(target().wordKind); + AMD64AddressValue address = prepareAddress(result.getKind(), base, displacement, index, scale); append(new LeaOp(result, address)); return result; } @Override - public void emitJump(LabelRef label, LIRFrameState info) { - append(new JumpOp(label, info)); + public Variable emitLea(StackSlot address) { + Variable result = newVariable(target().wordKind); + append(new StackLeaOp(result, address)); + return result; } @Override - public void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef label, LIRFrameState info) { + public void emitJump(LabelRef label) { + append(new JumpOp(label)); + } + + @Override + public void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef label) { boolean mirrored = emitCompare(left, right); Condition finalCondition = mirrored ? cond.mirror() : cond; switch (left.getKind().getStackKind()) { case Int: case Long: case Object: - append(new BranchOp(finalCondition, label, info)); + append(new BranchOp(finalCondition, label)); break; case Float: case Double: - append(new FloatBranchOp(finalCondition, unorderedIsTrue, label, info)); + append(new FloatBranchOp(finalCondition, unorderedIsTrue, label)); break; default: throw GraalInternalError.shouldNotReachHere("" + left.getKind()); @@ -248,9 +276,14 @@ } @Override - public void emitIntegerTestBranch(Value left, Value right, boolean negated, LabelRef label, LIRFrameState info) { + public void emitOverflowCheckBranch(LabelRef destination, boolean negated) { + append(new BranchOp(negated ? ConditionFlag.NoOverflow : ConditionFlag.Overflow, destination)); + } + + @Override + public void emitIntegerTestBranch(Value left, Value right, boolean negated, LabelRef label) { emitIntegerTest(left, right); - append(new BranchOp(negated ? Condition.NE : Condition.EQ, label, info)); + append(new BranchOp(negated ? Condition.NE : Condition.EQ, label)); } @Override @@ -314,7 +347,6 @@ mirrored = false; } switch (left.getKind().getStackKind()) { - case Jsr: case Int: append(new CompareOp(ICMP, left, right)); break; @@ -337,42 +369,29 @@ } @Override - public Variable emitNegate(Value input) { + public void emitNullCheck(ValueNode v) { + assert v.kind() == Kind.Object; + Variable obj = newVariable(Kind.Object); + emitMove(obj, operand(v)); + append(new AMD64Move.NullCheckOp(obj, state())); + } + + @Override + public Variable emitNegate(Value inputVal) { + AllocatableValue input = asAllocatable(inputVal); Variable result = newVariable(input.getKind()); switch (input.getKind()) { case Int: - append(new Op1Stack(INEG, result, input)); + append(new Unary1Op(INEG, result, input)); break; case Long: - append(new Op1Stack(LNEG, result, input)); + append(new Unary1Op(LNEG, result, input)); break; case Float: - append(new Op2Reg(FXOR, result, input, Constant.forFloat(Float.intBitsToFloat(0x80000000)))); + append(new BinaryRegConst(FXOR, result, input, Constant.forFloat(Float.intBitsToFloat(0x80000000)))); break; case Double: - append(new Op2Reg(DXOR, result, input, Constant.forDouble(Double.longBitsToDouble(0x8000000000000000L)))); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - return result; - } - - @Override - public Variable emitAdd(Value a, Value b) { - Variable result = newVariable(a.getKind()); - switch (a.getKind()) { - 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))); + append(new BinaryRegConst(DXOR, result, input, Constant.forDouble(Double.longBitsToDouble(0x8000000000000000L)))); break; default: throw GraalInternalError.shouldNotReachHere(); @@ -380,48 +399,104 @@ return result; } - @Override - public Variable emitSub(Value a, Value b) { - Variable result = newVariable(a.getKind()); - switch (a.getKind()) { - case Int: - append(new Op2Stack(ISUB, result, a, loadNonConst(b))); + private Variable emitBinary(AMD64Arithmetic op, boolean commutative, Value a, Value b) { + if (isConstant(b)) { + return emitBinaryConst(op, commutative, asAllocatable(a), asConstant(b)); + } else if (commutative && isConstant(a)) { + return emitBinaryConst(op, commutative, asAllocatable(b), asConstant(a)); + } else { + return emitBinaryVar(op, commutative, asAllocatable(a), asAllocatable(b)); + } + } + + private Variable emitBinaryConst(AMD64Arithmetic op, boolean commutative, AllocatableValue a, Constant b) { + switch (op) { + case IADD: + case LADD: + case ISUB: + case LSUB: + case IAND: + case LAND: + case IOR: + case LOR: + case IXOR: + case LXOR: + if (NumUtil.isInt(b.asLong())) { + Variable result = newVariable(a.getKind()); + append(new BinaryRegConst(op, result, a, b)); + return result; + } break; - case Long: - append(new Op2Stack(LSUB, result, a, loadNonConst(b))); - break; - case Float: - append(new Op2Stack(FSUB, result, a, loadNonConst(b))); + + case IMUL: + case LMUL: + if (NumUtil.isInt(b.asLong())) { + Variable result = newVariable(a.getKind()); + append(new BinaryRegStackConst(op, result, a, b)); + return result; + } break; - case Double: - append(new Op2Stack(DSUB, result, a, loadNonConst(b))); - break; - default: - throw GraalInternalError.shouldNotReachHere(); + } + + return emitBinaryVar(op, commutative, a, asAllocatable(b)); + } + + private Variable emitBinaryVar(AMD64Arithmetic op, boolean commutative, AllocatableValue a, AllocatableValue b) { + Variable result = newVariable(a.getKind()); + if (commutative) { + append(new BinaryCommutative(op, result, a, b)); + } else { + append(new BinaryRegStack(op, result, a, b)); } return result; } @Override - public Variable emitMul(Value a, Value b) { - Variable result = newVariable(a.getKind()); + public Variable emitAdd(Value a, Value b) { switch (a.getKind()) { case Int: - append(new Op2Reg(IMUL, result, a, loadNonConst(b))); - break; + return emitBinary(IADD, true, a, b); case Long: - append(new Op2Reg(LMUL, result, a, loadNonConst(b))); - break; + return emitBinary(LADD, true, a, b); case Float: - append(new Op2Stack(FMUL, result, a, loadNonConst(b))); - break; + return emitBinary(FADD, true, a, b); case Double: - append(new Op2Stack(DMUL, result, a, loadNonConst(b))); - break; + return emitBinary(DADD, true, a, b); default: throw GraalInternalError.shouldNotReachHere(); } - return result; + } + + @Override + public Variable emitSub(Value a, Value b) { + switch (a.getKind()) { + case Int: + return emitBinary(ISUB, false, a, b); + case Long: + return emitBinary(LSUB, false, a, b); + case Float: + return emitBinary(FSUB, false, a, b); + case Double: + return emitBinary(DSUB, false, a, b); + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + @Override + public Variable emitMul(Value a, Value b) { + switch (a.getKind()) { + case Int: + return emitBinary(IMUL, true, a, b); + case Long: + return emitBinary(LMUL, true, a, b); + case Float: + return emitBinary(FMUL, true, a, b); + case Double: + return emitBinary(DMUL, true, a, b); + default: + throw GraalInternalError.shouldNotReachHere(); + } } @Override @@ -451,15 +526,19 @@ return false; } + private void emitDivRem(AMD64Arithmetic op, Value a, Value b) { + AllocatableValue rax = AMD64.rax.asValue(a.getKind()); + emitMove(rax, a); + append(new DivRemOp(op, rax, asAllocatable(b), state())); + } + public Value[] emitIntegerDivRem(Value a, Value b) { switch (a.getKind()) { case Int: - emitMove(a, RAX_I); - append(new DivRemOp(IDIVREM, RAX_I, load(b), state())); + emitDivRem(IDIVREM, a, b); return new Value[]{emitMove(RAX_I), emitMove(RDX_I)}; case Long: - emitMove(a, RAX_L); - append(new DivRemOp(LDIVREM, RAX_L, load(b), state())); + emitDivRem(LDIVREM, a, b); return new Value[]{emitMove(RAX_L), emitMove(RDX_L)}; default: throw GraalInternalError.shouldNotReachHere(); @@ -470,21 +549,19 @@ public Value emitDiv(Value a, Value b) { switch (a.getKind()) { case Int: - emitMove(a, RAX_I); - append(new DivOp(IDIV, RAX_I, RAX_I, load(b), state())); + emitDivRem(IDIV, a, b); return emitMove(RAX_I); case Long: - emitMove(a, RAX_L); - append(new DivOp(LDIV, RAX_L, RAX_L, load(b), state())); + emitDivRem(LDIV, a, b); return emitMove(RAX_L); case Float: { Variable result = newVariable(a.getKind()); - append(new Op2Stack(FDIV, result, a, loadNonConst(b))); + append(new BinaryRegStack(FDIV, result, asAllocatable(a), asAllocatable(b))); return result; } case Double: { Variable result = newVariable(a.getKind()); - append(new Op2Stack(DDIV, result, a, loadNonConst(b))); + append(new BinaryRegStack(DDIV, result, asAllocatable(a), asAllocatable(b))); return result; } default: @@ -496,12 +573,10 @@ public Value emitRem(Value a, Value b) { switch (a.getKind()) { case Int: - emitMove(a, RAX_I); - append(new DivOp(IREM, RDX_I, RAX_I, load(b), state())); + emitDivRem(IREM, a, b); return emitMove(RDX_I); case Long: - emitMove(a, RAX_L); - append(new DivOp(LREM, RDX_L, RAX_L, load(b), state())); + emitDivRem(LREM, a, b); return emitMove(RDX_L); case Float: { RuntimeCallTarget stub = runtime.lookupRuntimeCall(ARITHMETIC_FREM); @@ -520,12 +595,10 @@ public Variable emitUDiv(Value a, Value b) { switch (a.getKind()) { case Int: - emitMove(a, RAX_I); - append(new DivOp(IUDIV, RAX_I, RAX_I, load(b), state())); + emitDivRem(IUDIV, a, b); return emitMove(RAX_I); case Long: - emitMove(a, RAX_L); - append(new DivOp(LUDIV, RAX_L, RAX_L, load(b), state())); + emitDivRem(LUDIV, a, b); return emitMove(RAX_L); default: throw GraalInternalError.shouldNotReachHere(); @@ -536,12 +609,10 @@ public Variable emitURem(Value a, Value b) { switch (a.getKind()) { case Int: - emitMove(a, RAX_I); - append(new DivOp(IUREM, RDX_I, RAX_I, load(b), state())); + emitDivRem(IUREM, a, b); return emitMove(RDX_I); case Long: - emitMove(a, RAX_L); - append(new DivOp(LUREM, RDX_L, RAX_L, load(b), state())); + emitDivRem(LUREM, a, b); return emitMove(RDX_L); default: throw GraalInternalError.shouldNotReachHere(); @@ -550,107 +621,86 @@ @Override public Variable emitAnd(Value a, Value b) { - Variable result = newVariable(a.getKind()); switch (a.getKind()) { case Int: - append(new Op2Stack(IAND, result, a, loadNonConst(b))); - break; + return emitBinary(IAND, true, a, b); case Long: - append(new Op2Stack(LAND, result, a, loadNonConst(b))); - break; + return emitBinary(LAND, true, a, b); default: throw GraalInternalError.shouldNotReachHere(); } - 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; + return emitBinary(IOR, true, a, b); case Long: - append(new Op2Stack(LOR, result, a, loadNonConst(b))); - break; + return emitBinary(LOR, true, a, b); default: throw GraalInternalError.shouldNotReachHere(); } - 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; + return emitBinary(IXOR, true, a, b); case Long: - append(new Op2Stack(LXOR, result, a, loadNonConst(b))); - break; + return emitBinary(LXOR, true, a, b); default: throw GraalInternalError.shouldNotReachHere(); } + } + + private Variable emitShift(AMD64Arithmetic op, Value a, Value b) { + Variable result = newVariable(a.getKind()); + AllocatableValue input = asAllocatable(a); + if (isConstant(b)) { + append(new BinaryRegConst(op, result, input, asConstant(b))); + } else { + emitMove(RCX_I, b); + append(new BinaryRegReg(op, result, input, RCX_I)); + } return result; } @Override public Variable emitShl(Value a, Value b) { - Variable result = newVariable(a.getKind()); switch (a.getKind()) { case Int: - append(new ShiftOp(ISHL, result, a, loadShiftCount(b))); - break; + return emitShift(ISHL, a, b); case Long: - append(new ShiftOp(LSHL, result, a, loadShiftCount(b))); - break; + return emitShift(LSHL, a, b); default: - GraalInternalError.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere(); } - return result; } @Override public Variable emitShr(Value a, Value b) { - Variable result = newVariable(a.getKind()); switch (a.getKind()) { case Int: - append(new ShiftOp(ISHR, result, a, loadShiftCount(b))); - break; + return emitShift(ISHR, a, b); case Long: - append(new ShiftOp(LSHR, result, a, loadShiftCount(b))); - break; + return emitShift(LSHR, a, b); default: - GraalInternalError.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere(); } - return result; } @Override public Variable emitUShr(Value a, Value b) { - Variable result = newVariable(a.getKind()); switch (a.getKind()) { case Int: - append(new ShiftOp(IUSHR, result, a, loadShiftCount(b))); - break; + return emitShift(IUSHR, a, b); case Long: - append(new ShiftOp(LUSHR, result, a, loadShiftCount(b))); - break; + return emitShift(LUSHR, a, b); default: - GraalInternalError.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere(); } - return result; - } - - private Value loadShiftCount(Value value) { - if (isConstant(value)) { - return value; - } - // Non-constant shift count must be in RCX - emitMove(value, RCX_I); - return RCX_I; } @Override @@ -659,67 +709,67 @@ Variable result = newVariable(opcode.to); switch (opcode) { case I2L: - append(new Op1Reg(I2L, result, input)); + append(new Unary2Op(I2L, result, input)); break; case L2I: - append(new Op1Stack(L2I, result, input)); + append(new Unary1Op(L2I, result, input)); break; case I2B: - append(new Op1Stack(I2B, result, input)); + append(new Unary2Op(I2B, result, input)); break; case I2C: - append(new Op1Stack(I2C, result, input)); + append(new Unary1Op(I2C, result, input)); break; case I2S: - append(new Op1Stack(I2S, result, input)); + append(new Unary2Op(I2S, result, input)); break; case F2D: - append(new Op1Reg(F2D, result, input)); + append(new Unary2Op(F2D, result, input)); break; case D2F: - append(new Op1Reg(D2F, result, input)); + append(new Unary2Op(D2F, result, input)); break; case I2F: - append(new Op1Reg(I2F, result, input)); + append(new Unary2Op(I2F, result, input)); break; case I2D: - append(new Op1Reg(I2D, result, input)); + append(new Unary2Op(I2D, result, input)); break; case F2I: - append(new Op1Reg(F2I, result, input)); + append(new Unary2Op(F2I, result, input)); break; case D2I: - append(new Op1Reg(D2I, result, input)); + append(new Unary2Op(D2I, result, input)); break; case L2F: - append(new Op1Reg(L2F, result, input)); + append(new Unary2Op(L2F, result, input)); break; case L2D: - append(new Op1Reg(L2D, result, input)); + append(new Unary2Op(L2D, result, input)); break; case F2L: - append(new Op1Reg(F2L, result, input)); + append(new Unary2Op(F2L, result, input)); break; case D2L: - append(new Op1Reg(D2L, result, input)); + append(new Unary2Op(D2L, result, input)); break; case MOV_I2F: - append(new Op1Reg(MOV_I2F, result, input)); + append(new Unary2Op(MOV_I2F, result, input)); break; case MOV_L2D: - append(new Op1Reg(MOV_L2D, result, input)); + append(new Unary2Op(MOV_L2D, result, input)); break; case MOV_F2I: - append(new Op1Reg(MOV_F2I, result, input)); + append(new Unary2Op(MOV_F2I, result, input)); break; case MOV_D2L: - append(new Op1Reg(MOV_D2L, result, input)); + 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(input, result); + emitMove(result, input); break; default: throw GraalInternalError.shouldNotReachHere(); @@ -728,20 +778,6 @@ } @Override - public void emitDeoptimizeOnOverflow(DeoptimizationAction action, DeoptimizationReason reason, Object deoptInfo) { - LIRFrameState info = state(); - LabelRef stubEntry = createDeoptStub(action, reason, info, deoptInfo); - append(new BranchOp(ConditionFlag.overflow, stubEntry, info)); - } - - @Override - public void emitDeoptimize(DeoptimizationAction action, DeoptimizationReason reason, Object deoptInfo) { - LIRFrameState info = state(); - LabelRef stubEntry = createDeoptStub(action, reason, info, deoptInfo); - append(new JumpOp(stubEntry, info)); - } - - @Override public void emitMembar(int barriers) { int necessaryBarriers = target.arch.requiredBarriers(barriers); if (target.isMP && necessaryBarriers != 0) { @@ -750,54 +786,42 @@ } @Override - protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { - append(new DirectCallOp(callTarget.target(), result, parameters, temps, callState)); - } + protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { - @Override - protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { - // The current register allocator cannot handle variables at call sites, need a fixed - // register. - Value targetAddress = AMD64.rax.asValue(); - emitMove(operand(callTarget.computedAddress()), targetAddress); - append(new IndirectCallOp(callTarget.target(), result, parameters, temps, targetAddress, callState)); - } - - @Override - protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, Value targetAddress, LIRFrameState info) { - if (isConstant(targetAddress)) { - append(new DirectCallOp(callTarget, result, arguments, temps, info)); + long maxOffset = callTarget.getMaxCallTargetOffset(); + if (maxOffset != (int) maxOffset) { + append(new AMD64Call.DirectFarRuntimeCallOp(this, callTarget, result, arguments, temps, info)); } else { - append(new IndirectCallOp(callTarget, result, arguments, temps, targetAddress, info)); + append(new AMD64Call.DirectNearRuntimeCallOp(callTarget, result, arguments, temps, info)); } } @Override public void emitBitCount(Variable result, Value value) { if (value.getKind().getStackKind() == Kind.Int) { - append(new AMD64BitManipulationOp(IPOPCNT, result, value)); + append(new AMD64BitManipulationOp(IPOPCNT, result, asAllocatable(value))); } else { - append(new AMD64BitManipulationOp(LPOPCNT, result, value)); + append(new AMD64BitManipulationOp(LPOPCNT, result, asAllocatable(value))); } } @Override public void emitBitScanForward(Variable result, Value value) { - append(new AMD64BitManipulationOp(BSF, result, value)); + append(new AMD64BitManipulationOp(BSF, result, asAllocatable(value))); } @Override public void emitBitScanReverse(Variable result, Value value) { if (value.getKind().getStackKind() == Kind.Int) { - append(new AMD64BitManipulationOp(IBSR, result, value)); + append(new AMD64BitManipulationOp(IBSR, result, asAllocatable(value))); } else { - append(new AMD64BitManipulationOp(LBSR, result, value)); + append(new AMD64BitManipulationOp(LBSR, result, asAllocatable(value))); } } @Override public void emitMathAbs(Variable result, Variable input) { - append(new Op2Reg(DAND, result, input, Constant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL)))); + append(new BinaryRegConst(DAND, result, input, Constant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL)))); } @Override @@ -861,21 +885,6 @@ } @Override - protected LabelRef createDeoptStub(DeoptimizationAction action, DeoptimizationReason reason, LIRFrameState info, Object deoptInfo) { - assert info.topFrame.getBCI() >= 0 : "invalid bci for deopt framestate"; - AMD64DeoptimizationStub stub = new AMD64DeoptimizationStub(action, reason, info, deoptInfo); - lir.stubs.add(stub); - return LabelRef.forLabel(stub.label); - } - - @Override - protected void emitNullCheckGuard(ValueNode object) { - Variable value = load(operand(object)); - LIRFrameState info = state(); - append(new NullCheckOp(value, info)); - } - - @Override public void visitCompareAndSwap(CompareAndSwapNode node) { Kind kind = node.newValue().kind(); assert kind == node.expected().kind(); @@ -883,19 +892,19 @@ Value expected = loadNonConst(operand(node.expected())); Variable newValue = load(operand(node.newValue())); - Address address; + AMD64AddressValue address; int displacement = node.displacement(); Value index = operand(node.offset()); if (isConstant(index) && NumUtil.isInt(asConstant(index).asLong() + displacement)) { assert !runtime.needsDataPatch(asConstant(index)); displacement += (int) asConstant(index).asLong(); - address = new Address(kind, load(operand(node.object())), displacement); + address = new AMD64AddressValue(kind, load(operand(node.object())), displacement); } else { - address = new Address(kind, load(operand(node.object())), load(index), Address.Scale.Times1, displacement); + address = new AMD64AddressValue(kind, load(operand(node.object())), load(index), Scale.Times1, displacement); } RegisterValue rax = AMD64.rax.asValue(kind); - emitMove(expected, rax); + emitMove(rax, expected); append(new CompareAndSwapOp(rax, address, rax, newValue)); Variable result = newVariable(node.kind()); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/BasicPTXTest.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/BasicPTXTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,91 @@ +/* + * 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.ptx.test; + +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.*; +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.*; +import com.oracle.graal.ptx.*; + +/** + * Test class for small Java methods compiled to PTX kernels. + */ +public class BasicPTXTest extends GraalCompilerTest { + + @Test + public void testAdd() { + test("testAddSnippet"); + } + + public static int testAddSnippet(int a) { + return a + 1; + } + + @Test + public void testArray() { + test("testArraySnippet"); + } + + public static int testArraySnippet(int[] array) { + return array[0]; + } + + private void 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()); + System.out.println("result=" + result); + } + + private static class PTXPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + System.out.println("PTX phase"); + for (LocalNode local : graph.getNodes(LocalNode.class)) { + if (local.kind() == Kind.Object) { + local.setStamp(StampFactory.declaredNonNull(local.objectStamp().type())); + } + } + } + + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXBackend.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXBackend.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,111 @@ +/* + * 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; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.asm.ptx.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.*; + +/** + * PTX specific backend. + */ +public class PTXBackend extends Backend { + + public PTXBackend(CodeCacheProvider runtime, TargetDescription target) { + super(runtime, target); + } + + @Override + public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) { + return new PTXLIRGenerator(graph, runtime(), target, frameMap, method, lir); + } + + class HotSpotFrameContext implements FrameContext { + + @Override + public void enter(TargetMethodAssembler tasm) { + Buffer codeBuffer = tasm.asm.codeBuffer; + codeBuffer.emitString(".version 1.4"); + codeBuffer.emitString(".target sm_10"); + // codeBuffer.emitString(".address_size 32"); // PTX ISA version 2.3 + } + + @Override + public void leave(TargetMethodAssembler tasm) { + } + } + + @Override + public TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult) { + // Omit the frame if the method: + // - has no spill slots or other slots allocated during register allocation + // - has no callee-saved registers + // - has no incoming arguments passed on the stack + // - has no instructions with debug info + FrameMap frameMap = lirGen.frameMap; + AbstractAssembler masm = new PTXAssembler(target, frameMap.registerConfig); + HotSpotFrameContext frameContext = new HotSpotFrameContext(); + TargetMethodAssembler tasm = new TargetMethodAssembler(target, runtime(), frameMap, masm, frameContext, compilationResult); + tasm.setFrameSize(frameMap.frameSize()); + return tasm; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, ResolvedJavaMethod method, LIRGenerator lirGen) { + // Emit the prologue + final String name = method.getName(); + Buffer codeBuffer = tasm.asm.codeBuffer; + codeBuffer.emitString0(".entry " + name + " ("); + codeBuffer.emitString(""); + + Signature signature = method.getSignature(); + for (int i = 0; i < signature.getParameterCount(false); i++) { + System.err.println(i + ": " + signature.getParameterKind(i)); + String param = ".param .u32 param" + i; + codeBuffer.emitString(param); + } + + codeBuffer.emitString0(") {"); + codeBuffer.emitString(""); + + // XXX For now declare one predicate and all registers + codeBuffer.emitString(" .reg .pred %p;"); + codeBuffer.emitString(" .reg .u32 %r<16>;"); + + // Emit code for the LIR + lirGen.lir.emitCode(tasm); + + // Emit the epilogue + codeBuffer.emitString0("}"); + codeBuffer.emitString(""); + + byte[] data = codeBuffer.copyData(0, codeBuffer.position()); + System.err.println(new String(data)); + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,480 @@ +/* + * 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; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.ptx.PTXArithmetic.*; +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.lir.StandardOp.JumpOp; +import com.oracle.graal.lir.ptx.*; +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.PTXCompare.CompareOp; +import com.oracle.graal.lir.ptx.PTXControlFlow.BranchOp; +import com.oracle.graal.lir.ptx.PTXControlFlow.ReturnOp; +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.*; + +/** + * This class implements the PTX specific portion of the LIR generator. + */ +public class PTXLIRGenerator extends LIRGenerator { + + public static class PTXSpillMoveFactory implements LIR.SpillMoveFactory { + + @Override + public LIRInstruction createMove(Value result, Value input) { + throw new InternalError("NYI"); + } + } + + public PTXLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) { + super(graph, runtime, target, frameMap, method, lir); + lir.spillMoveFactory = new PTXSpillMoveFactory(); + } + + @Override + protected void emitNode(ValueNode node) { + if (node instanceof LIRGenLowerable) { + ((LIRGenLowerable) node).generate(this); + } else { + super.emitNode(node); + } + } + + @Override + public boolean canStoreConstant(Constant c) { + // Operand b must be in the .reg state space. + return false; + } + + @Override + public boolean canInlineConstant(Constant c) { + switch (c.getKind()) { + case Long: + return NumUtil.isInt(c.asLong()) && !runtime.needsDataPatch(c); + case Object: + return c.isNull(); + default: + return true; + } + } + + @Override + public Variable emitMove(Value input) { + Variable result = newVariable(input.getKind()); + emitMove(result, input); + return result; + } + + @Override + public void emitMove(Value dst, Value src) { + if (isRegister(src) || isStackSlot(dst)) { + append(new MoveFromRegOp(dst, src)); + } else { + append(new MoveToRegOp(dst, src)); + } + } + + private PTXAddressValue prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) { + AllocatableValue baseRegister; + long finalDisp = displacement; + if (isConstant(base)) { + if (asConstant(base).isNull()) { + baseRegister = AllocatableValue.UNUSED; + } else if (asConstant(base).getKind() != Kind.Object) { + finalDisp += asConstant(base).asLong(); + baseRegister = AllocatableValue.UNUSED; + } else { + baseRegister = load(base); + } + } else if (base == Value.ILLEGAL) { + baseRegister = AllocatableValue.UNUSED; + } else { + baseRegister = asAllocatable(base); + } + + if (index != Value.ILLEGAL) { + if (isConstant(index)) { + finalDisp += asConstant(index).asLong() * scale; + } else { + Value indexRegister; + if (scale != 1) { + indexRegister = emitMul(index, Constant.forInt(scale)); + } else { + indexRegister = index; + } + + if (baseRegister == AllocatableValue.UNUSED) { + baseRegister = asAllocatable(indexRegister); + } else { + baseRegister = emitAdd(baseRegister, indexRegister); + } + } + } + + return new PTXAddressValue(kind, baseRegister, finalDisp); + } + + @Override + public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap) { + PTXAddressValue loadAddress = prepareAddress(kind, base, displacement, index, scale); + Variable result = newVariable(loadAddress.getKind()); + append(new LoadOp(result, loadAddress, canTrap ? state() : null)); + return result; + } + + @Override + public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, boolean canTrap) { + PTXAddressValue storeAddress = prepareAddress(kind, base, displacement, index, scale); + Variable input = load(inputVal); + append(new StoreOp(storeAddress, input, canTrap ? state() : null)); + } + + @Override + public Variable emitLea(Value base, int displacement, Value index, int scale) { + throw new InternalError("NYI"); + } + + @Override + public Variable emitLea(StackSlot address) { + throw new InternalError("NYI"); + } + + @Override + public void emitJump(LabelRef label) { + append(new JumpOp(label)); + } + + @Override + public void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef label) { + switch (left.getKind().getStackKind()) { + case Int: + append(new CompareOp(ICMP, cond, left, right)); + append(new BranchOp(cond, label)); + break; + case Object: + append(new CompareOp(ACMP, cond, left, right)); + append(new BranchOp(cond, label)); + break; + default: + throw GraalInternalError.shouldNotReachHere("" + left.getKind()); + } + } + + @Override + public void emitOverflowCheckBranch(LabelRef label, boolean negated) { + throw new InternalError("NYI"); + } + + @Override + public void emitIntegerTestBranch(Value left, Value right, boolean negated, LabelRef label) { + throw new InternalError("NYI"); + } + + @Override + public Variable emitConditionalMove(Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) { + throw new InternalError("NYI"); + } + + @Override + public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) { + throw new InternalError("NYI"); + } + + @Override + public Variable emitNegate(Value input) { + Variable result = newVariable(input.getKind()); + switch (input.getKind()) { + case Int: + append(new Op1Stack(INEG, result, input)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + return result; + } + + @Override + public Variable emitAdd(Value a, Value b) { + Variable result = newVariable(a.getKind()); + switch (a.getKind()) { + case Int: + append(new Op2Stack(IADD, result, a, loadNonConst(b))); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + return result; + } + + @Override + public Variable emitSub(Value a, Value b) { + Variable result = newVariable(a.getKind()); + switch (a.getKind()) { + case Int: + append(new Op2Stack(ISUB, result, a, loadNonConst(b))); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + return result; + } + + @Override + public Variable emitMul(Value a, Value b) { + Variable result = newVariable(a.getKind()); + switch (a.getKind()) { + case Int: + append(new Op2Reg(IMUL, result, a, loadNonConst(b))); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + return result; + } + + @Override + protected boolean peephole(ValueNode valueNode) { + // No peephole optimizations for now + return false; + } + + @Override + public Value emitDiv(Value a, Value b) { + 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) { + throw new InternalError("NYI"); + } + + @Override + public Variable emitAnd(Value a, Value b) { + Variable result = newVariable(a.getKind()); + switch (a.getKind()) { + case Int: + append(new Op2Stack(IAND, result, a, loadNonConst(b))); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + return result; + } + + @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"); + } + + @Override + public Variable emitShr(Value a, Value b) { + throw new InternalError("NYI"); + } + + @Override + public Variable emitUShr(Value a, Value b) { + Variable result = newVariable(a.getKind()); + switch (a.getKind()) { + case Int: + append(new ShiftOp(IUSHR, result, a, b)); + break; + default: + GraalInternalError.shouldNotReachHere(); + } + return result; + } + + @Override + public Variable emitConvert(ConvertNode.Op opcode, Value inputVal) { + throw new InternalError("NYI"); + } + + @Override + public void emitDeoptimize(DeoptimizationAction action, DeoptimizationReason reason) { + append(new ReturnOp(Value.ILLEGAL)); + } + + @Override + public void emitMembar(int barriers) { + throw new InternalError("NYI"); + } + + @Override + protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + throw new InternalError("NYI"); + } + + @Override + protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + throw new InternalError("NYI"); + } + + @Override + protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { + throw new InternalError("NYI"); + } + + @Override + public void emitBitCount(Variable result, Value value) { + if (value.getKind().getStackKind() == Kind.Int) { + append(new PTXBitManipulationOp(IPOPCNT, result, value)); + } else { + append(new PTXBitManipulationOp(LPOPCNT, result, value)); + } + } + + @Override + public void emitBitScanForward(Variable result, Value value) { + throw new InternalError("NYI"); + } + + @Override + public void emitBitScanReverse(Variable result, Value value) { + throw new InternalError("NYI"); + } + + @Override + public void emitMathAbs(Variable result, Variable input) { + throw new InternalError("NYI"); + } + + @Override + public void emitMathSqrt(Variable result, Variable input) { + throw new InternalError("NYI"); + } + + @Override + public void emitMathLog(Variable result, Variable input, boolean base10) { + throw new InternalError("NYI"); + } + + @Override + public void emitMathCos(Variable result, Variable input) { + throw new InternalError("NYI"); + } + + @Override + public void emitMathSin(Variable result, Variable input) { + throw new InternalError("NYI"); + } + + @Override + public void emitMathTan(Variable result, Variable input) { + throw new InternalError("NYI"); + } + + @Override + public void emitByteSwap(Variable result, Value input) { + throw new InternalError("NYI"); + } + + @Override + protected void emitReturn(Value input) { + append(new ReturnOp(input)); + } + + @Override + protected void emitSequentialSwitch(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) { + throw new InternalError("NYI"); + } + + @Override + protected void emitSwitchRanges(int[] lowKeys, int[] highKeys, LabelRef[] targets, LabelRef defaultTarget, Value key) { + throw new InternalError("NYI"); + } + + @Override + protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) { + throw new InternalError("NYI"); + } + + @Override + public void visitCompareAndSwap(CompareAndSwapNode node) { + throw new InternalError("NYI"); + } + + @Override + public void visitBreakpointNode(BreakpointNode node) { + throw new InternalError("NYI"); + } + + @Override + public void visitExceptionObject(ExceptionObjectNode i) { + throw new InternalError("NYI"); + } + + @Override + public void visitSafepointNode(SafepointNode i) { + throw new InternalError("NYI"); + } + + @Override + public void emitUnwind(Value operand) { + // TODO Auto-generated method stub + + } + + @Override + public void emitNullCheck(ValueNode v) { + throw new InternalError("NYI"); + } +} diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Thu Mar 21 14:11:13 2013 +0100 @@ -31,7 +31,6 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.calc.ConvertNode.Op; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; /** @@ -63,13 +62,7 @@ } @Override - protected void emitNullCheckGuard(ValueNode object) { - // SPARC: Auto-generated method stub - - } - - @Override - public void emitJump(LabelRef label, LIRFrameState info) { + public void emitJump(LabelRef label) { @SuppressWarnings("unused") SPARCLIRInstruction instruction = null; // SPARC: Auto-generated method stub @@ -77,13 +70,19 @@ } @Override - public void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef label, LIRFrameState info) { + public void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef label) { // SPARC: Auto-generated method stub } @Override - public void emitIntegerTestBranch(Value left, Value right, boolean negated, LabelRef label, LIRFrameState info) { + public void emitOverflowCheckBranch(LabelRef label, boolean negated) { + // SPARC: Auto-generated method stub + + } + + @Override + public void emitIntegerTestBranch(Value left, Value right, boolean negated, LabelRef label) { // SPARC: Auto-generated method stub } @@ -113,18 +112,12 @@ } @Override - protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, Value targetAddress, LIRFrameState info) { + protected void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { // SPARC: Auto-generated method stub } @Override - protected LabelRef createDeoptStub(DeoptimizationAction action, DeoptimizationReason reason, LIRFrameState info, Object deoptInfo) { - // SPARC: Auto-generated method stub - return null; - } - - @Override protected void emitSequentialSwitch(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) { // SPARC: Auto-generated method stub @@ -215,31 +208,31 @@ } @Override - public Address makeAddress(LocationNode location, ValueNode object) { - // SPARC: Auto-generated method stub - return null; - } - - @Override - public void emitMove(Value src, Value dst) { + public void emitMove(Value dst, Value src) { // SPARC: Auto-generated method stub } @Override - public Value emitLoad(Value loadAddress, boolean canTrap) { + public Value emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap) { // SPARC: Auto-generated method stub return null; } @Override - public void emitStore(Value storeAddress, Value input, boolean canTrap) { + public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value input, boolean canTrap) { // SPARC: Auto-generated method stub } @Override - public Value emitLea(Value address) { + public Value emitLea(Value base, int displacement, Value index, int scale) { + // SPARC: Auto-generated method stub + return null; + } + + @Override + public Value emitLea(StackSlot address) { // SPARC: Auto-generated method stub return null; } @@ -341,13 +334,7 @@ } @Override - public void emitDeoptimizeOnOverflow(DeoptimizationAction action, DeoptimizationReason reason, Object deoptInfo) { - // SPARC: Auto-generated method stub - - } - - @Override - public void emitDeoptimize(DeoptimizationAction action, DeoptimizationReason reason, Object deoptInfo) { + public void emitDeoptimize(DeoptimizationAction action, DeoptimizationReason reason) { // SPARC: Auto-generated method stub } @@ -375,4 +362,16 @@ // SPARC: Auto-generated method stub } + + @Override + public void emitUnwind(Value operand) { + // SPARC: Auto-generated method stub + + } + + @Override + public void emitNullCheck(ValueNode v) { + // SPARC: Auto-generated method stub + + } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -126,13 +126,13 @@ } Assumptions assumptions = new Assumptions(false); - new InliningPhase(null, runtime(), hints, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); - new CanonicalizerPhase(null, runtime(), assumptions).apply(graph); + 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(null, runtime(), assumptions).apply(graph); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); new DeadCodeEliminationPhase().apply(graph); StructuredGraph referenceGraph = parse(referenceSnippet); assertEquals(referenceGraph, graph); diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -35,7 +35,7 @@ private StructuredGraph getCanonicalizedGraph(String name) { StructuredGraph graph = parse(name); - new CanonicalizerPhase(null, runtime(), null).apply(graph); + new CanonicalizerPhase(runtime(), null).apply(graph); return graph; } @@ -53,7 +53,7 @@ assertEquals(referenceGraph, graph); } Assumptions assumptions = new Assumptions(false); - new CanonicalizerPhase(null, runtime(), assumptions).apply(referenceGraph); + new CanonicalizerPhase(runtime(), assumptions).apply(referenceGraph); for (int i = 1; i < 4; i++) { StructuredGraph graph = getCanonicalizedGraph("canonicalCompare" + i); assertEquals(referenceGraph, graph); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompiledMethodTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompiledMethodTest.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,199 +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.lang.reflect.*; - -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.graph.*; -import com.oracle.graal.java.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; - -/** - * In the following tests, the usages of local variable "a" are replaced with the integer constant - * 0. Then canonicalization is applied and it is verified that the resulting graph is equal to the - * graph of the method that just has a "return 1" statement in it. - */ -public class CompiledMethodTest extends GraalCompilerTest { - - public static Object testMethod(Object arg1, Object arg2, Object arg3) { - return arg1 + " " + arg2 + " " + arg3; - } - - Object f1; - - public Object testMethodVirtual(Object arg1, Object arg2, Object arg3) { - return f1 + " " + arg1 + " " + arg2 + " " + arg3; - } - - @Test - public void test1() { - Method method = getMethod("testMethod"); - final StructuredGraph graph = parse(method); - new CanonicalizerPhase(null, 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 && " ".equals(constant.value.asObject())) { - graph.replaceFloating(constant, ConstantNode.forObject("-", runtime, graph)); - } - } - } - - final ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(method); - InstalledCode compiledMethod = getCode(javaMethod, graph); - try { - Object result = compiledMethod.execute("1", "2", "3"); - Assert.assertEquals("1-2-3", result); - } catch (MethodInvalidatedException t) { - Assert.fail("method invalidated"); - } - } - - @Test - public void test3() { - Method method = getMethod("testMethod"); - final StructuredGraph graph = parse(method); - final ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(method); - InstalledCode compiledMethod = getCode(javaMethod, graph); - try { - Object result = compiledMethod.executeVarargs("1", "2", "3"); - Assert.assertEquals("1 2 3", result); - } catch (MethodInvalidatedException t) { - Assert.fail("method invalidated"); - } - } - - @Test - public void test4() { - Method method = getMethod("testMethodVirtual"); - final StructuredGraph graph = parse(method); - final ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(method); - InstalledCode compiledMethod = getCode(javaMethod, graph); - try { - f1 = "0"; - Object result = compiledMethod.executeVarargs(this, "1", "2", "3"); - Assert.assertEquals("0 1 2 3", result); - } catch (MethodInvalidatedException t) { - Assert.fail("method invalidated"); - } - } - - @Test - 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.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph); - new CanonicalizerPhase(null, 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 dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -84,7 +84,7 @@ for (Invoke invoke : graph.getInvokes()) { invoke.intrinsify(null); } - new CanonicalizerPhase(null, runtime(), new Assumptions(false)).apply(graph); + new CanonicalizerPhase(runtime(), new Assumptions(false)).apply(graph); StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); Debug.dump(referenceGraph, "Graph"); assertEquals(referenceGraph, graph); diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -32,6 +32,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.target.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.Verbosity; @@ -67,12 +68,12 @@ public abstract class GraalCompilerTest extends GraalTest { protected final GraalCodeCacheProvider runtime; - protected final GraalCompiler graalCompiler; + protected final Backend backend; public GraalCompilerTest() { DebugEnvironment.initialize(System.out); this.runtime = Graal.getRequiredCapability(GraalCodeCacheProvider.class); - this.graalCompiler = Graal.getRequiredCapability(GraalCompiler.class); + this.backend = Graal.getRequiredCapability(Backend.class); } protected void assertEquals(StructuredGraph expected, StructuredGraph graph) { @@ -220,7 +221,7 @@ return method.invoke(receiver, args); } - static class Result { + protected static class Result { final Object returnValue; final Throwable exception; @@ -262,7 +263,10 @@ before(); Object[] executeArgs = argsWithReceiver(receiver, args); - InstalledCode compiledMethod = getCode(runtime.lookupJavaMethod(method), parse(method)); + ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(method); + checkArgs(javaMethod, executeArgs); + + InstalledCode compiledMethod = getCode(javaMethod, parse(method)); try { return new Result(compiledMethod.executeVarargs(executeArgs), null); } catch (Throwable e) { @@ -272,6 +276,25 @@ } } + protected void checkArgs(ResolvedJavaMethod method, Object[] args) { + JavaType[] sig = MetaUtil.signatureToTypes(method); + Assert.assertEquals(sig.length, args.length); + for (int i = 0; i < args.length; i++) { + JavaType javaType = sig[i]; + Kind kind = javaType.getKind(); + Object arg = args[i]; + if (kind == Kind.Object) { + if (arg != null && javaType instanceof ResolvedJavaType) { + ResolvedJavaType resolvedJavaType = (ResolvedJavaType) javaType; + Assert.assertTrue(resolvedJavaType + " from " + runtime.lookupJavaType(arg.getClass()), resolvedJavaType.isAssignableFrom(runtime.lookupJavaType(arg.getClass()))); + } + } else { + Assert.assertNotNull(arg); + Assert.assertEquals(kind.toBoxedJavaClass(), arg.getClass()); + } + } + } + /** * Prepends a non-null receiver argument to a given list or args. * @@ -295,18 +318,28 @@ Method method = getMethod(name); Object receiver = Modifier.isStatic(method.getModifiers()) ? null : this; + test(method, receiver, args); + } + + protected void test(Method method, Object receiver, Object... args) { Result expect = executeExpected(method, receiver, args); if (runtime == null) { return; } + test(method, expect, receiver, args); + } + + protected void test(Method method, Result expect, Object receiver, Object... args) { Result actual = executeActual(method, receiver, args); if (expect.exception != null) { Assert.assertTrue("expected " + expect.exception, actual.exception != null); Assert.assertEquals(expect.exception.getClass(), actual.exception.getClass()); } else { - // System.out.println(name + "(" + Arrays.toString(args) + "): expected=" + - // expect.returnValue + ", actual=" + actual.returnValue); + if (actual.exception != null) { + actual.exception.printStackTrace(); + Assert.fail("expected " + expect.returnValue + " but got an exception"); + } assertEquals(expect.returnValue, actual.returnValue); } } @@ -342,8 +375,6 @@ if (cached != null) { if (cached.isValid()) { return cached; - } else { - // System.out.println(cached.getMethod() + " was invalidated"); } } @@ -351,7 +382,7 @@ final int id = compilationId++; - InstalledCode installedCode = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true), new Callable() { + InstalledCode installedCode = Debug.scope("Compiling", new Object[]{runtime, new DebugDumpScope(String.valueOf(id), true)}, new Callable() { public InstalledCode call() throws Exception { final boolean printCompilation = GraalOptions.PrintCompilation && !TTY.isSuppressed(); @@ -363,7 +394,7 @@ GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL); phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase); editPhasePlan(method, graph, phasePlan); - CompilationResult compResult = graalCompiler.compileMethod(method, graph, null, phasePlan, OptimisticOptimizations.ALL); + CompilationResult compResult = GraalCompiler.compileMethod(runtime(), 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())); } @@ -378,17 +409,16 @@ } protected InstalledCode addMethod(final ResolvedJavaMethod method, final CompilationResult compResult) { - assert graalCompiler != null; - return Debug.scope("CodeInstall", new Object[]{graalCompiler, method}, new Callable() { + return Debug.scope("CodeInstall", new Object[]{runtime, method}, new Callable() { @Override public InstalledCode call() throws Exception { - final CodeInfo[] info = Debug.isDumpEnabled() ? new CodeInfo[1] : null; - InstalledCode installedMethod = runtime.addMethod(method, compResult, info); - if (info != null) { - Debug.dump(new Object[]{compResult, info[0]}, "After code installation"); + InstalledCode installedCode = runtime.addMethod(method, compResult); + if (Debug.isDumpEnabled()) { + Debug.dump(new Object[]{compResult, installedCode}, "After code installation"); } - return installedMethod; + + return installedCode; } }); } @@ -408,7 +438,7 @@ protected StructuredGraph parse(Method m) { ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(m); StructuredGraph graph = new StructuredGraph(javaMethod); - new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.ALL).apply(graph); + new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); return graph; } @@ -424,7 +454,7 @@ protected PhasePlan getDefaultPhasePlan() { PhasePlan plan = new PhasePlan(); - plan.addPhase(PhasePosition.AFTER_PARSING, new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.ALL)); + plan.addPhase(PhasePosition.AFTER_PARSING, new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL)); return plan; } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfBoxingEliminationTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -89,19 +89,19 @@ } Assumptions assumptions = new Assumptions(false); - new InliningPhase(null, runtime(), hints, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); - new CanonicalizerPhase(null, runtime(), assumptions).apply(graph); + new InliningPhase(runtime(), hints, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); new PhiStampPhase().apply(graph); - new CanonicalizerPhase(null, runtime(), assumptions).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(null, runtime(), assumptions).apply(graph); - new CanonicalizerPhase(null, runtime(), assumptions).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(null, runtime(), assumptions).apply(referenceGraph); + new CanonicalizerPhase(runtime(), assumptions).apply(referenceGraph); new DeadCodeEliminationPhase().apply(referenceGraph); assertEquals(referenceGraph, graph); diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -144,7 +144,7 @@ n.replaceFirstInput(local, constant); } Debug.dump(graph, "Graph"); - new CanonicalizerPhase(null, runtime(), new Assumptions(false)).apply(graph); + new CanonicalizerPhase(runtime(), new Assumptions(false)).apply(graph); StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); assertEquals(referenceGraph, graph); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -65,8 +65,8 @@ hints.add(invoke); } Assumptions assumptions = new Assumptions(false); - new InliningPhase(null, runtime(), hints, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); - new CanonicalizerPhase(null, runtime(), assumptions).apply(graph); + new InliningPhase(runtime(), hints, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); new DeadCodeEliminationPhase().apply(graph); } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -76,8 +76,8 @@ } Assumptions assumptions = new Assumptions(false); - new InliningPhase(null, runtime(), hints, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); - new CanonicalizerPhase(null, runtime(), assumptions).apply(graph); + new InliningPhase(runtime(), hints, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); new DeadCodeEliminationPhase().apply(graph); StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); assertEquals(referenceGraph, graph); diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -133,8 +133,8 @@ } Assumptions assumptions = new Assumptions(false); - new CanonicalizerPhase(null, runtime(), assumptions).apply(graph); - new CanonicalizerPhase(null, runtime(), assumptions).apply(referenceGraph); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); + new CanonicalizerPhase(runtime(), assumptions).apply(referenceGraph); Debug.scope("Test", new DebugDumpScope("Test:" + snippet), new Runnable() { @Override diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,246 @@ +/* + * 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 static org.junit.Assert.*; + +import java.util.concurrent.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.schedule.*; + +/** + * In these test the FrameStates are explicitly cleared out, so that the scheduling of + * FloatingReadNodes depends solely on the scheduling algorithm. The FrameStates normally keep the + * FloatingReadNodes above a certain point, so that they (most of the time...) magically do the + * right thing. + * + * The scheduling shouldn't depend on FrameStates, which is tested by this class. + */ +public class MemoryScheduleTest extends GraphScheduleTest { + + private static enum TestMode { + WITH_FRAMESTATES, WITHOUT_FRAMESTATES, INLINED_WITHOUT_FRAMESTATES + } + + public static class Container { + + public int a; + public int b; + public int c; + } + + private static final Container container = new Container(); + + /** + * In this test the read should be scheduled before the write. + */ + public static int testSimpleSnippet() { + try { + return container.a; + } finally { + container.a = 15; + } + } + + @Test + public void testSimple() { + for (TestMode mode : TestMode.values()) { + SchedulePhase schedule = getFinalSchedule("testSimpleSnippet", mode); + assertReadAfterWrite(schedule, false); + } + } + + /** + * In this case the read should be scheduled in the first block. + */ + public static int testSplitSnippet1(int a) { + try { + return container.a; + } finally { + if (a < 0) { + container.a = 15; + } else { + container.b = 15; + } + } + } + + @Test + public void testSplit1() { + for (TestMode mode : TestMode.values()) { + SchedulePhase schedule = getFinalSchedule("testSplitSnippet1", mode); + assertReadWithinStartBlock(schedule, true); + } + } + + /** + * Here the read should float to the end. + */ + public static int testSplit2Snippet(int a) { + try { + return container.a; + } finally { + if (a < 0) { + container.c = 15; + } else { + container.b = 15; + } + } + } + + @Test + public void testSplit2() { + SchedulePhase schedule = getFinalSchedule("testSplit2Snippet", TestMode.WITHOUT_FRAMESTATES); + assertReadWithinStartBlock(schedule, false); + } + + /** + * Here the read should not float to the end. + */ + public static int testLoop1Snippet(int a, int b) { + try { + return container.a; + } finally { + for (int i = 0; i < a; i++) { + if (b < 0) { + container.b = 10; + } else { + container.a = 15; + } + } + } + } + + @Test + public void testLoop1() { + SchedulePhase schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES); + assertEquals(7, schedule.getCFG().getBlocks().length); + assertReadWithinStartBlock(schedule, true); + } + + /** + * Here the read should float to the end. + */ + public static int testLoop2Snippet(int a, int b) { + try { + return container.a; + } finally { + for (int i = 0; i < a; i++) { + if (b < 0) { + container.b = 10; + } else { + container.c = 15; + } + } + } + } + + @Test + public void testLoop2() { + SchedulePhase schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES); + assertEquals(7, schedule.getCFG().getBlocks().length); + assertReadWithinStartBlock(schedule, false); + } + + /** + * Here the read should float to the end (into the same block as the return). + */ + public static int testArrayCopySnippet(Integer intValue, char[] a, char[] b, int len) { + System.arraycopy(a, 0, b, 0, len); + return intValue.intValue(); + } + + @Test + public void testArrayCopy() { + SchedulePhase schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES); + StructuredGraph graph = (StructuredGraph) schedule.getCFG().getStartBlock().getBeginNode().graph(); + ReturnNode ret = graph.getNodes(ReturnNode.class).first(); + assertTrue(ret.result() instanceof FloatingReadNode); + assertEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result())); + } + + private void assertReadAfterWrite(SchedulePhase schedule, boolean readAfterWrite) { + boolean writeEncountered = false; + assertEquals(1, schedule.getCFG().getBlocks().length); + for (Node node : schedule.getBlockToNodesMap().get(schedule.getCFG().getStartBlock())) { + if (node instanceof WriteNode) { + writeEncountered = true; + } else if (node instanceof FloatingReadNode) { + assertEquals(readAfterWrite, writeEncountered); + } + } + } + + private void assertReadWithinStartBlock(SchedulePhase schedule, boolean withinStartBlock) { + boolean readEncountered = false; + for (Node node : schedule.getBlockToNodesMap().get(schedule.getCFG().getStartBlock())) { + if (node instanceof FloatingReadNode) { + readEncountered = true; + } + } + assertEquals(withinStartBlock, readEncountered); + } + + private SchedulePhase getFinalSchedule(final String snippet, final TestMode mode) { + return Debug.scope("FloatingReadTest", new DebugDumpScope(snippet), new Callable() { + + @Override + public SchedulePhase call() throws Exception { + 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 LoweringPhase(null, runtime(), new Assumptions(false)).apply(graph); + if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) { + for (Node node : graph.getNodes()) { + if (node instanceof StateSplit) { + FrameState stateAfter = ((StateSplit) node).stateAfter(); + if (stateAfter != null) { + ((StateSplit) node).setStateAfter(null); + GraphUtil.killWithUnusedFloatingInputs(stateAfter); + } + } + } + } + new FloatingReadPhase().apply(graph); + + new RemoveValueProxyPhase().apply(graph); + + SchedulePhase schedule = new SchedulePhase(); + schedule.apply(graph); + return schedule; + } + }); + } +} diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -54,7 +54,7 @@ return 1; } - @Test(expected = AssertionError.class) + @Test public void test1() { test("test1Snippet"); } @@ -93,8 +93,8 @@ hints.add(invoke); } Assumptions assumptions = new Assumptions(false); - new InliningPhase(null, runtime(), hints, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); - new CanonicalizerPhase(null, runtime(), assumptions).apply(graph); + new InliningPhase(runtime(), hints, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); new DeadCodeEliminationPhase().apply(graph); return graph; } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReassociateAndCanonicalTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -244,9 +244,9 @@ private void test(String test, String ref) { StructuredGraph testGraph = parse(test); Assumptions assumptions = new Assumptions(false); - new CanonicalizerPhase(null, runtime(), assumptions).apply(testGraph); + new CanonicalizerPhase(runtime(), assumptions).apply(testGraph); StructuredGraph refGraph = parse(ref); - new CanonicalizerPhase(null, runtime(), assumptions).apply(refGraph); + new CanonicalizerPhase(runtime(), assumptions).apply(refGraph); assertEquals(testGraph, refGraph); } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -165,11 +165,10 @@ // No debug scope to reduce console noise for @Test(expected = ...) tests StructuredGraph graph = parse(snippet); Debug.dump(graph, "Graph"); - // TypeSystemTest.outputGraph(graph); Assumptions assumptions = new Assumptions(false); - new CanonicalizerPhase(null, runtime(), assumptions).apply(graph); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); new ConditionalEliminationPhase(runtime()).apply(graph); - new CanonicalizerPhase(null, runtime(), assumptions).apply(graph); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); StructuredGraph referenceGraph = parse(referenceSnippet); assertEquals(referenceGraph, graph); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StampCanonicalizerTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -98,7 +98,7 @@ private void testZeroReturn(String methodName) { StructuredGraph graph = parse(methodName); - new CanonicalizerPhase(null, runtime(), new Assumptions(false)).apply(graph); + new CanonicalizerPhase(runtime(), new Assumptions(false)).apply(graph); new DeadCodeEliminationPhase().apply(graph); assertConstantReturn(graph, 0); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StraighteningTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -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(null, runtime(), new Assumptions(false)).apply(graph); + new CanonicalizerPhase(runtime(), new Assumptions(false)).apply(graph); StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); assertEquals(referenceGraph, graph); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -186,13 +186,13 @@ StructuredGraph graph = parse(snippet); Debug.dump(graph, "Graph"); Assumptions assumptions = new Assumptions(false); - new CanonicalizerPhase(null, runtime(), assumptions).apply(graph); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); new ConditionalEliminationPhase(runtime()).apply(graph); - new CanonicalizerPhase(null, runtime(), assumptions).apply(graph); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); // a second canonicalizer is needed to process nested MaterializeNodes - new CanonicalizerPhase(null, runtime(), assumptions).apply(graph); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); StructuredGraph referenceGraph = parse(referenceSnippet); - new CanonicalizerPhase(null, runtime(), assumptions).apply(referenceGraph); + new CanonicalizerPhase(runtime(), assumptions).apply(referenceGraph); assertEquals(referenceGraph, graph); } @@ -242,9 +242,9 @@ StructuredGraph graph = parse(snippet); Debug.dump(graph, "Graph"); Assumptions assumptions = new Assumptions(false); - new CanonicalizerPhase(null, runtime(), assumptions).apply(graph); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); new ConditionalEliminationPhase(runtime()).apply(graph); - new CanonicalizerPhase(null, runtime(), assumptions).apply(graph); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); Debug.dump(graph, "Graph"); Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes(clazz).iterator().hasNext()); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,131 @@ +/* + * 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.backend; + +import java.util.*; +import java.util.concurrent.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.ValueProcedure; +import com.oracle.graal.lir.StandardOp.MoveOp; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.phases.*; + +public class AllocatorTest extends GraalCompilerTest { + + protected void test(String snippet, final int expectedRegisters, final int expectedRegRegMoves, final int expectedSpillMoves) { + final StructuredGraph graph = parse(snippet); + Debug.scope("AllocatorTest", new Object[]{graph, graph.method(), runtime}, new Runnable() { + + @Override + public void run() { + final RegisterStats stats = getRegisterStats(graph); + + Debug.scope("Assertions", stats.lir, new Runnable() { + + @Override + public void run() { + Assert.assertEquals("register count", expectedRegisters, stats.registers.size()); + Assert.assertEquals("reg-reg moves", expectedRegRegMoves, stats.regRegMoves); + Assert.assertEquals("spill moves", expectedSpillMoves, stats.spillMoves); + } + }); + } + }); + } + + private class RegisterStats { + + public final LIR lir; + public HashSet registers = new HashSet<>(); + public int regRegMoves; + public int spillMoves; + + public RegisterStats(LIR lir) { + this.lir = lir; + + for (Block block : lir.codeEmittingOrder()) { + for (LIRInstruction instr : lir.lir(block)) { + collectStats(instr); + } + } + } + + private void collectStats(final LIRInstruction instr) { + instr.forEachOutput(new ValueProcedure() { + + @Override + public Value doValue(Value value) { + if (ValueUtil.isRegister(value)) { + final Register reg = ValueUtil.asRegister(value); + registers.add(reg); + } + return value; + } + }); + + if (instr instanceof MoveOp) { + MoveOp move = (MoveOp) instr; + Value def = move.getResult(); + Value use = move.getInput(); + if (ValueUtil.isRegister(def)) { + if (ValueUtil.isRegister(use) && ValueUtil.asRegister(def) != ValueUtil.asRegister(use)) { + regRegMoves++; + } + } else if (ValueUtil.isStackSlot(def)) { + spillMoves++; + } + } + } + } + + private RegisterStats getRegisterStats(final StructuredGraph graph) { + final PhasePlan phasePlan = getDefaultPhasePlan(); + final Assumptions assumptions = new Assumptions(GraalOptions.OptAssumptions); + + final LIR lir = Debug.scope("FrontEnd", new Callable() { + + @Override + public LIR call() { + return GraalCompiler.emitHIR(runtime, backend.target, graph, assumptions, null, phasePlan, OptimisticOptimizations.NONE, new SpeculationLog()); + } + }); + + return Debug.scope("BackEnd", lir, new Callable() { + + @Override + public RegisterStats call() { + GraalCompiler.emitLIR(backend, backend.target, lir, graph, graph.method()); + return new RegisterStats(lir); + } + }); + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,201 @@ +/* + * 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.deopt; + +import java.lang.reflect.*; + +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.*; + +/** + * In the following tests, the usages of local variable "a" are replaced with the integer constant + * 0. Then canonicalization is applied and it is verified that the resulting graph is equal to the + * graph of the method that just has a "return 1" statement in it. + */ +public class CompiledMethodTest extends GraalCompilerTest { + + public static Object testMethod(Object arg1, Object arg2, Object arg3) { + return arg1 + " " + arg2 + " " + arg3; + } + + Object f1; + + public Object testMethodVirtual(Object arg1, Object arg2, Object arg3) { + return f1 + " " + arg1 + " " + arg2 + " " + arg3; + } + + @LongTest + public void test1() { + Method method = getMethod("testMethod"); + final StructuredGraph graph = parse(method); + 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 && " ".equals(constant.value.asObject())) { + graph.replaceFloating(constant, ConstantNode.forObject("-", runtime, graph)); + } + } + } + + final ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(method); + InstalledCode compiledMethod = getCode(javaMethod, graph); + try { + Object result = compiledMethod.execute("1", "2", "3"); + Assert.assertEquals("1-2-3", result); + } catch (MethodInvalidatedException t) { + Assert.fail("method invalidated"); + } + } + + @LongTest + public void test3() { + Method method = getMethod("testMethod"); + final StructuredGraph graph = parse(method); + final ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(method); + InstalledCode compiledMethod = getCode(javaMethod, graph); + try { + Object result = compiledMethod.executeVarargs("1", "2", "3"); + Assert.assertEquals("1 2 3", result); + } catch (MethodInvalidatedException t) { + Assert.fail("method invalidated"); + } + } + + @LongTest + public void test4() { + Method method = getMethod("testMethodVirtual"); + final StructuredGraph graph = parse(method); + final ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(method); + InstalledCode compiledMethod = getCode(javaMethod, graph); + try { + f1 = "0"; + Object result = compiledMethod.executeVarargs(this, "1", "2", "3"); + Assert.assertEquals("0 1 2 3", result); + } catch (MethodInvalidatedException 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 dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/SynchronizedMethodDeoptimizationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/SynchronizedMethodDeoptimizationTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,74 @@ +/* + * 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.deopt; + +import java.lang.reflect.*; + +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.*; + +/** + * In the following tests, we try to deoptimize out of synchronized methods. + */ +public class SynchronizedMethodDeoptimizationTest extends GraalCompilerTest { + + public static final int N = 15000; + + public static synchronized Object testMethodSynchronized(Object o) { + if (o == null) { + return null; + } + return o; + } + + @Test + public void test1() { + Method method = getMethod("testMethodSynchronized"); + String testString = "test"; + for (int i = 0; i < N; ++i) { + Assert.assertEquals(testString, testMethodSynchronized(testString)); + } + final StructuredGraph graph = parseProfiled(method); + final ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(method); + InstalledCode compiledMethod = getCode(javaMethod, graph); + try { + Object result = compiledMethod.executeVarargs(testString); + Assert.assertEquals(testString, result); + } catch (MethodInvalidatedException t) { + Assert.fail("method invalidated"); + } + + try { + Object result = compiledMethod.executeVarargs(new Object[]{null}); + Assert.assertEquals(null, result); + Assert.assertFalse(compiledMethod.isValid()); + } catch (MethodInvalidatedException t) { + Assert.fail("method invalidated"); + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -205,9 +205,9 @@ } Assumptions assumptions = new Assumptions(false); - new InliningPhase(null, runtime(), null, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + new InliningPhase(runtime(), null, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); new DeadCodeEliminationPhase().apply(graph); - new PartialEscapeAnalysisPhase(null, runtime(), assumptions, iterativeEscapeAnalysis).apply(graph); + new PartialEscapeAnalysisPhase(runtime(), assumptions, iterativeEscapeAnalysis).apply(graph); Assert.assertEquals(1, graph.getNodes(ReturnNode.class).count()); ReturnNode returnNode = graph.getNodes(ReturnNode.class).first(); if (expectedConstantResult != null) { diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -150,14 +150,14 @@ n.node().setProbability(100000); } Assumptions assumptions = new Assumptions(false); - new InliningPhase(null, runtime(), null, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + new InliningPhase(runtime(), null, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); new DeadCodeEliminationPhase().apply(graph); - new CanonicalizerPhase(null, runtime(), assumptions).apply(graph); - new PartialEscapeAnalysisPhase(null, runtime(), assumptions, false).apply(graph); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); + new PartialEscapeAnalysisPhase(runtime(), assumptions, false).apply(graph); new CullFrameStatesPhase().apply(graph); new DeadCodeEliminationPhase().apply(graph); - new CanonicalizerPhase(null, runtime(), assumptions).apply(graph); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); return graph; } catch (AssertionFailedError t) { throw new RuntimeException(t.getMessage() + "\n" + getCanonicalGraphString(graph), t); diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -136,9 +136,9 @@ Assumptions assumptions = new Assumptions(true); new ComputeProbabilityPhase().apply(graph); Debug.dump(graph, "Graph"); - new InliningPhase(null, runtime(), null, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); + new InliningPhase(runtime(), null, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); Debug.dump(graph, "Graph"); - new CanonicalizerPhase(null, runtime(), assumptions).apply(graph); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); new DeadCodeEliminationPhase().apply(graph); return graph; } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Thu Mar 21 14:11:13 2013 +0100 @@ -47,55 +47,38 @@ public class GraalCompiler { - /** - * The target that this compiler has been configured for. - */ - public final TargetDescription target; - - /** - * The runtime that this compiler has been configured for. - */ - public final GraalCodeCacheProvider runtime; - - /** - * The backend that this compiler has been configured for. - */ - public final Backend backend; - - public GraalCompiler(GraalCodeCacheProvider runtime, TargetDescription target, Backend backend) { - this.runtime = runtime; - this.target = target; - this.backend = backend; - } - - public CompilationResult compileMethod(final ResolvedJavaMethod method, final StructuredGraph graph, final GraphCache cache, final PhasePlan plan, final OptimisticOptimizations optimisticOpts) { + 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) { assert (method.getModifiers() & Modifier.NATIVE) == 0 : "compiling native methods is not supported"; - return Debug.scope("GraalCompiler", new Object[]{graph, method, this}, new Callable() { + final CompilationResult compilationResult = new CompilationResult(); + Debug.scope("GraalCompiler", new Object[]{graph, method, runtime}, new Runnable() { - public CompilationResult call() { + public void run() { final Assumptions assumptions = new Assumptions(GraalOptions.OptAssumptions); final LIR lir = Debug.scope("FrontEnd", new Callable() { public LIR call() { - return emitHIR(graph, assumptions, cache, plan, optimisticOpts); + return emitHIR(runtime, target, graph, assumptions, cache, plan, optimisticOpts, speculationLog); } }); - final FrameMap frameMap = Debug.scope("BackEnd", lir, new Callable() { + final LIRGenerator lirGen = Debug.scope("BackEnd", lir, new Callable() { - public FrameMap call() { - return emitLIR(lir, graph, method); + public LIRGenerator call() { + return emitLIR(backend, target, lir, graph, method); } }); - return Debug.scope("CodeGen", frameMap, new Callable() { + Debug.scope("CodeGen", lirGen, new Runnable() { - public CompilationResult call() { - return emitCode(getLeafGraphIdArray(graph), assumptions, method, lir, frameMap); + public void run() { + emitCode(backend, getLeafGraphIdArray(graph), assumptions, method, lirGen, compilationResult); } }); } }); + + return compilationResult; } private static long[] getLeafGraphIdArray(StructuredGraph graph) { @@ -110,8 +93,17 @@ /** * Builds the graph, optimizes it. + * + * @param runtime + * + * @param target */ - public LIR emitHIR(StructuredGraph graph, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) { + public static LIR emitHIR(GraalCodeCacheProvider runtime, TargetDescription target, StructuredGraph graph, Assumptions assumptions, GraphCache cache, PhasePlan plan, + OptimisticOptimizations optimisticOpts, final SpeculationLog speculationLog) { + + if (speculationLog != null) { + speculationLog.snapshot(); + } if (graph.start().next() == null) { plan.runPhases(PhasePosition.AFTER_PARSING, graph); @@ -125,16 +117,16 @@ } if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions).apply(graph); + new CanonicalizerPhase(runtime, assumptions).apply(graph); } if (GraalOptions.Inline && !plan.isPhaseDisabled(InliningPhase.class)) { - new InliningPhase(target, runtime, null, assumptions, cache, plan, optimisticOpts).apply(graph); + new InliningPhase(runtime, null, assumptions, cache, plan, optimisticOpts).apply(graph); new DeadCodeEliminationPhase().apply(graph); - if (GraalOptions.CheckCastElimination && GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions).apply(graph); - new IterativeConditionalEliminationPhase(target, runtime, assumptions).apply(graph); + if (GraalOptions.ConditionalElimination && GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase(runtime, assumptions).apply(graph); + new IterativeConditionalEliminationPhase(runtime, assumptions).apply(graph); } } @@ -145,19 +137,23 @@ if (GraalOptions.FullUnroll) { new LoopFullUnrollPhase(runtime, assumptions).apply(graph); if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions).apply(graph); + new CanonicalizerPhase(runtime, assumptions).apply(graph); } } if (GraalOptions.OptTailDuplication) { new TailDuplicationPhase().apply(graph); if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions).apply(graph); + new CanonicalizerPhase(runtime, assumptions).apply(graph); } } if (GraalOptions.PartialEscapeAnalysis && !plan.isPhaseDisabled(PartialEscapeAnalysisPhase.class)) { - new PartialEscapeAnalysisPhase(target, runtime, assumptions, true).apply(graph); + new PartialEscapeAnalysisPhase(runtime, assumptions, true).apply(graph); + } + + if (GraalOptions.OptConvertDeoptsToGuards) { + new ConvertDeoptimizeToGuardPhase().apply(graph); } new LockEliminationPhase().apply(graph); @@ -169,7 +165,7 @@ new RemoveValueProxyPhase().apply(graph); if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions).apply(graph); + new CanonicalizerPhase(runtime, assumptions).apply(graph); } new LoweringPhase(target, runtime, assumptions).apply(graph); @@ -181,7 +177,7 @@ if (GraalOptions.OptFloatingReads) { int mark = graph.getMark(); new FloatingReadPhase().apply(graph); - new CanonicalizerPhase(target, runtime, assumptions, mark, null).apply(graph); + new CanonicalizerPhase(runtime, assumptions, mark, null).apply(graph); if (GraalOptions.OptReadElimination) { new ReadEliminationPhase().apply(graph); } @@ -189,15 +185,15 @@ new RemoveValueProxyPhase().apply(graph); if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions).apply(graph); + new CanonicalizerPhase(runtime, assumptions).apply(graph); } if (GraalOptions.OptEliminatePartiallyRedundantGuards) { new EliminatePartiallyRedundantGuardsPhase(false, true).apply(graph); } - if (GraalOptions.CheckCastElimination && GraalOptions.OptCanonicalizer) { - new IterativeConditionalEliminationPhase(target, runtime, assumptions).apply(graph); + if (GraalOptions.ConditionalElimination && GraalOptions.OptCanonicalizer) { + new IterativeConditionalEliminationPhase(runtime, assumptions).apply(graph); } if (GraalOptions.OptEliminatePartiallyRedundantGuards) { @@ -208,10 +204,10 @@ plan.runPhases(PhasePosition.LOW_LEVEL, graph); + new GuardLoweringPhase(target).apply(graph); + // Add safepoints to loops - if (GraalOptions.GenLoopSafepoints) { - new LoopSafepointInsertionPhase().apply(graph); - } + new SafepointInsertionPhase().apply(graph); final SchedulePhase schedule = new SchedulePhase(); schedule.apply(graph); @@ -231,7 +227,7 @@ List codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock); List linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock); - LIR lir = new LIR(schedule.getCFG(), schedule.getBlockToNodesMap(), linearScanOrder, codeEmittingOrder); + LIR lir = new LIR(schedule.getCFG(), schedule.getBlockToNodesMap(), linearScanOrder, codeEmittingOrder, speculationLog); Debug.dump(lir, "After linear scan order"); return lir; @@ -240,11 +236,11 @@ } - public FrameMap emitLIR(final LIR lir, StructuredGraph graph, final ResolvedJavaMethod method) { - final FrameMap frameMap = backend.newFrameMap(runtime.lookupRegisterConfig(method)); - final LIRGenerator lirGenerator = backend.newLIRGenerator(graph, frameMap, method, lir); + public static LIRGenerator emitLIR(Backend backend, final TargetDescription target, final LIR lir, StructuredGraph graph, final ResolvedJavaMethod method) { + final FrameMap frameMap = backend.newFrameMap(); + final LIRGenerator lirGen = backend.newLIRGenerator(graph, frameMap, method, lir); - Debug.scope("LIRGen", lirGenerator, new Runnable() { + Debug.scope("LIRGen", lirGen, new Runnable() { public void run() { for (Block b : lir.linearScanOrder()) { @@ -261,23 +257,25 @@ emitBlock(pred); } } - lirGenerator.doBlock(b); + lirGen.doBlock(b); } } }); + lirGen.beforeRegisterAllocation(); + Debug.scope("Allocator", new Runnable() { public void run() { - new LinearScan(target, method, lir, lirGenerator, frameMap).allocate(); + new LinearScan(target, method, lir, lirGen, frameMap).allocate(); } }); - return frameMap; + return lirGen; } - public CompilationResult emitCode(long[] leafGraphIds, Assumptions assumptions, ResolvedJavaMethod method, LIR lir, FrameMap frameMap) { - TargetMethodAssembler tasm = backend.newAssembler(frameMap, lir); - backend.emitCode(tasm, method, lir); + public static void emitCode(Backend backend, long[] leafGraphIds, Assumptions assumptions, ResolvedJavaMethod method, LIRGenerator lirGen, CompilationResult compilationResult) { + TargetMethodAssembler tasm = backend.newAssembler(lirGen, compilationResult); + backend.emitCode(tasm, method, lirGen); CompilationResult result = tasm.finishTargetMethod(method, false); if (!assumptions.isEmpty()) { result.setAssumptions(assumptions); @@ -285,6 +283,5 @@ result.setLeafGraphIds(leafGraphIds); Debug.dump(result, "After code generation"); - return result; } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java Thu Mar 21 14:11:13 2013 +0100 @@ -417,8 +417,8 @@ public final int operandNumber; /** - * The {@linkplain RegisterValue register}, {@linkplain StackSlot spill slot} or - * {@linkplain Address address} assigned to this interval. + * The {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to this + * interval. */ private Value location; @@ -515,8 +515,8 @@ } /** - * Gets the {@linkplain RegisterValue register}, {@linkplain StackSlot spill slot} or - * {@linkplain Address address} assigned to this interval. + * Gets the {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to + * this interval. */ public Value location() { return location; diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Thu Mar 21 14:11:13 2013 +0100 @@ -282,7 +282,6 @@ * @return the created interval */ Interval createInterval(Value operand) { - assert isProcessed(operand); assert isLegal(operand); int operandNumber = operandNumber(operand); Interval interval = new Interval(operand, operandNumber); @@ -347,6 +346,15 @@ return intervals[operandNumber]; } + Interval getOrCreateInterval(Value operand) { + Interval ret = intervalFor(operand); + if (ret == null) { + return createInterval(operand); + } else { + return ret; + } + } + /** * Gets the highest instruction id allocated by this object. */ @@ -968,11 +976,7 @@ TTY.println(" use %s from %d to %d (%s)", operand, from, to, registerPriority.name()); } - Interval interval = intervalFor(operand); - if (interval == null) { - interval = createInterval(operand); - } - + Interval interval = getOrCreateInterval(operand); if (kind != Kind.Illegal) { interval.setKind(kind); } @@ -990,11 +994,8 @@ if (GraalOptions.TraceLinearScanLevel >= 2) { TTY.println(" temp %s tempPos %d (%s)", operand, tempPos, RegisterPriority.MustHaveRegister.name()); } - Interval interval = intervalFor(operand); - if (interval == null) { - interval = createInterval(operand); - } + Interval interval = getOrCreateInterval(operand); if (kind != Kind.Illegal) { interval.setKind(kind); } @@ -1014,42 +1015,26 @@ if (GraalOptions.TraceLinearScanLevel >= 2) { TTY.println(" def %s defPos %d (%s)", operand, defPos, registerPriority.name()); } - Interval interval = intervalFor(operand); - if (interval != null) { - if (kind != Kind.Illegal) { - interval.setKind(kind); - } + Interval interval = getOrCreateInterval(operand); + if (kind != Kind.Illegal) { + interval.setKind(kind); + } - Range r = interval.first(); - if (r.from <= defPos) { - // Update the starting point (when a range is first created for a use, its - // start is the beginning of the current block until a def is encountered.) - r.from = defPos; - interval.addUsePos(defPos, registerPriority); - - } else { - // Dead value - make vacuous interval - // also add register priority for dead intervals - interval.addRange(defPos, defPos + 1); - interval.addUsePos(defPos, registerPriority); - if (GraalOptions.TraceLinearScanLevel >= 2) { - TTY.println("Warning: def of operand %s at %d occurs without use", operand, defPos); - } - } + Range r = interval.first(); + if (r.from <= defPos) { + // Update the starting point (when a range is first created for a use, its + // start is the beginning of the current block until a def is encountered.) + r.from = defPos; + interval.addUsePos(defPos, registerPriority); } else { // Dead value - make vacuous interval // also add register priority for dead intervals - interval = createInterval(operand); - if (kind != Kind.Illegal) { - interval.setKind(kind); - } - interval.addRange(defPos, defPos + 1); interval.addUsePos(defPos, registerPriority); if (GraalOptions.TraceLinearScanLevel >= 2) { - TTY.println("Warning: dead value %s at %d in live intervals", operand, defPos); + TTY.println("Warning: def of operand %s at %d occurs without use", operand, defPos); } } @@ -1066,8 +1051,7 @@ static RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) { if (op instanceof MoveOp) { MoveOp move = (MoveOp) op; - if (isStackSlot(move.getInput()) && move.getInput().getKind() != Kind.Object) { - // method argument (condition must be equal to handleMethodArguments) + if (optimizeMethodArgument(move.getInput())) { return RegisterPriority.None; } } @@ -1088,6 +1072,14 @@ return RegisterPriority.MustHaveRegister; } + private static boolean optimizeMethodArgument(Value value) { + /* + * Object method arguments that are passed on the stack are currently not optimized because + * this requires that the runtime visits method arguments during stack walking. + */ + return isStackSlot(value) && asStackSlot(value).isInCallerFrame() && value.getKind() != Kind.Object; + } + /** * Optimizes moves related to incoming stack based arguments. The interval for the destination * of such moves is assigned the stack slot (which is in the caller's frame) as its spill slot. @@ -1095,8 +1087,8 @@ void handleMethodArguments(LIRInstruction op) { if (op instanceof MoveOp) { MoveOp move = (MoveOp) op; - if (isStackSlot(move.getInput()) && move.getInput().getKind() != Kind.Object) { - StackSlot slot = (StackSlot) move.getInput(); + if (optimizeMethodArgument(move.getInput())) { + StackSlot slot = asStackSlot(move.getInput()); if (GraalOptions.DetailedAsserts) { assert op.id() > 0 : "invalid id"; assert blockForId(op.id()).getPredecessorCount() == 0 : "move from stack must be in first block"; @@ -1114,7 +1106,7 @@ } } - void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet flags) { + void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet flags, final boolean hintAtDef) { if (flags.contains(OperandFlag.HINT) && isVariableOrRegister(targetValue)) { op.forEachRegisterHint(targetValue, mode, new ValueProcedure() { @@ -1122,15 +1114,20 @@ @Override protected Value doValue(Value registerHint) { if (isVariableOrRegister(registerHint)) { - Interval from = intervalFor(registerHint); - Interval to = intervalFor(targetValue); - if (from != null && to != null) { + Interval from = getOrCreateInterval(registerHint); + Interval to = getOrCreateInterval(targetValue); + + // hints always point from def to use + if (hintAtDef) { to.setLocationHint(from); - if (GraalOptions.TraceLinearScanLevel >= 4) { - TTY.println("operation at opId %d: added hint from interval %d to %d", op.id(), from.operandNumber, to.operandNumber); - } - return registerHint; + } else { + from.setLocationHint(to); } + + if (GraalOptions.TraceLinearScanLevel >= 4) { + TTY.println("operation at opId %d: added hint from interval %d to %d", op.id(), from.operandNumber, to.operandNumber); + } + return registerHint; } return null; } @@ -1201,7 +1198,7 @@ public Value doValue(Value operand, OperandMode mode, EnumSet flags) { if (isVariableOrRegister(operand)) { addDef(operand, opId, registerPriorityOfOutputOperand(op), operand.getKind().getStackKind()); - addRegisterHint(op, operand, mode, flags); + addRegisterHint(op, operand, mode, flags, true); } return operand; } @@ -1212,7 +1209,7 @@ public Value doValue(Value operand, OperandMode mode, EnumSet flags) { if (isVariableOrRegister(operand)) { addTemp(operand, opId, RegisterPriority.MustHaveRegister, operand.getKind().getStackKind()); - addRegisterHint(op, operand, mode, flags); + addRegisterHint(op, operand, mode, flags, false); } return operand; } @@ -1224,7 +1221,7 @@ if (isVariableOrRegister(operand)) { RegisterPriority p = registerPriorityOfInputOperand(flags); addUse(operand, blockFrom, opId + 1, p, operand.getKind().getStackKind()); - addRegisterHint(op, operand, mode, flags); + addRegisterHint(op, operand, mode, flags, false); } return operand; } @@ -1236,7 +1233,7 @@ if (isVariableOrRegister(operand)) { RegisterPriority p = registerPriorityOfInputOperand(flags); addUse(operand, blockFrom, opId, p, operand.getKind().getStackKind()); - addRegisterHint(op, operand, mode, flags); + addRegisterHint(op, operand, mode, flags, false); } return operand; } @@ -1960,12 +1957,6 @@ throw new GraalInternalError(""); } - if (!isProcessed(i1.location())) { - TTY.println("Can not have an Interval for an ignored register " + i1.location()); - TTY.println(i1.logString(this)); - throw new GraalInternalError(""); - } - if (i1.first() == Range.EndMarker) { TTY.println("Interval %d has no Range", i1.operandNumber); TTY.println(i1.logString(this)); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Thu Mar 21 14:11:13 2013 +0100 @@ -45,7 +45,7 @@ private HashMap virtualObjects = new HashMap<>(); private IdentityHashMap objectStates = new IdentityHashMap<>(); - public LIRFrameState build(FrameState topState, List lockData, LabelRef exceptionEdge) { + public LIRFrameState build(FrameState topState, List lockData, short reason, LabelRef exceptionEdge) { assert virtualObjects.size() == 0; assert objectStates.size() == 0; @@ -103,7 +103,7 @@ } objectStates.clear(); - return new LIRFrameState(frame, virtualObjectsArray, exceptionEdge); + return new LIRFrameState(frame, virtualObjectsArray, exceptionEdge, reason); } private BytecodeFrame computeFrameForState(FrameState state, List lockDataSlots) { @@ -135,7 +135,7 @@ throw new BailoutException("unbalanced monitors: found monitor for unknown frame (%d != %d) at %s", lockDataSlots.size(), numLocks, state); } } - assert state.bci >= 0 || state.bci == FrameState.BEFORE_BCI; + assert state.bci >= 0 || state.bci == FrameState.BEFORE_BCI : "bci == " + state.bci; return new BytecodeFrame(caller, state.method(), state.bci, state.rethrowException(), state.duringCall(), values, numLocals, numStack, numLocks); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Thu Mar 21 14:11:13 2013 +0100 @@ -54,17 +54,18 @@ */ public abstract class LIRGenerator extends LIRGeneratorTool { + public final FrameMap frameMap; + public final NodeMap nodeOperands; + public final LIR lir; + protected final StructuredGraph graph; protected final CodeCacheProvider runtime; protected final TargetDescription target; protected final ResolvedJavaMethod method; - protected final FrameMap frameMap; - public final NodeMap nodeOperands; - protected final LIR lir; private final DebugInfoBuilder debugInfoBuilder; - private Block currentBlock; + protected Block currentBlock; private ValueNode currentInstruction; private ValueNode lastInstructionPrinted; // Debugging only private FrameState lastState; @@ -90,6 +91,16 @@ */ private final ArrayList lockDataSlots; + /** + * Checks whether the supplied constant can be used without loading it into a register for store + * operations, i.e., on the right hand side of a memory access. + * + * @param c The constant to check. + * @return True if the constant can be used directly, false if the constant needs to be in a + * register. + */ + public abstract boolean canStoreConstant(Constant c); + public LIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) { this.graph = graph; this.runtime = runtime; @@ -151,7 +162,6 @@ public Variable newVariable(Kind kind) { Kind stackKind = kind.getStackKind(); switch (stackKind) { - case Jsr: case Int: case Long: case Object: @@ -184,6 +194,14 @@ @Override public abstract Variable emitMove(Value input); + public AllocatableValue asAllocatable(Value value) { + if (isAllocatableValue(value)) { + return asAllocatableValue(value); + } else { + return emitMove(value); + } + } + public Variable load(Value value) { if (!isVariable(value)) { return emitMove(value); @@ -198,18 +216,6 @@ return value; } - public Value loadForStore(Value value, Kind storeKind) { - if (isConstant(value) && canStoreConstant((Constant) value)) { - return value; - } - if (storeKind == Kind.Byte || storeKind == Kind.Boolean) { - Variable tempVar = new Variable(value.getKind(), lir.nextVariable(), Register.RegisterFlag.Byte); - emitMove(value, tempVar); - return tempVar; - } - return load(value); - } - protected LabelRef getLIRBlock(FixedNode b) { Block result = lir.cfg.blockFor(b); int suxIndex = currentBlock.getSuccessors().indexOf(result); @@ -226,19 +232,23 @@ } public LIRFrameState state() { + return state(null); + } + + public LIRFrameState state(DeoptimizationReason reason) { assert lastState != null || needOnlyOopMaps() : "must have state before instruction"; - return stateFor(lastState); + return stateFor(lastState, reason); } - public LIRFrameState stateFor(FrameState state) { - return stateFor(state, null); + public LIRFrameState stateFor(FrameState state, DeoptimizationReason reason) { + return stateForWithExceptionEdge(state, reason, null); } - public LIRFrameState stateFor(FrameState state, LabelRef exceptionEdge) { + public LIRFrameState stateForWithExceptionEdge(FrameState state, DeoptimizationReason reason, LabelRef exceptionEdge) { if (needOnlyOopMaps()) { - return new LIRFrameState(null, null, null); + return new LIRFrameState(null, null, null, (short) -1); } - return debugInfoBuilder.build(state, lockDataSlots.subList(0, currentLockCount), exceptionEdge); + return debugInfoBuilder.build(state, lockDataSlots.subList(0, currentLockCount), lir.getDeoptimizationReasons().addSpeculation(reason), exceptionEdge); } /** @@ -340,28 +350,6 @@ List nodes = lir.nodesFor(block); for (int i = 0; i < nodes.size(); i++) { Node instr = nodes.get(i); - - if (GraalOptions.OptImplicitNullChecks) { - Node nextInstr = null; - if (i < nodes.size() - 1) { - nextInstr = nodes.get(i + 1); - } - - if (instr instanceof GuardNode) { - GuardNode guardNode = (GuardNode) instr; - if (guardNode.condition() instanceof IsNullNode && guardNode.negated()) { - IsNullNode isNullNode = (IsNullNode) guardNode.condition(); - if (nextInstr instanceof Access) { - Access access = (Access) nextInstr; - if (isNullNode.object() == access.object() && canBeNullCheck(access.location())) { - // TTY.println("implicit null check"); - access.setNullCheck(true); - continue; - } - } - } - } - } if (GraalOptions.TraceLIRGeneratorLevel >= 3) { TTY.println("LIRGen for " + instr); } @@ -402,7 +390,7 @@ NodeClassIterable successors = block.getEndNode().successors(); assert successors.isNotEmpty() : "should have at least one successor : " + block.getEndNode(); - emitJump(getLIRBlock((FixedNode) successors.first()), null); + emitJump(getLIRBlock((FixedNode) successors.first())); } if (GraalOptions.TraceLIRGeneratorLevel >= 1) { @@ -461,10 +449,6 @@ ((LIRLowerable) node).generate(this); } - private boolean canBeNullCheck(LocationNode location) { - return !(location instanceof IndexedLocationNode) && location.displacement() < this.target().implicitNullCheckLimit; - } - protected CallingConvention createCallingConvention() { return frameMap.registerConfig.getCallingConvention(JavaCallee, method.getSignature().getReturnType(null), MetaUtil.signatureToTypes(method), target, false); } @@ -483,7 +467,7 @@ } } - append(new ParametersOp(params)); + emitIncomingValues(params); for (LocalNode local : graph.getNodes(LocalNode.class)) { Value param = params[local.index()]; @@ -492,6 +476,10 @@ } } + public void emitIncomingValues(Value[] params) { + append(new ParametersOp(params)); + } + /** * Increases the number of currently locked monitors and makes sure that a lock data slot is * available for the new lock. @@ -527,7 +515,7 @@ Value operand = Value.ILLEGAL; if (x.result() != null) { operand = resultOperandFor(x.result().kind()); - emitMove(operand(x.result()), operand); + emitMove(operand, operand(x.result())); } emitReturn(operand); } @@ -558,12 +546,12 @@ for (PhiNode phi : merge.phis()) { if (phi.type() == PhiType.Value) { ValueNode curVal = phi.valueAt(pred); - resolver.move(operand(curVal), operandForPhi(phi)); + resolver.move(operandForPhi(phi), operand(curVal)); } } resolver.dispose(); - append(new JumpOp(getLIRBlock(merge), null)); + append(new JumpOp(getLIRBlock(merge))); } private Value operandForPhi(PhiNode phi) { @@ -581,82 +569,46 @@ @Override public void emitIf(IfNode x) { - emitBranch(x.condition(), getLIRBlock(x.trueSuccessor()), getLIRBlock(x.falseSuccessor()), null); + emitBranch(x.condition(), getLIRBlock(x.trueSuccessor()), getLIRBlock(x.falseSuccessor())); } - @Override - public void emitGuardCheck(LogicNode comp, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) { - if (comp instanceof IsNullNode && negated) { - emitNullCheckGuard(((IsNullNode) comp).object()); - } else if (comp instanceof LogicConstantNode && ((LogicConstantNode) comp).getValue() != negated) { - // True constant, nothing to emit. - // False constants are handled within emitBranch. - } else { - // Fall back to a normal branch. - LIRFrameState info = state(); - LabelRef stubEntry = createDeoptStub(action, deoptReason, info, comp); - if (negated) { - emitBranch(comp, stubEntry, null, info); - } else { - emitBranch(comp, null, stubEntry, info); - } - } - } - - protected abstract void emitNullCheckGuard(ValueNode object); - - public void emitBranch(LogicNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRFrameState info) { + public void emitBranch(LogicNode node, LabelRef trueSuccessor, LabelRef falseSuccessor) { if (node instanceof IsNullNode) { - emitNullCheckBranch((IsNullNode) node, trueSuccessor, falseSuccessor, info); + emitNullCheckBranch((IsNullNode) node, trueSuccessor, falseSuccessor); } else if (node instanceof CompareNode) { - emitCompareBranch((CompareNode) node, trueSuccessor, falseSuccessor, info); + emitCompareBranch((CompareNode) node, trueSuccessor, falseSuccessor); } else if (node instanceof LogicConstantNode) { - emitConstantBranch(((LogicConstantNode) node).getValue(), trueSuccessor, falseSuccessor, info); + emitConstantBranch(((LogicConstantNode) node).getValue(), trueSuccessor, falseSuccessor); } else if (node instanceof IntegerTestNode) { - emitIntegerTestBranch((IntegerTestNode) node, trueSuccessor, falseSuccessor, info); + emitIntegerTestBranch((IntegerTestNode) node, trueSuccessor, falseSuccessor); } else { throw GraalInternalError.unimplemented(node.toString()); } } - private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRFrameState info) { - if (falseSuccessor != null) { - emitCompareBranch(operand(node.object()), Constant.NULL_OBJECT, Condition.NE, false, falseSuccessor, info); - if (trueSuccessor != null) { - emitJump(trueSuccessor, null); - } - } else { - emitCompareBranch(operand(node.object()), Constant.NULL_OBJECT, Condition.EQ, false, trueSuccessor, info); - } + private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor) { + emitCompareBranch(operand(node.object()), Constant.NULL_OBJECT, Condition.NE, false, falseSuccessor); + emitJump(trueSuccessor); + } + + public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock) { + emitCompareBranch(operand(compare.x()), operand(compare.y()), compare.condition().negate(), !compare.unorderedIsTrue(), falseSuccessorBlock); + emitJump(trueSuccessorBlock); } - public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock, LIRFrameState info) { - if (falseSuccessorBlock != null) { - emitCompareBranch(operand(compare.x()), operand(compare.y()), compare.condition().negate(), !compare.unorderedIsTrue(), falseSuccessorBlock, info); - if (trueSuccessorBlock != null) { - emitJump(trueSuccessorBlock, null); - } - } else { - emitCompareBranch(operand(compare.x()), operand(compare.y()), compare.condition(), compare.unorderedIsTrue(), trueSuccessorBlock, info); - } + public void emitOverflowCheckBranch(LabelRef noOverflowBlock, LabelRef overflowBlock) { + emitOverflowCheckBranch(overflowBlock, false); + emitJump(noOverflowBlock); } - public void emitIntegerTestBranch(IntegerTestNode test, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock, LIRFrameState info) { - if (falseSuccessorBlock != null) { - emitIntegerTestBranch(operand(test.x()), operand(test.y()), true, falseSuccessorBlock, info); - if (trueSuccessorBlock != null) { - emitJump(trueSuccessorBlock, null); - } - } else { - emitIntegerTestBranch(operand(test.x()), operand(test.y()), false, trueSuccessorBlock, info); - } + public void emitIntegerTestBranch(IntegerTestNode test, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock) { + emitIntegerTestBranch(operand(test.x()), operand(test.y()), true, falseSuccessorBlock); + emitJump(trueSuccessorBlock); } - public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock, LIRFrameState info) { + public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock) { LabelRef block = value ? trueSuccessorBlock : falseSuccessorBlock; - if (block != null) { - emitJump(block, info); - } + emitJump(block); } @Override @@ -683,11 +635,13 @@ } } - public abstract void emitJump(LabelRef label, LIRFrameState info); + public abstract void emitJump(LabelRef label); + + public abstract void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef label); - public abstract void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef label, LIRFrameState info); + public abstract void emitOverflowCheckBranch(LabelRef label, boolean negated); - public abstract void emitIntegerTestBranch(Value left, Value right, boolean negated, LabelRef label, LIRFrameState info); + public abstract void emitIntegerTestBranch(Value left, Value right, boolean negated, LabelRef label); public abstract Variable emitConditionalMove(Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue); @@ -703,7 +657,7 @@ LIRFrameState callState = null; if (x.stateAfter() != null) { - callState = stateFor(x.stateDuring(), x instanceof InvokeWithExceptionNode ? getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge()) : null); + callState = stateForWithExceptionEdge(x.stateDuring(), null, x instanceof InvokeWithExceptionNode ? getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge()) : null); } Value result = cc.getReturn(); @@ -725,9 +679,9 @@ protected abstract void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState); - protected abstract void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, Value targetAddress, LIRFrameState info); + protected abstract void emitCall(RuntimeCallTarget callTarget, Value result, Value[] arguments, Value[] temps, LIRFrameState info); - private static Value toStackKind(Value value) { + protected static Value toStackKind(Value value) { if (value.getKind().getStackKind() != value.getKind()) { // We only have stack-kinds in the LIR, so convert the operand kind for values from the // calling convention. @@ -749,7 +703,7 @@ for (ValueNode arg : arguments) { if (arg != null) { Value operand = toStackKind(cc.getArgument(j)); - emitMove(operand(arg), operand); + emitMove(operand, operand(arg)); result[j] = operand; j++; } else { @@ -759,8 +713,6 @@ return result; } - protected abstract LabelRef createDeoptStub(DeoptimizationAction action, DeoptimizationReason reason, LIRFrameState info, Object deoptInfo); - @Override public Variable emitCall(RuntimeCallTarget callTarget, CallingConvention cc, boolean canTrap, Value... args) { LIRFrameState info = canTrap ? state() : null; @@ -772,10 +724,10 @@ for (int i = 0; i < args.length; i++) { Value arg = args[i]; Value loc = cc.getArgument(i); - emitMove(arg, loc); + emitMove(loc, arg); argLocations[i] = loc; } - emitCall(callTarget, cc.getReturn(), argLocations, cc.getTemporaries(), Constant.forLong(0), info); + emitCall(callTarget, cc.getReturn(), argLocations, cc.getTemporaries(), info); if (isLegal(cc.getReturn())) { return emitMove(cc.getReturn()); @@ -805,12 +757,12 @@ 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); + info = stateFor(stateBeforeReturn, null); } else { info = state(); } - emitCall(call, resultOperand, args, cc.getTemporaries(), Constant.forLong(0), info); + emitCall(call, resultOperand, args, cc.getTemporaries(), info); if (isLegal(resultOperand)) { setResult(x, emitMove(resultOperand)); @@ -829,7 +781,7 @@ public void emitSwitch(SwitchNode x) { int keyCount = x.keyCount(); if (keyCount == 0) { - emitJump(getLIRBlock(x.defaultSuccessor()), null); + emitJump(getLIRBlock(x.defaultSuccessor())); } else { Variable value = load(operand(x.value())); LabelRef defaultTarget = x.defaultSuccessor() == null ? null : getLIRBlock(x.defaultSuccessor()); @@ -841,7 +793,7 @@ long valueRange = x.keyAt(keyCount - 1).asLong() - x.keyAt(0).asLong() + 1; int switchRangeCount = switchRangeCount(x); if (switchRangeCount == 0) { - emitJump(getLIRBlock(x.defaultSuccessor()), null); + emitJump(getLIRBlock(x.defaultSuccessor())); } else if (switchRangeCount >= GraalOptions.MinimumJumpTableSize && keyCount / (double) valueRange >= GraalOptions.MinTableSwitchDensity) { int minValue = x.keyAt(0).asInt(); assert valueRange < Integer.MAX_VALUE; diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java Thu Mar 21 14:11:13 2013 +0100 @@ -131,7 +131,7 @@ PhiResolverNode node = variableOperands.get(i); if (!node.visited) { loop = null; - move(null, node); + move(node, null); node.startNode = true; assert isIllegal(temp) : "moveTempTo() call missing"; } @@ -141,12 +141,12 @@ for (int i = otherOperands.size() - 1; i >= 0; i--) { PhiResolverNode node = otherOperands.get(i); for (int j = node.destinations.size() - 1; j >= 0; j--) { - emitMove(node.operand, node.destinations.get(j).operand); + emitMove(node.destinations.get(j).operand, node.operand); } } } - public void move(Value src, Value dest) { + public void move(Value dest, Value src) { assert isVariable(dest) : "destination must be virtual"; // tty.print("move "); src.print(); tty.print(" to "); dest.print(); tty.cr(); assert isLegal(src) : "source for phi move is illegal"; @@ -184,24 +184,24 @@ return createNode(opr, false); } - private void emitMove(Value src, Value dest) { + private void emitMove(Value dest, Value src) { assert isLegal(src); assert isLegal(dest); - gen.emitMove(src, dest); + gen.emitMove(dest, src); } // Traverse assignment graph in depth first order and generate moves in post order // ie. two assignments: b := c, a := b start with node c: - // Call graph: move(NULL, c) -> move(c, b) -> move(b, a) + // Call graph: move(c, NULL) -> move(b, c) -> move(a, b) // Generates moves in this order: move b to a and move c to b // ie. cycle a := b, b := a start with node a - // Call graph: move(NULL, a) -> move(a, b) -> move(b, a) + // Call graph: move(a, NULL) -> move(b, a) -> move(a, b) // Generates moves in this order: move b to temp, move a to b, move temp to a - private void move(PhiResolverNode src, PhiResolverNode dest) { + private void move(PhiResolverNode dest, PhiResolverNode src) { if (!dest.visited) { dest.visited = true; for (int i = dest.destinations.size() - 1; i >= 0; i--) { - move(dest, dest.destinations.get(i)); + move(dest.destinations.get(i), dest); } } else if (!dest.startNode) { // cycle in graph detected @@ -216,7 +216,7 @@ moveTempTo(dest.operand); dest.assigned = true; } else if (src != null) { - emitMove(src.operand, dest.operand); + emitMove(dest.operand, src.operand); dest.assigned = true; } } @@ -224,14 +224,14 @@ private void moveTempTo(Value dest) { assert isLegal(temp); - emitMove(temp, dest); + emitMove(dest, temp); temp = ILLEGAL; } private void moveToTemp(Value src) { assert isIllegal(temp); temp = gen.newVariable(src.getKind()); - emitMove(src, temp); + emitMove(temp, src); } private PhiResolverNode sourceNode(Value opr) { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Thu Mar 21 14:11:13 2013 +0100 @@ -28,7 +28,6 @@ import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.phases.*; /** * The {@code Backend} class represents a compiler backend for Graal. @@ -47,46 +46,19 @@ return runtime; } - public FrameMap newFrameMap(RegisterConfig registerConfig) { - return new FrameMap(runtime, target, registerConfig); + public FrameMap newFrameMap() { + return new FrameMap(runtime, target, runtime.lookupRegisterConfig()); } public abstract LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, ResolvedJavaMethod method, LIR lir); - public abstract TargetMethodAssembler newAssembler(FrameMap frameMap, LIR lir); - - /** - * Emits code to do stack overflow checking. - * - * @param afterFrameInit specifies if the stack pointer has already been adjusted to allocate - * the current frame - */ - protected static void emitStackOverflowCheck(TargetMethodAssembler tasm, boolean afterFrameInit) { - if (GraalOptions.StackShadowPages > 0) { - int frameSize = tasm.frameMap.frameSize(); - if (frameSize > 0) { - int lastFramePage = frameSize / tasm.target.pageSize; - // emit multiple stack bangs for methods with frames larger than a page - for (int i = 0; i <= lastFramePage; i++) { - int disp = (i + GraalOptions.StackShadowPages) * tasm.target.pageSize; - if (afterFrameInit) { - disp -= frameSize; - } - tasm.blockComment("[stack overflow check]"); - tasm.asm.bangStack(disp); - } - } - } - } + public abstract TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult); /** * Emits the code for a given method. This includes any architecture/runtime specific * prefix/suffix. A prefix typically contains the code for setting up the frame, spilling * callee-save registers, stack overflow checking, handling multiple entry points etc. A suffix * may contain out-of-line stubs and method end guard instructions. - * - * @param method the method associated with {@code lir} - * @param lir the LIR of {@code method} */ - public abstract void emitCode(TargetMethodAssembler tasm, ResolvedJavaMethod method, LIR lir); + public abstract void emitCode(TargetMethodAssembler tasm, ResolvedJavaMethod method, LIRGenerator lirGen); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Thu Mar 21 14:11:13 2013 +0100 @@ -324,10 +324,8 @@ }; } - private static class PlaceHolderNode extends Node { - } - - private static final PlaceHolderNode PLACE_HOLDER = new PlaceHolderNode(); + private static final Node PLACE_HOLDER = new Node() { + }; private class TypedNodeIterator implements Iterator { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java Thu Mar 21 14:11:13 2013 +0100 @@ -72,6 +72,10 @@ assert !isNew(node) : "this node was added to the graph after creating the node map : " + node; } + public void clear() { + Arrays.fill(values, null); + } + public Iterable> entries() { return new Iterable>() { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/AMD64HotSpotFrameOmissionTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -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.hotspot.amd64.test; + +import static com.oracle.graal.amd64.AMD64.*; + +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.api.runtime.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.compiler.test.*; + +/** + * Ensures that frame omission works in cases where it is expected to. + */ +public class AMD64HotSpotFrameOmissionTest extends GraalCompilerTest { + + interface CodeGenerator { + + void generateCode(AMD64Assembler asm); + } + + public static void test1snippet() { + return; + } + + @Test + public void test1() { + testHelper("test1snippet", new CodeGenerator() { + + @Override + public void generateCode(AMD64Assembler asm) { + asm.ret(0); + } + }); + } + + public static int test2snippet(int x) { + return x + 5; + } + + @Test + public void test2() { + testHelper("test2snippet", new CodeGenerator() { + + @Override + public void generateCode(AMD64Assembler asm) { + asm.addl(rsi, 5); + asm.movl(rax, rsi); + asm.ret(0); + } + }); + } + + public static long test3snippet(long x) { + return 1 + x; + } + + @Test + public void test3() { + testHelper("test3snippet", new CodeGenerator() { + + @Override + public void generateCode(AMD64Assembler asm) { + asm.addq(rsi, 1); + asm.movq(rax, rsi); + asm.ret(0); + } + }); + } + + private void testHelper(String name, CodeGenerator gen) { + Method method = getMethod(name); + ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(method); + InstalledCode installedCode = getCode(javaMethod, parse(method)); + + CodeCacheProvider codeCache = Graal.getRequiredCapability(CodeCacheProvider.class); + TargetDescription target = codeCache.getTarget(); + RegisterConfig registerConfig = codeCache.lookupRegisterConfig(); + AMD64Assembler asm = new AMD64Assembler(target, registerConfig); + + gen.generateCode(asm); + byte[] expectedCode = asm.codeBuffer.close(true); + + // Only compare up to expectedCode.length bytes to ignore + // padding instructions adding during code installation + byte[] actualCode = Arrays.copyOf(installedCode.getCode(), expectedCode.length); + + Assert.assertArrayEquals(expectedCode, actualCode); + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,57 @@ +/* + * 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.amd64; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.*; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; + +@Opcode("DEOPT") +final class AMD64DeoptimizeOp extends AMD64LIRInstruction { + + public static final Descriptor DEOPTIMIZE = new Descriptor("deoptimize", true, void.class); + + private DeoptimizationAction action; + private DeoptimizationReason reason; + @State private LIRFrameState info; + + AMD64DeoptimizeOp(DeoptimizationAction action, DeoptimizationReason reason, LIRFrameState info) { + this.action = action; + this.reason = reason; + this.info = info; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + HotSpotGraalRuntime runtime = HotSpotGraalRuntime.getInstance(); + Register thread = runtime.getRuntime().threadRegister(); + masm.movl(new AMD64Address(thread, runtime.getConfig().pendingDeoptimizationOffset), tasm.runtime.encodeDeoptActionAndReason(action, reason)); + AMD64Call.directCall(tasm, masm, tasm.runtime.lookupRuntimeCall(DEOPTIMIZE), null, false, info); + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DirectCallOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DirectCallOp.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +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.amd64; - -import static com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind.*; - -import com.oracle.graal.amd64.*; -import com.oracle.graal.api.code.CompilationResult.Mark; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.hotspot.bridge.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.LIRInstruction.Opcode; -import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.amd64.AMD64Call.DirectCallOp; -import com.oracle.graal.lir.asm.*; -import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; - -/** - * A direct call that complies with the conventions for such calls in HotSpot. In particular, for - * calls using an inline cache, a MOVE instruction is emitted just prior to the aligned direct call. - * This instruction (which moves 0L in RAX) is patched by the C++ Graal code to replace the 0L - * constant with Universe::non_oop_word(), a special sentinel used for the initial value of the - * Klass in an inline cache. - *

- * For non-inline cache calls (i.e., INVOKESTATIC and INVOKESPECIAL), a static call stub is emitted. - * Initially, these calls go to the global static call resolution stub (i.e., - * SharedRuntime::get_resolve_static_call_stub()). Resolution will link the call to a compiled - * version of the callee if available otherwise to the interpreter. The interpreter expects to find - * the Method* for the callee in RBX. To achieve this, the static call is linked to a static call - * stub which initializes RBX and jumps to the interpreter. This pattern is shown below: - * - *

- *       call L1
- *       nop
- * 
- *       ...
- * 
- *   L1: mov rbx [Method*]
- *       jmp [interpreter entry point]
- * 
- */ -@Opcode("CALL_DIRECT") -final class AMD64DirectCallOp extends DirectCallOp { - - /** - * The mark emitted at the position of the direct call instruction. This is only recorded for - * calls that have an associated static call stub (i.e., - * {@code invokeKind == Static || invokeKind == Special}). - */ - Mark callsiteMark; - - private final InvokeKind invokeKind; - - AMD64DirectCallOp(Object target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, LIR lir) { - super(target, result, parameters, temps, state); - this.invokeKind = invokeKind; - - if (invokeKind == Static || invokeKind == Special) { - lir.stubs.add(new AMD64Code() { - - public String description() { - return "static call stub for Invoke" + AMD64DirectCallOp.this.invokeKind; - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - assert callsiteMark != null : "static call site has not yet been emitted"; - tasm.recordMark(Marks.MARK_STATIC_CALL_STUB, callsiteMark); - masm.movq(AMD64.rbx, 0L); - int pos = masm.codeBuffer.position(); - // Create a jump-to-self as expected by CompiledStaticCall::set_to_interpreted() - // in compiledIC.cpp - masm.jmp(pos, true); - } - }); - } - - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - if (invokeKind == Static || invokeKind == Special) { - tasm.recordMark(invokeKind == Static ? Marks.MARK_INVOKESTATIC : Marks.MARK_INVOKESPECIAL); - } else { - assert invokeKind == Virtual || invokeKind == Interface; - // The mark for an invocation that uses an inline cache must be placed at the - // instruction - // that loads the Klass from the inline cache so that the C++ code can find it - // and replace the inline 0L value with Universe::non_oop_word() - tasm.recordMark(invokeKind == Virtual ? Marks.MARK_INVOKEVIRTUAL : Marks.MARK_INVOKEINTERFACE); - AMD64Move.move(tasm, masm, AMD64.rax.asValue(Kind.Long), Constant.LONG_0); - } - - emitAlignmentForDirectCall(tasm, masm); - - if (invokeKind == Static || invokeKind == Special) { - callsiteMark = tasm.recordMark(null); - } - - AMD64Call.directCall(tasm, masm, callTarget, state); - } -} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Thu Mar 21 14:11:13 2013 +0100 @@ -29,25 +29,23 @@ import java.lang.reflect.*; +import sun.misc.*; + import com.oracle.graal.amd64.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; +import com.oracle.graal.asm.amd64.*; import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag; -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.compiler.amd64.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.meta.*; -import com.oracle.graal.hotspot.nodes.*; -import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.amd64.*; -import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp; import com.oracle.graal.lir.asm.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.*; /** @@ -55,110 +53,43 @@ */ public class AMD64HotSpotBackend extends HotSpotBackend { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + public static final Descriptor EXCEPTION_HANDLER = new Descriptor("exceptionHandler", true, void.class); + public static final Descriptor DEOPT_HANDLER = new Descriptor("deoptHandler", true, void.class); + public static final Descriptor IC_MISS_HANDLER = new Descriptor("icMissHandler", true, void.class); + public AMD64HotSpotBackend(HotSpotRuntime runtime, TargetDescription target) { super(runtime, target); } @Override public LIRGenerator newLIRGenerator(StructuredGraph graph, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) { - return new HotSpotAMD64LIRGenerator(graph, runtime(), target, frameMap, method, lir); + return new AMD64HotSpotLIRGenerator(graph, runtime(), target, frameMap, method, lir); } - static final class HotSpotAMD64LIRGenerator extends AMD64LIRGenerator implements HotSpotLIRGenerator { - - private HotSpotRuntime runtime() { - return (HotSpotRuntime) runtime; - } - - private HotSpotAMD64LIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) { - super(graph, runtime, target, frameMap, method, lir); - } - - @Override - protected boolean needOnlyOopMaps() { - // Stubs only need oop maps - return runtime().asStub(method) != null; - } - - @Override - protected CallingConvention createCallingConvention() { - Stub stub = runtime().asStub(method); - if (stub != null) { - return stub.getLinkage().getCallingConvention(); - } - - if (graph.getEntryBCI() == StructuredGraph.INVOCATION_ENTRY_BCI) { - return super.createCallingConvention(); - } else { - return frameMap.registerConfig.getCallingConvention(JavaCallee, method.getSignature().getReturnType(null), new JavaType[]{runtime.lookupJavaType(long.class)}, target, false); - } - } - - @Override - public void visitSafepointNode(SafepointNode i) { - LIRFrameState info = state(); - append(new AMD64SafepointOp(info, runtime().config)); - } - - @Override - public void visitExceptionObject(ExceptionObjectNode x) { - HotSpotVMConfig config = runtime().config; - RegisterValue thread = runtime().threadRegister().asValue(); - Address exceptionAddress = new Address(Kind.Object, thread, config.threadExceptionOopOffset); - Address pcAddress = new Address(Kind.Long, thread, config.threadExceptionPcOffset); - Value exception = emitLoad(exceptionAddress, false); - emitStore(exceptionAddress, Constant.NULL_OBJECT, false); - emitStore(pcAddress, Constant.LONG_0, false); - setResult(x, exception); - } + /** + * Emits code to do stack overflow checking. + * + * @param afterFrameInit specifies if the stack pointer has already been adjusted to allocate + * the current frame + */ + protected static void emitStackOverflowCheck(TargetMethodAssembler tasm, boolean afterFrameInit) { + if (GraalOptions.StackShadowPages > 0) { - @SuppressWarnings("hiding") - @Override - public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) { - Kind kind = x.newValue().kind(); - assert kind == x.expectedValue().kind(); - - Value expected = loadNonConst(operand(x.expectedValue())); - Variable newVal = load(operand(x.newValue())); - - int disp = 0; - Address address; - Value index = operand(x.offset()); - if (ValueUtil.isConstant(index) && NumUtil.isInt(ValueUtil.asConstant(index).asLong() + disp)) { - assert !runtime.needsDataPatch(asConstant(index)); - disp += (int) ValueUtil.asConstant(index).asLong(); - address = new Address(kind, load(operand(x.object())), disp); - } else { - address = new Address(kind, load(operand(x.object())), load(index), Address.Scale.Times1, disp); + AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm; + int frameSize = tasm.frameMap.frameSize(); + if (frameSize > 0) { + int lastFramePage = frameSize / unsafe.pageSize(); + // emit multiple stack bangs for methods with frames larger than a page + for (int i = 0; i <= lastFramePage; i++) { + int disp = (i + GraalOptions.StackShadowPages) * unsafe.pageSize(); + if (afterFrameInit) { + disp -= frameSize; + } + tasm.blockComment("[stack overflow check]"); + asm.movq(new AMD64Address(rsp, -disp), AMD64.rax); + } } - - RegisterValue rax = AMD64.rax.asValue(kind); - emitMove(expected, rax); - append(new CompareAndSwapOp(rax, address, rax, newVal)); - - Variable result = newVariable(x.kind()); - emitMove(rax, result); - setResult(x, result); - } - - @Override - public void emitTailcall(Value[] args, Value address) { - append(new AMD64TailcallOp(args, address)); - - } - - @Override - protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { - append(new AMD64DirectCallOp(callTarget.target(), result, parameters, temps, callState, ((HotSpotDirectCallTargetNode) callTarget).invokeKind(), lir)); - } - - @Override - protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { - Value metaspaceMethod = AMD64.rbx.asValue(); - emitMove(operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()), metaspaceMethod); - Value targetAddress = AMD64.rax.asValue(); - emitMove(operand(callTarget.computedAddress()), targetAddress); - append(new AMD64IndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState)); } } @@ -171,13 +102,11 @@ AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm; emitStackOverflowCheck(tasm, false); - asm.push(rbp); - asm.movq(rbp, rsp); - asm.decrementq(rsp, frameSize - 8); // account for the push of RBP above + asm.decrementq(rsp, frameSize); if (GraalOptions.ZapStackOnMethodEntry) { final int intSize = 4; for (int i = 0; i < frameSize / intSize; ++i) { - asm.movl(new Address(Kind.Int, rsp.asValue(), i * intSize), 0xC1C1C1C1); + asm.movl(new AMD64Address(rsp, i * intSize), 0xC1C1C1C1); } } CalleeSaveLayout csl = frameMap.registerConfig.getCalleeSaveLayout(); @@ -193,61 +122,43 @@ int frameSize = tasm.frameMap.frameSize(); AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm; CalleeSaveLayout csl = tasm.frameMap.registerConfig.getCalleeSaveLayout(); - RegisterConfig regConfig = tasm.frameMap.registerConfig; if (csl != null && csl.size != 0) { - tasm.targetMethod.setRegisterRestoreEpilogueOffset(asm.codeBuffer.position()); + tasm.compilationResult.setRegisterRestoreEpilogueOffset(asm.codeBuffer.position()); // saved all registers, restore all registers int frameToCSA = tasm.frameMap.offsetToCalleeSaveArea(); asm.restore(csl, frameToCSA); } - asm.incrementq(rsp, frameSize - 8); // account for the pop of RBP below - asm.pop(rbp); - - if (GraalOptions.GenSafepoints) { - HotSpotVMConfig config = runtime().config; - - // If at the return point, then the frame has already been popped - // so deoptimization cannot be performed here. The HotSpot runtime - // detects this case - see the definition of frame::should_be_deoptimized() - - Register scratch = regConfig.getScratchRegister(); - int offset = SafepointPollOffset % target.pageSize; - if (config.isPollingPageFar) { - asm.movq(scratch, config.safepointPollingAddress + offset); - tasm.recordMark(Marks.MARK_POLL_RETURN_FAR); - asm.movq(scratch, new Address(tasm.target.wordKind, scratch.asValue())); - } else { - tasm.recordMark(Marks.MARK_POLL_RETURN_NEAR); - // 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, new Address(tasm.target.wordKind, rip.asValue(), offset)); - } - } + asm.incrementq(rsp, frameSize); } } @Override - public TargetMethodAssembler newAssembler(FrameMap frameMap, LIR lir) { + public TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult) { // Omit the frame if the method: // - has no spill slots or other slots allocated during register allocation // - has no callee-saved registers // - has no incoming arguments passed on the stack // - has no instructions with debug info - boolean omitFrame = GraalOptions.CanOmitFrame && frameMap.frameSize() == frameMap.initialFrameSize && frameMap.registerConfig.getCalleeSaveLayout().registers.length == 0 && - !lir.hasArgInCallerFrame() && !lir.hasDebugInfo(); + AMD64HotSpotLIRGenerator gen = (AMD64HotSpotLIRGenerator) lirGen; + FrameMap frameMap = gen.frameMap; + LIR lir = gen.lir; + boolean omitFrame = CanOmitFrame && !frameMap.frameNeedsAllocating() && !lir.hasArgInCallerFrame(); AbstractAssembler masm = new AMD64MacroAssembler(target, frameMap.registerConfig); HotSpotFrameContext frameContext = omitFrame ? null : new HotSpotFrameContext(); - TargetMethodAssembler tasm = new TargetMethodAssembler(target, runtime(), frameMap, masm, frameContext, lir.stubs); + TargetMethodAssembler tasm = new TargetMethodAssembler(target, runtime(), frameMap, masm, frameContext, compilationResult); tasm.setFrameSize(frameMap.frameSize()); - tasm.targetMethod.setCustomStackAreaOffset(frameMap.offsetToCustomArea()); + StackSlot deoptimizationRescueSlot = gen.deoptimizationRescueSlot; + if (deoptimizationRescueSlot != null) { + tasm.compilationResult.setCustomStackAreaOffset(frameMap.offsetForStackSlot(deoptimizationRescueSlot)); + } return tasm; } @Override - public void emitCode(TargetMethodAssembler tasm, ResolvedJavaMethod method, LIR lir) { + public void emitCode(TargetMethodAssembler tasm, ResolvedJavaMethod method, LIRGenerator lirGen) { AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm; FrameMap frameMap = tasm.frameMap; RegisterConfig regConfig = frameMap.registerConfig; @@ -263,10 +174,10 @@ Register inlineCacheKlass = rax; // see definition of IC_Klass in // c1_LIRAssembler_x86.cpp Register receiver = asRegister(cc.getArgument(0)); - Address src = new Address(target.wordKind, receiver.asValue(), config.hubOffset); + AMD64Address src = new AMD64Address(receiver, config.hubOffset); asm.cmpq(inlineCacheKlass, src); - asm.jcc(ConditionFlag.notEqual, unverifiedStub); + asm.jcc(ConditionFlag.NotEqual, unverifiedStub); } asm.align(config.codeEntryAlignment); @@ -274,31 +185,23 @@ tasm.recordMark(Marks.MARK_VERIFIED_ENTRY); // Emit code for the LIR - lir.emitCode(tasm); + lirGen.lir.emitCode(tasm); boolean frameOmitted = tasm.frameContext == null; if (!frameOmitted) { tasm.recordMark(Marks.MARK_EXCEPTION_HANDLER_ENTRY); - AMD64Call.directCall(tasm, asm, config.handleExceptionStub, null); - AMD64Call.shouldNotReachHere(tasm, asm); - + AMD64Call.directCall(tasm, asm, runtime().lookupRuntimeCall(EXCEPTION_HANDLER), null, false, null); tasm.recordMark(Marks.MARK_DEOPT_HANDLER_ENTRY); - AMD64Call.directCall(tasm, asm, config.handleDeoptStub, null); - AMD64Call.shouldNotReachHere(tasm, asm); + AMD64Call.directCall(tasm, asm, runtime().lookupRuntimeCall(DEOPT_HANDLER), null, false, null); } else { // No need to emit the stubs for entries back into the method since // it has no calls that can cause such "return" entries - assert !frameMap.accessesCallerFrame(); + assert !frameMap.accessesCallerFrame() : method; } if (unverifiedStub != null) { asm.bind(unverifiedStub); - AMD64Call.directJmp(tasm, asm, config.inlineCacheMissStub); + AMD64Call.directJmp(tasm, asm, runtime().lookupRuntimeCall(IC_MISS_HANDLER)); } - - for (int i = 0; i < GraalOptions.MethodEndBreakpointGuards; ++i) { - asm.int3(); - } - } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,45 @@ +/* + * 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.amd64; + +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.amd64.*; + +/** + * Superclass for operations that use the value of RBP saved in a method's prologue. + */ +abstract class AMD64HotSpotEpilogueOp extends AMD64LIRInstruction { + + /** + * The type of location (i.e., stack or register) in which RBP is saved is not known until + * initial LIR generation is finished. Until then, we use a placeholder variable so that LIR + * verification is successful. + */ + private static final Variable PLACEHOLDER = new Variable(Kind.Long, Integer.MAX_VALUE, Register.RegisterFlag.CPU); + + @Use({REG, STACK}) protected AllocatableValue savedRbp = PLACEHOLDER; +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime.java Thu Mar 21 14:11:13 2013 +0100 @@ -47,11 +47,9 @@ @Override protected TargetDescription createTarget() { - final int wordSize = 8; final int stackFrameAlignment = 16; - final int stackBias = 0; final int implicitNullCheckLimit = 4096; - return new TargetDescription(new AMD64(), true, stackFrameAlignment, stackBias, implicitNullCheckLimit, config.vmPageSize, wordSize, true, true); + return new TargetDescription(new AMD64(), true, stackFrameAlignment, implicitNullCheckLimit, true); } @Override diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,255 @@ +/* + * 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.amd64; + +import static com.oracle.graal.amd64.AMD64.*; +import static com.oracle.graal.api.code.CallingConvention.Type.*; +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.hotspot.amd64.AMD64HotSpotUnwindOp.*; + +import java.util.*; + +import com.oracle.graal.amd64.*; +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.compiler.amd64.*; +import com.oracle.graal.hotspot.*; +import com.oracle.graal.hotspot.meta.*; +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.amd64.*; +import com.oracle.graal.lir.amd64.AMD64Move.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.*; + +/** + * LIR generator specialized for AMD64 HotSpot. + */ +final class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSpotLIRGenerator { + + private HotSpotRuntime runtime() { + return (HotSpotRuntime) runtime; + } + + AMD64HotSpotLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, ResolvedJavaMethod method, LIR lir) { + super(graph, runtime, target, frameMap, method, lir); + } + + /** + * The slot reserved for storing the original return address when a frame is marked for + * deoptimization. The return address slot in the callee is overwritten with the address of a + * deoptimization stub. + */ + StackSlot deoptimizationRescueSlot; + + /** + * The position at which the instruction for saving RBP should be inserted. + */ + Block saveRbpBlock; + int saveRbpIndex; + + /** + * The slot reserved for saving RBP. + */ + StackSlot rbpSlot; + + /** + * List of epilogue operations that need to restore RBP. + */ + List epilogueOps = new ArrayList<>(2); + + @Override + protected void emitPrologue() { + + CallingConvention incomingArguments = createCallingConvention(); + + RegisterValue rbpParam = rbp.asValue(Kind.Long); + Value[] params = new Value[incomingArguments.getArgumentCount() + 1]; + for (int i = 0; i < params.length - 1; i++) { + params[i] = toStackKind(incomingArguments.getArgument(i)); + if (isStackSlot(params[i])) { + StackSlot slot = ValueUtil.asStackSlot(params[i]); + if (slot.isInCallerFrame() && !lir.hasArgInCallerFrame()) { + lir.setHasArgInCallerFrame(); + } + } + } + params[params.length - 1] = rbpParam; + + ParametersOp paramsOp = new ParametersOp(params); + append(paramsOp); + saveRbpBlock = currentBlock; + saveRbpIndex = lir.lir(saveRbpBlock).size(); + append(paramsOp); // placeholder + rbpSlot = frameMap.allocateSpillSlot(Kind.Long); + assert rbpSlot.getRawOffset() == -16 : rbpSlot.getRawOffset(); + + for (LocalNode local : graph.getNodes(LocalNode.class)) { + Value param = params[local.index()]; + assert param.getKind() == local.kind().getStackKind(); + setResult(local, emitMove(param)); + } + } + + @Override + protected void emitReturn(Value input) { + AMD64HotSpotReturnOp op = new AMD64HotSpotReturnOp(input); + epilogueOps.add(op); + append(op); + } + + @Override + protected boolean needOnlyOopMaps() { + // Stubs only need oop maps + return runtime().asStub(method) != null; + } + + @Override + protected CallingConvention createCallingConvention() { + Stub stub = runtime().asStub(method); + if (stub != null) { + return stub.getLinkage().getCallingConvention(); + } + + if (graph.getEntryBCI() == StructuredGraph.INVOCATION_ENTRY_BCI) { + return super.createCallingConvention(); + } else { + return frameMap.registerConfig.getCallingConvention(JavaCallee, method.getSignature().getReturnType(null), new JavaType[]{runtime.lookupJavaType(long.class)}, target, false); + } + } + + @Override + public void visitSafepointNode(SafepointNode i) { + LIRFrameState info = state(); + 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) { + Kind kind = x.newValue().kind(); + assert kind == x.expectedValue().kind(); + + Value expected = loadNonConst(operand(x.expectedValue())); + Variable newVal = load(operand(x.newValue())); + + int disp = 0; + AMD64AddressValue address; + Value index = operand(x.offset()); + if (ValueUtil.isConstant(index) && NumUtil.isInt(ValueUtil.asConstant(index).asLong() + disp)) { + assert !runtime.needsDataPatch(asConstant(index)); + disp += (int) ValueUtil.asConstant(index).asLong(); + address = new AMD64AddressValue(kind, load(operand(x.object())), disp); + } else { + address = new AMD64AddressValue(kind, load(operand(x.object())), load(index), Scale.Times1, disp); + } + + RegisterValue rax = AMD64.rax.asValue(kind); + emitMove(rax, expected); + append(new CompareAndSwapOp(rax, address, rax, newVal)); + + Variable result = newVariable(x.kind()); + emitMove(result, rax); + setResult(x, result); + } + + @Override + public void emitTailcall(Value[] args, Value address) { + append(new AMD64TailcallOp(args, address)); + + } + + @Override + protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind(); + if (invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual) { + append(new AMD64HotspotDirectVirtualCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind)); + } else { + assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special; + HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.target(); + Constant metaspaceMethod = resolvedMethod.getMetaspaceMethodConstant(); + append(new AMD64HotspotDirectStaticCallOp(callTarget.target(), result, parameters, temps, callState, invokeKind, metaspaceMethod)); + } + } + + @Override + protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { + Value metaspaceMethod = AMD64.rbx.asValue(); + emitMove(metaspaceMethod, operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod())); + Value targetAddress = AMD64.rax.asValue(); + emitMove(targetAddress, operand(callTarget.computedAddress())); + append(new AMD64IndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod, targetAddress, callState)); + } + + @Override + public void emitUnwind(Value exception) { + RegisterValue exceptionParameter = EXCEPTION.asValue(); + emitMove(exceptionParameter, exception); + AMD64HotSpotUnwindOp op = new AMD64HotSpotUnwindOp(exceptionParameter); + epilogueOps.add(op); + append(op); + } + + @Override + public void emitDeoptimize(DeoptimizationAction action, DeoptimizationReason reason) { + append(new AMD64DeoptimizeOp(action, reason, state())); + } + + @Override + public void beforeRegisterAllocation() { + assert rbpSlot != null; + RegisterValue rbpParam = rbp.asValue(Kind.Long); + AllocatableValue savedRbp; + LIRInstruction saveRbp; + if (lir.hasDebugInfo()) { + savedRbp = rbpSlot; + deoptimizationRescueSlot = frameMap.allocateSpillSlot(Kind.Long); + } else { + frameMap.freeSpillSlot(rbpSlot); + savedRbp = newVariable(Kind.Long); + } + + for (AMD64HotSpotEpilogueOp op : epilogueOps) { + op.savedRbp = savedRbp; + } + + saveRbp = new MoveFromRegOp(savedRbp, rbpParam); + lir.lir(saveRbpBlock).set(saveRbpIndex, saveRbp); + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java Thu Mar 21 14:11:13 2013 +0100 @@ -33,16 +33,12 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; +import com.oracle.graal.phases.*; // @formatter:off public class AMD64HotSpotRegisterConfig implements RegisterConfig { - // be careful - the contents of this array are duplicated in graal_CodeInstaller.cpp - private final Register[] allocatable = { - rax, rbx, rcx, rdx, rsi, rdi, r8, r9, /* r10, */r11, r12, r13, r14, /*r15*/ - xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, - xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 - }; + private final Register[] allocatable = initAllocatable(); private final EnumMap categorized = Register.categorize(allocatable); @@ -69,6 +65,34 @@ private final CalleeSaveLayout csl; + private static Register findRegister(String name, Register[] all) { + for (Register reg : all) { + if (reg.name.equals(name)) { + return reg; + } + } + throw new IllegalArgumentException("register " + name + " is not allocatable"); + } + + private static Register[] initAllocatable() { + Register[] allocatable = { + rax, rbx, rcx, rdx, /*rsp,*/ rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, /*r15, */ + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + + if (GraalOptions.RegisterPressure != null) { + String[] names = GraalOptions.RegisterPressure.split(","); + Register[] regs = new Register[names.length]; + for (int i = 0; i < names.length; i++) { + regs[i] = findRegister(names[i], allocatable); + } + return regs; + } + + return allocatable; + } + public AMD64HotSpotRegisterConfig(HotSpotVMConfig config, boolean globalStubConfig) { if (config.windowsOs) { javaGeneralParameterRegisters = new Register[] {rdx, r8, r9, rdi, rsi, rcx}; @@ -87,12 +111,7 @@ }; csl = new CalleeSaveLayout(0, -1, 8, regs); } else { - // We reserve space for saving RBP but don't explicitly specify - // it as a callee save register since we explicitly do the saving - // with push and pop in HotSpotFrameContext - final int size = 8; - final Register[] regs = {}; - csl = new CalleeSaveLayout(0, size, 8, regs); + csl = null; } attributesMap = RegisterAttributes.createMap(this, AMD64.allRegisters); @@ -191,11 +210,6 @@ } @Override - public Register getScratchRegister() { - return r10; - } - - @Override public Register getFrameRegister() { return rsp; } @@ -209,8 +223,7 @@ String res = String.format( "Allocatable: " + Arrays.toString(getAllocatableRegisters()) + "%n" + "CallerSave: " + Arrays.toString(getCallerSaveRegisters()) + "%n" + - "CalleeSave: " + getCalleeSaveLayout() + "%n" + - "Scratch: " + getScratchRegister() + "%n"); + "CalleeSave: " + getCalleeSaveLayout() + "%n"); return res; } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,63 @@ +/* + * 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.amd64; + +import static com.oracle.graal.amd64.AMD64.*; +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.asm.*; + +/** + * Performs an unwind to throw an exception. + */ +@Opcode("RETURN") +final class AMD64HotSpotReturnOp extends AMD64HotSpotEpilogueOp { + + @Use({REG, ILLEGAL}) protected Value value; + + AMD64HotSpotReturnOp(Value value) { + this.value = value; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + if (isStackSlot(savedRbp)) { + // Restoring RBP from the stack must be done before the frame is removed + masm.movq(rbp, (AMD64Address) tasm.asAddress(savedRbp)); + } else { + Register framePointer = asRegister(savedRbp); + if (framePointer != rbp) { + masm.movq(rbp, framePointer); + } + } + if (tasm.frameContext != null) { + tasm.frameContext.leave(tasm); + } + masm.ret(0); + } +} diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java Thu Mar 21 14:11:13 2013 +0100 @@ -23,8 +23,9 @@ package com.oracle.graal.hotspot.amd64; import static com.oracle.graal.amd64.AMD64.*; -import static com.oracle.graal.compiler.amd64.AMD64DeoptimizationStub.*; import static com.oracle.graal.compiler.amd64.AMD64LIRGenerator.*; +import static com.oracle.graal.hotspot.amd64.AMD64DeoptimizeOp.*; +import static com.oracle.graal.hotspot.amd64.AMD64HotSpotUnwindOp.*; import static com.oracle.graal.hotspot.nodes.IdentityHashCodeStubCall.*; import static com.oracle.graal.hotspot.nodes.MonitorEnterStubCall.*; import static com.oracle.graal.hotspot.nodes.MonitorExitStubCall.*; @@ -42,12 +43,17 @@ import static com.oracle.graal.hotspot.snippets.AESCryptSubstitutions.EncryptBlockStubCall.*; import static com.oracle.graal.hotspot.snippets.CipherBlockChainingSubstitutions.DecryptAESCryptStubCall.*; import static com.oracle.graal.hotspot.snippets.CipherBlockChainingSubstitutions.EncryptAESCryptStubCall.*; -import static com.oracle.graal.lir.amd64.AMD64Call.*; 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.snippets.*; +import com.oracle.graal.snippets.amd64.*; public class AMD64HotSpotRuntime extends HotSpotRuntime { @@ -57,20 +63,15 @@ Kind word = graalRuntime.getTarget().wordKind; // @formatter:off + addRuntimeCall(UNWIND_EXCEPTION, config.unwindExceptionStub, + /* temps */ null, + /* ret */ ret(Kind.Void), + /* arg0: exception */ rax.asValue(Kind.Object)); addRuntimeCall(DEOPTIMIZE, config.deoptimizeStub, /* temps */ null, /* ret */ ret(Kind.Void)); - addRuntimeCall(SET_DEOPT_INFO, config.setDeoptInfoStub, - /* temps */ null, - /* ret */ ret(Kind.Void), - /* arg0: info */ scratch(Kind.Object)); - - addRuntimeCall(DEBUG, config.debugStub, - /* temps */ null, - /* ret */ ret(Kind.Void)); - addRuntimeCall(ARITHMETIC_FREM, config.arithmeticFremStub, /* temps */ null, /* ret */ ret(Kind.Float), @@ -189,10 +190,39 @@ /* arg3: r */ word, /* arg4: inLength */ Kind.Int)); + addRuntimeCall(AMD64HotSpotBackend.EXCEPTION_HANDLER, config.handleExceptionStub, + /* temps */ null, + /* ret */ ret(Kind.Void)); + + addRuntimeCall(AMD64HotSpotBackend.DEOPT_HANDLER, config.handleDeoptStub, + /* temps */ null, + /* ret */ ret(Kind.Void)); + + addRuntimeCall(AMD64HotSpotBackend.IC_MISS_HANDLER, config.inlineCacheMissStub, + /* temps */ null, + /* ret */ ret(Kind.Void)); // @formatter:on } + private AMD64ConvertSnippets.Templates convertSnippets; + + @Override + public void installSnippets(Backend backend, SnippetInstaller installer, Assumptions assumptions) { + installer.installSnippets(AMD64ConvertSnippets.class); + convertSnippets = new AMD64ConvertSnippets.Templates(this, assumptions, graalRuntime.getTarget()); + super.installSnippets(backend, installer, assumptions); + } + + @Override + public void lower(Node n, LoweringTool tool) { + if (n instanceof ConvertNode) { + convertSnippets.lower((ConvertNode) n, tool); + } else { + super.lower(n, tool); + } + } + @Override public Register threadRegister() { return r15; diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,75 @@ +/* + * 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.amd64; + +import static com.oracle.graal.amd64.AMD64.*; +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.amd64.*; +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.asm.*; + +/** + * Performs an unwind to throw an exception. + */ +@Opcode("UNWIND") +final class AMD64HotSpotUnwindOp extends AMD64HotSpotEpilogueOp { + + public static final Descriptor UNWIND_EXCEPTION = new Descriptor("unwindException", true, void.class, Object.class); + + /** + * Unwind stub expects the exception in RAX. + */ + public static final Register EXCEPTION = AMD64.rax; + + @Use({REG}) protected AllocatableValue exception; + + AMD64HotSpotUnwindOp(AllocatableValue exception) { + this.exception = exception; + assert asRegister(exception) == EXCEPTION; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + // Copy the saved RBP value into the slot just below the return address + // so that the stub can pick it up from there. + AMD64Address rbpSlot; + int rbpSlotOffset = tasm.frameMap.frameSize() - 8; + if (isStackSlot(savedRbp)) { + rbpSlot = (AMD64Address) tasm.asAddress(savedRbp); + assert rbpSlot.getDisplacement() == rbpSlotOffset; + } else { + rbpSlot = new AMD64Address(rsp, rbpSlotOffset); + masm.movq(rbpSlot, asRegister(savedRbp)); + } + + // Pass the address of the RBP slot in RBP itself + masm.leaq(rbp, rbpSlot); + AMD64Call.directCall(tasm, masm, tasm.runtime.lookupRuntimeCall(UNWIND_EXCEPTION), AMD64.r10, false, null); + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectStaticCallOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectStaticCallOp.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,67 @@ +/* + * 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.amd64; + +import com.oracle.graal.amd64.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.hotspot.bridge.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.amd64.AMD64Call.DirectCallOp; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; + +/** + * A direct call that complies with the conventions for such calls in HotSpot. In particular, for + * calls using an inline cache, a MOVE instruction is emitted just prior to the aligned direct call. + * This instruction (which moves 0L in RAX) is patched by the C++ Graal code to replace the 0L + * constant with Universe::non_oop_word(), a special sentinel used for the initial value of the + * Klass in an inline cache. It puts the called method into rbx before calling. + */ +@Opcode("CALL_DIRECT") +final class AMD64HotspotDirectStaticCallOp extends DirectCallOp { + + private final Constant metaspaceMethod; + private final InvokeKind invokeKind; + + AMD64HotspotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, Constant metaspaceMethod) { + super(target, result, parameters, temps, state); + assert invokeKind == InvokeKind.Static || invokeKind == InvokeKind.Special; + this.metaspaceMethod = metaspaceMethod; + this.invokeKind = invokeKind; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + // The mark for an invocation that uses an inline cache must be placed at the + // instruction + // that loads the Klass from the inline cache so that the C++ code can find it + // and replace the inline 0L value with Universe::non_oop_word() + AMD64Move.move(tasm, masm, AMD64.rbx.asValue(Kind.Long), metaspaceMethod); + tasm.recordMark(invokeKind == InvokeKind.Static ? Marks.MARK_INVOKESTATIC : Marks.MARK_INVOKESPECIAL); + AMD64Move.move(tasm, masm, AMD64.rax.asValue(Kind.Long), Constant.LONG_0); + super.emitCode(tasm, masm); + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java Thu Mar 21 14:11:13 2013 +0100 @@ -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.amd64; + +import static com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind.*; + +import com.oracle.graal.amd64.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.hotspot.bridge.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.amd64.*; +import com.oracle.graal.lir.amd64.AMD64Call.DirectCallOp; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; + +/** + * A direct call that complies with the conventions for such calls in HotSpot. In particular, for + * calls using an inline cache, a MOVE instruction is emitted just prior to the aligned direct call. + * This instruction (which moves 0L in RAX) is patched by the C++ Graal code to replace the 0L + * constant with Universe::non_oop_word(), a special sentinel used for the initial value of the + * Klass in an inline cache. + */ +@Opcode("CALL_DIRECT") +final class AMD64HotspotDirectVirtualCallOp extends DirectCallOp { + + private final InvokeKind invokeKind; + + AMD64HotspotDirectVirtualCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind) { + super(target, result, parameters, temps, state); + this.invokeKind = invokeKind; + assert invokeKind == InvokeKind.Interface || invokeKind == InvokeKind.Virtual; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + // The mark for an invocation that uses an inline cache must be placed at the + // instruction + // that loads the Klass from the inline cache so that the C++ code can find it + // and replace the inline 0L value with Universe::non_oop_word() + tasm.recordMark(invokeKind == Virtual ? Marks.MARK_INVOKEVIRTUAL : Marks.MARK_INVOKEINTERFACE); + AMD64Move.move(tasm, masm, AMD64.rax.asValue(Kind.Long), Constant.LONG_0); + super.emitCode(tasm, masm); + } +} diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64IndirectCallOp.java Thu Mar 21 14:11:13 2013 +0100 @@ -52,14 +52,14 @@ @Use({REG}) protected Value metaspaceMethod; - AMD64IndirectCallOp(Object targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state) { + AMD64IndirectCallOp(InvokeTarget targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state) { super(targetMethod, result, parameters, temps, targetAddress, state); this.metaspaceMethod = metaspaceMethod; } @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - tasm.recordMark(Marks.MARK_INLINE_INVOKEVIRTUAL); + tasm.recordMark(Marks.MARK_INLINE_INVOKE); Register callReg = asRegister(targetAddress); assert callReg != METHOD; AMD64Call.indirectCall(tasm, masm, callReg, callTarget, state); diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64SafepointOp.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,6 +24,7 @@ import static com.oracle.graal.amd64.AMD64.*; import static com.oracle.graal.phases.GraalOptions.*; +import sun.misc.*; import com.oracle.graal.api.code.*; import com.oracle.graal.asm.amd64.*; @@ -33,6 +34,7 @@ import com.oracle.graal.lir.LIRInstruction.Opcode; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.spi.*; /** * Emits a safepoint poll. @@ -40,31 +42,35 @@ @Opcode("SAFEPOINT") public class AMD64SafepointOp extends AMD64LIRInstruction { + private static final Unsafe unsafe = Unsafe.getUnsafe(); + @State protected LIRFrameState state; + @Temp({OperandFlag.REG}) private AllocatableValue temp; private final HotSpotVMConfig config; - public AMD64SafepointOp(LIRFrameState state, HotSpotVMConfig config) { + public AMD64SafepointOp(LIRFrameState state, HotSpotVMConfig config, LIRGeneratorTool tool) { this.state = state; this.config = config; + temp = tool.newVariable(tool.target().wordKind); } @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler asm) { - Register scratch = tasm.frameMap.registerConfig.getScratchRegister(); int pos = asm.codeBuffer.position(); - int offset = SafepointPollOffset % tasm.target.pageSize; + int offset = SafepointPollOffset % unsafe.pageSize(); + RegisterValue scratch = (RegisterValue) temp; if (config.isPollingPageFar) { - asm.movq(scratch, config.safepointPollingAddress + offset); + asm.movq(scratch.getRegister(), config.safepointPollingAddress + offset); tasm.recordMark(Marks.MARK_POLL_FAR); tasm.recordSafepoint(pos, state); - asm.movq(scratch, new Address(tasm.target.wordKind, scratch.asValue())); + asm.movq(scratch.getRegister(), new AMD64Address(scratch.getRegister())); } else { tasm.recordMark(Marks.MARK_POLL_NEAR); tasm.recordSafepoint(pos, state); // 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, new Address(tasm.target.wordKind, rip.asValue(), offset)); + asm.movq(scratch.getRegister(), new AMD64Address(rip, offset)); } } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/CompilationServer.java --- a/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/CompilationServer.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/CompilationServer.java Thu Mar 21 14:11:13 2013 +0100 @@ -93,7 +93,6 @@ // return the initialized compiler to the client HotSpotGraalRuntime compiler = initializeServer(toVM); - compiler.getCompiler(); streams.getInvocation().sendResult(compiler); for (ConnectionObserver observer : observers) { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Thu Mar 21 14:11:13 2013 +0100 @@ -47,13 +47,13 @@ } @Override - public TargetMethodAssembler newAssembler(FrameMap frameMap, LIR lir) { + public TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult) { // SPARC: Create assembler. return null; } @Override - public void emitCode(TargetMethodAssembler tasm, ResolvedJavaMethod method, LIR lir) { + public void emitCode(TargetMethodAssembler tasm, ResolvedJavaMethod method, LIRGenerator lirGen) { // SPARC: Emit code } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/ArrayCopyIntrinsificationTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -51,9 +51,8 @@ if (node instanceof Invoke) { Invoke invoke = (Invoke) node; Assert.assertTrue(invoke.callTarget() instanceof DirectCallTargetNode); - DirectCallTargetNode directCall = (DirectCallTargetNode) invoke.callTarget(); - Assert.assertTrue(directCall.target() instanceof JavaMethod); - JavaMethod callee = (JavaMethod) directCall.target(); + 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())); @@ -64,8 +63,8 @@ for (Node node : graph.getNodes()) { if (node instanceof Invoke) { Invoke invoke = (Invoke) node; - DirectCallTargetNode directCall = (DirectCallTargetNode) invoke.callTarget(); - JavaMethod callee = (JavaMethod) directCall.target(); + AbstractCallTargetNode directCall = (AbstractCallTargetNode) invoke.callTarget(); + JavaMethod callee = directCall.target(); if (callee.getDeclaringClass().equals(runtime.lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) { found = true; } else { diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Thu Mar 21 14:11:13 2013 +0100 @@ -28,6 +28,7 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.internal.*; import com.oracle.graal.graph.*; @@ -143,10 +144,10 @@ } else { // Compiling an intrinsic graph - must clone the graph graph = graph.copy(); - // System.out.println("compiling intrinsic " + method); } InlinedBytecodes.add(method.getCodeSize()); - return graalRuntime.getCompiler().compileMethod(method, graph, graalRuntime.getCache(), plan, optimisticOpts); + return GraalCompiler.compileMethod(graalRuntime.getRuntime(), graalRuntime.getBackend(), graalRuntime.getTarget(), method, graph, graalRuntime.getCache(), plan, + optimisticOpts, method.getSpeculationLog()); } }); } finally { @@ -176,15 +177,14 @@ stats.finish(method); } - private void installMethod(final CompilationResult tm) { - Debug.scope("CodeInstall", new Object[]{new DebugDumpScope(String.valueOf(id), true), graalRuntime.getCompiler(), method}, new Runnable() { + private void installMethod(final CompilationResult compResult) { + Debug.scope("CodeInstall", new Object[]{new DebugDumpScope(String.valueOf(id), true), graalRuntime.getRuntime(), method}, new Runnable() { @Override public void run() { - final CodeInfo[] info = Debug.isDumpEnabled() ? new CodeInfo[1] : null; - graalRuntime.getRuntime().installMethod(method, entryBCI, tm, info); - if (info != null) { - Debug.dump(new Object[]{tm, info[0]}, "After code installation"); + HotSpotInstalledCode installedCode = graalRuntime.getRuntime().installMethod(method, entryBCI, compResult); + if (Debug.isDumpEnabled()) { + Debug.dump(new Object[]{compResult, installedCode}, "After code installation"); } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Thu Mar 21 14:11:13 2013 +0100 @@ -30,7 +30,7 @@ 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.target.*; import com.oracle.graal.hotspot.bridge.*; import com.oracle.graal.hotspot.logging.*; import com.oracle.graal.hotspot.meta.*; @@ -109,13 +109,13 @@ protected/* final */VMToCompiler vmToCompiler; protected final HotSpotRuntime runtime; - protected final GraalCompiler compiler; protected final TargetDescription target; private HotSpotRuntimeInterpreterInterface runtimeInterpreterInterface; private volatile HotSpotGraphCache cache; protected final HotSpotVMConfig config; + private final HotSpotBackend backend; protected HotSpotGraalRuntime() { CompilerToVM toVM = new CompilerToVMImpl(); @@ -139,9 +139,8 @@ runtime = createRuntime(); - HotSpotBackend backend = createBackend(); + backend = createBackend(); GraalOptions.StackShadowPages = config.stackShadowPages; - compiler = new GraalCompiler(getRuntime(), getTarget(), backend); if (GraalOptions.CacheGraphs) { cache = new HotSpotGraphCache(); } @@ -176,10 +175,6 @@ return target; } - public GraalCompiler getCompiler() { - return compiler; - } - public HotSpotGraphCache getCache() { return cache; } @@ -211,8 +206,6 @@ break; case Int: return impl.typeInt; - case Jsr: - break; case Long: return impl.typeLong; case Object: @@ -264,9 +257,16 @@ if (clazz == DisassemblerProvider.class || clazz == BytecodeDisassemblerProvider.class) { return (T) getRuntime(); } - if (clazz == GraalCompiler.class) { - return (T) getCompiler(); + if (clazz == HotSpotRuntime.class) { + return (T) runtime; + } + if (clazz == Backend.class) { + return (T) getBackend(); } return null; } + + public HotSpotBackend getBackend() { + return backend; + } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotRuntimeCallTarget.java Thu Mar 21 14:11:13 2013 +0100 @@ -30,7 +30,7 @@ /** * The details required to link a HotSpot runtime or stub call. */ -public class HotSpotRuntimeCallTarget implements RuntimeCallTarget { +public class HotSpotRuntimeCallTarget implements RuntimeCallTarget, InvokeTarget { /** * The descriptor of the stub. This is for informational purposes only. diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotSnippetInstaller.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotSnippetInstaller.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotSnippetInstaller.java Thu Mar 21 14:11:13 2013 +0100 @@ -42,7 +42,7 @@ } @Override - protected void installMethodSubstitution(Method originalMethod, Method substituteMethod) { + protected void installMethodSubstitution(Member originalMethod, Method substituteMethod) { if (substituteMethod.getDeclaringClass() == IntegerSubstitutions.class || substituteMethod.getDeclaringClass() == LongSubstitutions.class) { if (substituteMethod.getName().equals("bitCount")) { if (!config.usePopCountInstruction) { diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Thu Mar 21 14:11:13 2013 +0100 @@ -45,7 +45,6 @@ public boolean useG1GC; // offsets, ... - public int vmPageSize; public int stackShadowPages; /** @@ -171,6 +170,11 @@ public int uninitializedIdentityHashCodeValue; /** + * Offset of the pending deoptimization field. + */ + public int pendingDeoptimizationOffset; + + /** * Mark word right shift to get identity hash code. */ public int identityHashCodeShift; @@ -316,8 +320,6 @@ public int typeProfileWidth; // runtime stubs - public long debugStub; - public long instanceofStub; public long newInstanceStub; public long newArrayStub; public long newMultiArrayStub; @@ -335,7 +337,6 @@ public long unwindExceptionStub; public long osrMigrationEndStub; public long registerFinalizerStub; - public long setDeoptInfoStub; public long createNullPointerExceptionStub; public long createOutOfBoundsExceptionStub; public long javaTimeMillisStub; @@ -376,7 +377,6 @@ public int deoptActionMakeNotCompilable; public void check() { - assert vmPageSize >= 16; assert codeEntryAlignment > 0; assert stackShadowPages > 0; } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Thu Mar 21 14:11:13 2013 +0100 @@ -25,6 +25,7 @@ import java.lang.reflect.*; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; @@ -148,11 +149,9 @@ * @param compResult the result of a compilation * @param code if not null, then the code is installed as the non-default compiled code for the * associated method and the details of the installation are written to this object - * @param info additional information about the installation are written to this object if it is - * not null * @return the outcome of the installation as a {@link CodeInstallResult}. */ - CodeInstallResult installCode(HotSpotCompilationResult compResult, HotSpotInstalledCode code, HotSpotCodeInfo info); + CodeInstallResult installCode(HotSpotCompilationResult compResult, HotSpotInstalledCode code, SpeculationLog cache); void initializeConfiguration(HotSpotVMConfig config); @@ -189,9 +188,14 @@ long getMaxCallTargetOffset(long stub); - String disassembleNative(byte[] code, long address); + String disassembleNMethod(long nmethod); - String disassembleNMethod(long nmethod); + /** + * Gets a copy of the machine code for an nmethod. + * + * @return the machine code for {@code nmethod} if it is valid, null otherwise + */ + byte[] getCode(long nmethod); StackTraceElement getStackTraceElement(long metaspaceMethod, int bci); @@ -203,8 +207,6 @@ long[] getDeoptedLeafGraphIds(); - String decodePC(long pc); - long[] getLineNumberTable(HotSpotResolvedJavaMethod method); Local[] getLocalVariableTable(HotSpotResolvedJavaMethod method); diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Thu Mar 21 14:11:13 2013 +0100 @@ -25,6 +25,7 @@ import java.lang.reflect.*; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; @@ -34,11 +35,11 @@ */ public class CompilerToVMImpl implements CompilerToVM { - private native int installCode0(HotSpotCompilationResult comp, HotSpotInstalledCode code, HotSpotCodeInfo info); + private native int installCode0(HotSpotCompilationResult comp, HotSpotInstalledCode code, boolean[] triggeredDeoptimizations); @Override - public CodeInstallResult installCode(HotSpotCompilationResult comp, HotSpotInstalledCode code, HotSpotCodeInfo info) { - return CodeInstallResult.values()[installCode0(comp, code, info)]; + public CodeInstallResult installCode(HotSpotCompilationResult comp, HotSpotInstalledCode code, SpeculationLog speculationLog) { + return CodeInstallResult.values()[installCode0(comp, code, (speculationLog == null) ? null : speculationLog.getRawMap())]; } @Override @@ -123,10 +124,10 @@ public native long getMaxCallTargetOffset(long stub); @Override - public native String disassembleNative(byte[] code, long address); + public native String disassembleNMethod(long nmethod); @Override - public native String disassembleNMethod(long nmethod); + public native byte[] getCode(long nmethod); @Override public native StackTraceElement getStackTraceElement(long metaspaceMethod, int bci); @@ -144,9 +145,6 @@ public native long[] getDeoptedLeafGraphIds(); @Override - public native String decodePC(long pc); - - @Override public native long[] getLineNumberTable(HotSpotResolvedJavaMethod method); @Override diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/Marks.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/Marks.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/Marks.java Thu Mar 21 14:11:13 2013 +0100 @@ -29,24 +29,18 @@ */ public interface Marks { - // @formatter:off - // These constants need to correspond to those of the same name in graalCodeInstaller.hpp - Integer MARK_VERIFIED_ENTRY = 0x0001; - Integer MARK_UNVERIFIED_ENTRY = 0x0002; - Integer MARK_OSR_ENTRY = 0x0003; - Integer MARK_UNWIND_ENTRY = 0x0004; - Integer MARK_EXCEPTION_HANDLER_ENTRY = 0x0005; - Integer MARK_DEOPT_HANDLER_ENTRY = 0x0006; - Integer MARK_STATIC_CALL_STUB = 0x1000; - Integer MARK_INVOKEINTERFACE = 0x2001; - Integer MARK_INVOKESTATIC = 0x2002; - Integer MARK_INVOKESPECIAL = 0x2003; - Integer MARK_INVOKEVIRTUAL = 0x2004; - Integer MARK_INLINE_INVOKEVIRTUAL = 0x2005; - Integer MARK_IMPLICIT_NULL = 0x3000; - Integer MARK_POLL_NEAR = 0x3001; - Integer MARK_POLL_RETURN_NEAR = 0x3002; - Integer MARK_POLL_FAR = 0x3003; - Integer MARK_POLL_RETURN_FAR = 0x3004; - + int MARK_VERIFIED_ENTRY = 1; + int MARK_UNVERIFIED_ENTRY = 2; + int MARK_OSR_ENTRY = 3; + int MARK_EXCEPTION_HANDLER_ENTRY = 4; + int MARK_DEOPT_HANDLER_ENTRY = 5; + int MARK_INVOKEINTERFACE = 6; + int MARK_INVOKEVIRTUAL = 7; + int MARK_INVOKESTATIC = 8; + int MARK_INVOKESPECIAL = 9; + int MARK_INLINE_INVOKE = 10; + int MARK_POLL_NEAR = 11; + int MARK_POLL_RETURN_NEAR = 12; + int MARK_POLL_FAR = 13; + int MARK_POLL_RETURN_FAR = 14; } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Thu Mar 21 14:11:13 2013 +0100 @@ -36,7 +36,6 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.internal.*; import com.oracle.graal.hotspot.*; @@ -143,10 +142,9 @@ } // Install intrinsics. - GraalCompiler compiler = graalRuntime.getCompiler(); - final HotSpotRuntime runtime = (HotSpotRuntime) compiler.runtime; + final HotSpotRuntime runtime = graalRuntime.getCapability(HotSpotRuntime.class); if (GraalOptions.Intrinsify) { - Debug.scope("InstallSnippets", new Object[]{new DebugDumpScope("InstallSnippets"), compiler}, new Runnable() { + Debug.scope("InstallSnippets", new Object[]{new DebugDumpScope("InstallSnippets")}, new Runnable() { @Override public void run() { @@ -155,7 +153,7 @@ Assumptions assumptions = new Assumptions(false); SnippetInstaller installer = new HotSpotSnippetInstaller(runtime, assumptions, runtime.getGraalRuntime().getTarget()); GraalIntrinsics.installIntrinsics(installer); - runtime.installSnippets(installer, assumptions); + runtime.installSnippets(graalRuntime.getBackend(), installer, assumptions); } }); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeInfo.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeInfo.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +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.meta; - -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.hotspot.*; - -/** - * Implementation of {@link CodeInfo} for HotSpot. - */ -public class HotSpotCodeInfo extends CompilerObject implements CodeInfo { - - private static final long serialVersionUID = -6766490427732498354L; - - private long start; - private byte[] code; - public final CompilationResult targetMethod; - private HotSpotResolvedJavaMethod method; - - public HotSpotCodeInfo(CompilationResult targetMethod, HotSpotResolvedJavaMethod method) { - assert targetMethod != null; - this.method = method; - this.targetMethod = targetMethod; - } - - @Override - public long getStart() { - return start; - } - - @Override - public byte[] getCode() { - return code; - } - - @Override - public String toString() { - int size = code == null ? 0 : code.length; - return "installed code @[" + Long.toHexString(start) + "-" + Long.toHexString(start + size) + "]"; - - } - - @Override - public ResolvedJavaMethod getMethod() { - return method; - } -} diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInstalledCode.java Thu Mar 21 14:11:13 2013 +0100 @@ -38,10 +38,17 @@ private static final long serialVersionUID = 156632908220561612L; private final HotSpotResolvedJavaMethod method; + private final boolean isDefault; long nmethod; + long start; - public HotSpotInstalledCode(HotSpotResolvedJavaMethod method) { + public HotSpotInstalledCode(HotSpotResolvedJavaMethod method, boolean isDefault) { this.method = method; + this.isDefault = isDefault; + } + + public boolean isDefault() { + return isDefault; } @Override @@ -87,4 +94,14 @@ assert checkArgs(args); return HotSpotGraalRuntime.getInstance().getCompilerToVM().executeCompiledMethodVarargs(method.metaspaceMethod, nmethod, args); } + + @Override + public long getStart() { + return isValid() ? start : 0; + } + + @Override + public byte[] getCode() { + return HotSpotGraalRuntime.getInstance().getCompilerToVM().getCode(nmethod); + } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java Thu Mar 21 14:11:13 2013 +0100 @@ -30,6 +30,7 @@ import java.util.*; import java.util.concurrent.*; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.meta.ProfilingInfo.ExceptionSeen; import com.oracle.graal.bytecode.*; @@ -58,8 +59,8 @@ private HotSpotMethodData methodData; private byte[] code; private int compilationComplexity; - private CompilationTask currentTask; + private SpeculationLog speculationLog; HotSpotResolvedJavaMethod(HotSpotResolvedObjectType holder, long metaspaceMethod) { this.metaspaceMethod = metaspaceMethod; @@ -72,6 +73,13 @@ return holder; } + /** + * Gets the address of the C++ Method object for this method. + */ + public Constant getMetaspaceMethodConstant() { + return Constant.forIntegerKind(HotSpotGraalRuntime.getInstance().getTarget().wordKind, metaspaceMethod, this); + } + @Override public int getModifiers() { HotSpotVMConfig config = HotSpotGraalRuntime.getInstance().getConfig(); @@ -86,6 +94,9 @@ @Override public byte[] getCode() { + if (codeSize == 0) { + return null; + } if (code == null) { code = HotSpotGraalRuntime.getInstance().getCompilerToVM().initializeBytecode(metaspaceMethod, new byte[codeSize]); assert code.length == codeSize : "expected: " + codeSize + ", actual: " + code.length; @@ -335,4 +346,10 @@ return currentTask; } + public SpeculationLog getSpeculationLog() { + if (speculationLog == null) { + speculationLog = new SpeculationLog(); + } + return speculationLog; + } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -29,6 +29,7 @@ import java.lang.annotation.*; import java.lang.reflect.*; +import java.net.*; import java.util.*; import com.oracle.graal.api.meta.*; @@ -497,4 +498,26 @@ } return null; } + + @Override + public URL getClassFilePath() { + Class cls = mirror(); + return cls.getResource(MetaUtil.getSimpleName(cls, true).replace('.', '$') + ".class"); + } + + @Override + public boolean isLocal() { + return mirror().isLocalClass(); + } + + @Override + public boolean isMember() { + return mirror().isMemberClass(); + } + + @Override + public ResolvedJavaType getEnclosingType() { + final Class encl = mirror().getEnclosingClass(); + return encl == null ? null : fromClass(encl); + } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -24,6 +24,7 @@ import java.lang.annotation.*; import java.lang.reflect.*; +import java.net.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; @@ -189,4 +190,24 @@ public Class mirror() { return javaMirror; } + + @Override + public URL getClassFilePath() { + return null; + } + + @Override + public boolean isLocal() { + return false; + } + + @Override + public boolean isMember() { + return false; + } + + @Override + public ResolvedJavaType getEnclosingType() { + return null; + } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Thu Mar 21 14:11:13 2013 +0100 @@ -32,7 +32,6 @@ import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; import static com.oracle.graal.hotspot.snippets.SystemSubstitutions.*; import static com.oracle.graal.java.GraphBuilderPhase.RuntimeCalls.*; -import static com.oracle.graal.nodes.UnwindNode.*; import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*; import static com.oracle.graal.snippets.Log.*; import static com.oracle.graal.snippets.MathSubstitutionsX86.*; @@ -51,6 +50,7 @@ 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.*; @@ -196,10 +196,6 @@ return result; } - protected Value scratch(Kind kind) { - return globalStubRegConfig.getScratchRegister().asValue(kind); - } - public HotSpotRuntime(HotSpotVMConfig config, HotSpotGraalRuntime graalRuntime) { this.config = config; this.graalRuntime = graalRuntime; @@ -208,11 +204,6 @@ // @formatter:off - addRuntimeCall(UNWIND_EXCEPTION, config.unwindExceptionStub, - /* temps */ null, - /* ret */ ret(Kind.Void), - /* arg0: exception */ javaCallingConvention(Kind.Object)); - addRuntimeCall(OnStackReplacementPhase.OSR_MIGRATION_END, config.osrMigrationEndStub, /* temps */ null, /* ret */ ret(Kind.Void), @@ -328,7 +319,7 @@ protected abstract RegisterConfig createRegisterConfig(boolean globalStubConfig); - public void installSnippets(SnippetInstaller installer, Assumptions assumptions) { + public void installSnippets(Backend backend, SnippetInstaller installer, Assumptions assumptions) { if (GraalOptions.IntrinsifyObjectMethods) { installer.installSubstitutions(ObjectSubstitutions.class); } @@ -372,9 +363,8 @@ newInstanceStub = new NewInstanceStub(this, assumptions, graalRuntime.getTarget()); newArrayStub = new NewArrayStub(this, assumptions, graalRuntime.getTarget()); - newInstanceStub.install(graalRuntime.getCompiler()); - newArrayStub.install(graalRuntime.getCompiler()); - + newInstanceStub.install(backend); + newArrayStub.install(backend); } public HotSpotGraalRuntime getGraalRuntime() { @@ -392,16 +382,17 @@ public abstract Register stackPointerRegister(); @Override - public String disassemble(CodeInfo info, CompilationResult tm) { - byte[] code = info.getCode(); + public String disassemble(CompilationResult compResult, InstalledCode installedCode) { + byte[] code = installedCode == null ? Arrays.copyOf(compResult.getTargetCode(), compResult.getTargetCodeSize()) : installedCode.getCode(); + long start = installedCode == null ? 0L : installedCode.getStart(); TargetDescription target = graalRuntime.getTarget(); - HexCodeFile hcf = new HexCodeFile(code, info.getStart(), target.arch.getName(), target.wordSize * 8); - if (tm != null) { - HexCodeFile.addAnnotations(hcf, tm.getAnnotations()); - addExceptionHandlersComment(tm, hcf); + HexCodeFile hcf = new HexCodeFile(code, start, target.arch.getName(), target.wordSize * 8); + if (compResult != null) { + HexCodeFile.addAnnotations(hcf, compResult.getAnnotations()); + addExceptionHandlersComment(compResult, hcf); Register fp = regConfig.getFrameRegister(); RefMapFormatter slotFormatter = new RefMapFormatter(target.arch, target.wordSize, fp, 0); - for (Safepoint safepoint : tm.getSafepoints()) { + for (Safepoint safepoint : compResult.getSafepoints()) { if (safepoint instanceof Call) { Call call = (Call) safepoint; if (call.debugInfo != null) { @@ -415,10 +406,10 @@ addOperandComment(hcf, safepoint.pcOffset, "{safepoint}"); } } - for (DataPatch site : tm.getDataReferences()) { + for (DataPatch site : compResult.getDataReferences()) { hcf.addOperandComment(site.pcOffset, "{" + site.constant + "}"); } - for (Mark mark : tm.getMarks()) { + for (Mark mark : compResult.getMarks()) { hcf.addComment(mark.pcOffset, getMarkName(mark)); } } @@ -507,7 +498,7 @@ } @Override - public RegisterConfig lookupRegisterConfig(ResolvedJavaMethod method) { + public RegisterConfig lookupRegisterConfig() { return regConfig; } @@ -576,6 +567,9 @@ graph.addAfterFixed(metaspaceMethod, compiledEntry); } } + } else if (callTarget.invokeKind() == InvokeKind.Special || callTarget.invokeKind() == InvokeKind.Static) { + loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.node().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall, + callTarget.invokeKind())); } if (loweredCallTarget == null) { @@ -642,7 +636,7 @@ // 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, false); + 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)) { @@ -721,7 +715,7 @@ } else if (n instanceof UnsafeLoadNode) { UnsafeLoadNode load = (UnsafeLoadNode) n; assert load.kind() != Kind.Illegal; - IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, load.accessKind(), load.displacement(), load.offset(), graph, false); + IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, load.accessKind(), load.displacement(), load.offset(), graph, 1); ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp())); // An unsafe read must not floating outside its block as may float above an explicit // null check on its object. @@ -729,7 +723,7 @@ graph.replaceFixedWithFixed(load, memoryRead); } else if (n instanceof UnsafeStoreNode) { UnsafeStoreNode store = (UnsafeStoreNode) n; - IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, store.accessKind(), store.displacement(), store.offset(), graph, false); + 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)); write.setStateAfter(store.stateAfter()); @@ -808,14 +802,17 @@ } 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) { + // Nothing to do, using direct LIR lowering for these nodes. } else { assert false : "Node implementing Lowerable not handled: " + n; throw GraalInternalError.shouldNotReachHere(); } } - private static IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index) { - return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, getArrayBaseOffset(elementKind), index, graph, true); + 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); } private SafeReadNode safeReadArrayLength(ValueNode array) { @@ -839,13 +836,6 @@ return HotSpotResolvedObjectType.fromClass(clazz); } - public Object lookupCallTarget(Object callTarget) { - if (callTarget instanceof HotSpotRuntimeCallTarget) { - return ((HotSpotRuntimeCallTarget) callTarget).getAddress(); - } - return callTarget; - } - /** * Gets the stub corresponding to a given method. * @@ -881,26 +871,17 @@ return graalRuntime.getCompilerToVM().getJavaField(reflectionField); } - private static HotSpotCodeInfo makeInfo(ResolvedJavaMethod method, CompilationResult compResult, CodeInfo[] info) { - HotSpotCodeInfo hsInfo = null; - if (info != null && info.length > 0) { - hsInfo = new HotSpotCodeInfo(compResult, (HotSpotResolvedJavaMethod) method); - info[0] = hsInfo; - } - return hsInfo; - } - - public void installMethod(HotSpotResolvedJavaMethod method, int entryBCI, CompilationResult compResult, CodeInfo[] info) { - HotSpotCodeInfo hsInfo = makeInfo(method, compResult, info); - graalRuntime.getCompilerToVM().installCode(new HotSpotCompilationResult(method, entryBCI, compResult), null, hsInfo); + public HotSpotInstalledCode installMethod(HotSpotResolvedJavaMethod method, int entryBCI, CompilationResult compResult) { + HotSpotInstalledCode installedCode = new HotSpotInstalledCode(method, true); + graalRuntime.getCompilerToVM().installCode(new HotSpotCompilationResult(method, entryBCI, compResult), installedCode, method.getSpeculationLog()); + return installedCode; } @Override - public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, CodeInfo[] info) { - HotSpotCodeInfo hsInfo = makeInfo(method, compResult, info); + public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult) { HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method; - HotSpotInstalledCode code = new HotSpotInstalledCode(hotspotMethod); - CodeInstallResult result = graalRuntime.getCompilerToVM().installCode(new HotSpotCompilationResult(hotspotMethod, -1, compResult), code, hsInfo); + HotSpotInstalledCode code = new HotSpotInstalledCode(hotspotMethod, false); + CodeInstallResult result = graalRuntime.getCompilerToVM().installCode(new HotSpotCompilationResult(hotspotMethod, -1, compResult), code, null); if (result != CodeInstallResult.OK) { return null; } @@ -968,7 +949,7 @@ } public boolean needsDataPatch(Constant constant) { - return constant.getPrimitiveAnnotation() instanceof HotSpotResolvedObjectType; + return constant.getPrimitiveAnnotation() != null; } /** @@ -1021,7 +1002,7 @@ long nmethod = ((HotSpotInstalledCode) code).nmethod; return graalRuntime.getCompilerToVM().disassembleNMethod(nmethod); } - return ""; + return null; } public String disassemble(ResolvedJavaMethod method) { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ArrayWriteBarrier.java diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -52,6 +52,11 @@ } @Override + public Object[] getLocationIdentities() { + return new Object[]{LocationNode.ANY_LOCATION}; + } + + @Override public void generate(LIRGenerator gen) { gen.lock(); StackSlot lockData = gen.peekLock(); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentThread.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentThread.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentThread.java Thu Mar 21 14:11:13 2013 +0100 @@ -42,7 +42,7 @@ public void generate(LIRGeneratorTool gen) { HotSpotGraalRuntime runtime = HotSpotGraalRuntime.getInstance(); Register thread = runtime.getRuntime().threadRegister(); - gen.setResult(this, gen.emitLoad(new Address(Kind.Object, thread.asValue(gen.target().wordKind), runtime.getConfig().threadObjectOffset), false)); + gen.setResult(this, gen.emitLoad(Kind.Object, thread.asValue(gen.target().wordKind), runtime.getConfig().threadObjectOffset, Value.ILLEGAL, 0, false)); } @NodeIntrinsic diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -32,8 +32,8 @@ /** * A special purpose store node that differs from {@link CompareAndSwapNode} in that it is not a - * {@link StateSplit} and it {@linkplain #compareAndSwap(Object, long, Word, Word) returns} either - * the expected value or the compared against value instead of a boolean. + * {@link StateSplit} and it {@linkplain #compareAndSwap(Object, long, Word, Word, Object)} returns + * either the expected value or the compared against value instead of a boolean. */ public class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRGenLowerable, MemoryCheckpoint { @@ -42,17 +42,15 @@ @Input private ValueNode expectedValue; @Input private ValueNode newValue; - public DirectCompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue) { + private final Object locationIdentity; + + public DirectCompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, Object locationIdentity) { super(expected.stamp()); this.object = object; this.offset = offset; this.expectedValue = expected; this.newValue = newValue; - } - - @Override - public void generate(LIRGenerator gen) { - ((HotSpotLIRGenerator) gen).visitDirectCompareAndSwap(this); + this.locationIdentity = locationIdentity; } public ValueNode object() { @@ -71,6 +69,16 @@ return newValue; } + @Override + public Object[] getLocationIdentities() { + return new Object[]{locationIdentity}; + } + + @Override + public void generate(LIRGenerator gen) { + ((HotSpotLIRGenerator) gen).visitDirectCompareAndSwap(this); + } + /** * Compares an expected value with the actual value in a location denoted by an object and a * given offset. Iff they are same, {@code newValue} is placed into the location and the @@ -84,5 +92,5 @@ * @return either {@code expectedValue} or the actual value */ @NodeIntrinsic - public static native Word compareAndSwap(Object object, long offset, Word expectedValue, Word newValue); + public static native Word compareAndSwap(Object object, long offset, Word expectedValue, Word newValue, @ConstantNodeParameter Object locationIdentity); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -44,6 +44,11 @@ } @Override + public Object[] getLocationIdentities() { + return new Object[]{LocationNode.ANY_LOCATION}; + } + + @Override public void generate(LIRGenerator gen) { gen.unlock(); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/FieldWriteBarrier.java diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -47,7 +47,7 @@ @Override public void generate(LIRGeneratorTool gen) { Value obj = gen.newVariable(gen.target().wordKind); - gen.emitMove(gen.operand(object), obj); + gen.emitMove(obj, gen.operand(object)); gen.setResult(this, obj); } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotDirectCallTargetNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotDirectCallTargetNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotDirectCallTargetNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -34,7 +34,7 @@ private final InvokeKind invokeKind; - public HotSpotDirectCallTargetNode(List arguments, Stamp returnStamp, JavaType[] signature, Object target, Type callType, InvokeKind invokeKind) { + public HotSpotDirectCallTargetNode(List arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, Type callType, InvokeKind invokeKind) { super(arguments, returnStamp, signature, target, callType); this.invokeKind = invokeKind; } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotIndirectCallTargetNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotIndirectCallTargetNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotIndirectCallTargetNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -33,7 +33,8 @@ @Input private ValueNode metaspaceMethod; - public HotSpotIndirectCallTargetNode(ValueNode metaspaceMethod, ValueNode computedAddress, List arguments, Stamp returnStamp, JavaType[] signature, Object target, Type callType) { + public HotSpotIndirectCallTargetNode(ValueNode metaspaceMethod, ValueNode computedAddress, List arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, + Type callType) { super(computedAddress, arguments, returnStamp, signature, target, callType); this.metaspaceMethod = metaspaceMethod; } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/RegisterNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/RegisterNode.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +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.api.code.*; -import com.oracle.graal.api.meta.*; -import com.oracle.graal.graph.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -/** - * Access the value of a specific register. - */ -@NodeInfo(nameTemplate = "Register %{p#register}") -public final class RegisterNode extends FixedWithNextNode implements LIRLowerable { - - private final Register register; - - public RegisterNode(Register register, Kind kind) { - super(StampFactory.forKind(kind)); - this.register = register; - } - - public RegisterNode(Register register) { - super(StampFactory.object()); - this.register = register; - } - - @Override - public void generate(LIRGeneratorTool generator) { - Value result; - if (generator.attributes(register).isAllocatable()) { - // The register allocator would prefer us not to tie up an allocatable - // register for the complete lifetime of this node. - result = generator.newVariable(kind()); - generator.emitMove(register.asValue(kind()), result); - } else { - result = register.asValue(kind()); - } - generator.setResult(this, result); - } - - @Override - public String toString(Verbosity verbosity) { - if (verbosity == Verbosity.Name) { - return super.toString(Verbosity.Name) + "%" + register; - } else { - return super.toString(verbosity); - } - } -} diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -69,7 +69,7 @@ parameters.add(frameState.localAt(slot)); } Value[] args = gen.visitInvokeArguments(cc, parameters); - Value entry = gen.emitLoad(new Address(Kind.Long, gen.operand(target), config.nmethodEntryOffset), false); + Value entry = gen.emitLoad(Kind.Long, gen.operand(target), config.nmethodEntryOffset, Value.ILLEGAL, 0, false); HotSpotLIRGenerator hsgen = (HotSpotLIRGenerator) gen; hsgen.emitTailcall(args, entry); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,7 +22,6 @@ */ package com.oracle.graal.hotspot.nodes; -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.nodes.*; @@ -46,6 +45,6 @@ } else { base = gen.emitAdd(base, Constant.forLong(config.cardtableStartAddress)); } - gen.emitStore(new Address(Kind.Boolean, base, displacement), Constant.FALSE, false); + gen.emitStore(Kind.Boolean, base, displacement, Value.ILLEGAL, 0, Constant.FALSE, false); } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -26,14 +26,16 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.code.RuntimeCallTarget.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.*; import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.java.*; 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.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; @@ -43,6 +45,27 @@ public static final Descriptor OSR_MIGRATION_END = new Descriptor("OSR_migration_end", true, void.class, long.class); + public class OSREntryProxyNode extends FloatingNode implements LIRLowerable { + + @Input private ValueNode object; + @Input(notDataflow = true) private final RuntimeCallNode anchor; + + public OSREntryProxyNode(ValueNode object, RuntimeCallNode anchor) { + super(object.stamp()); + this.object = object; + this.anchor = anchor; + } + + public RuntimeCallNode getAnchor() { + return anchor; + } + + @Override + public void generate(LIRGeneratorTool generator) { + generator.setResult(this, generator.operand(object)); + } + } + @Override protected void run(StructuredGraph graph) { if (graph.getEntryBCI() == StructuredGraph.INVOCATION_ENTRY_BCI) { @@ -81,7 +104,7 @@ LoopTransformations.peel(osrLoop); for (Node usage : osr.usages().snapshot()) { - ValueProxyNode proxy = (ValueProxyNode) usage; + ProxyNode proxy = (ProxyNode) usage; proxy.replaceAndDelete(proxy.value()); } FixedNode next = osr.next(); @@ -108,15 +131,17 @@ start.setStateAfter(null); GraphUtil.killWithUnusedFloatingInputs(oldStartState); + // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block) int localsOffset = (graph.method().getMaxLocals() - 1) * 8; for (int i = 0; i < osrState.localsSize(); i++) { ValueNode value = osrState.localAt(i); if (value != null) { - ValueProxyNode proxy = (ValueProxyNode) value; - int size = (value.kind() == Kind.Long || value.kind() == Kind.Double) ? 2 : 1; + ProxyNode proxy = (ProxyNode) value; + int size = FrameStateBuilder.stackSlots(value.kind()); int offset = localsOffset - (i + size - 1) * 8; UnsafeLoadNode load = graph.add(new UnsafeLoadNode(buffer, offset, ConstantNode.forInt(0, graph), value.kind())); - proxy.replaceAndDelete(load); + OSREntryProxyNode newProxy = graph.add(new OSREntryProxyNode(load, migrationEnd)); + proxy.replaceAndDelete(newProxy); graph.addBeforeFixed(migrationEnd, load); } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/AESCryptSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/AESCryptSubstitutions.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/AESCryptSubstitutions.java Thu Mar 21 14:11:13 2013 +0100 @@ -41,7 +41,7 @@ /** * Substitutions for {@code com.sun.crypto.provider.AESCrypt} methods. */ -@ClassSubstitution(className = "com.sun.crypto.provider.AESCrypt") +@ClassSubstitution(className = "com.sun.crypto.provider.AESCrypt", optional = true) public class AESCryptSubstitutions { static final long kOffset; @@ -70,7 +70,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)).add(arrayBaseOffset(Kind.Byte)); + Word kAddr = Word.fromObject(rcvr).readWord(Word.unsigned(kOffset), UNKNOWN_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) { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopyNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopyNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopyNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -30,6 +30,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.virtual.*; +import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.snippets.nodes.*; @@ -59,21 +60,19 @@ return arguments.get(4); } - private ResolvedJavaMethod selectSnippet(LoweringTool tool) { + private StructuredGraph selectSnippet(LoweringTool tool) { ResolvedJavaType srcType = getSource().objectStamp().type(); ResolvedJavaType destType = getDestination().objectStamp().type(); - if (srcType != null && srcType.isArray() && destType != null && destType.isArray()) { - Kind componentKind = srcType.getComponentType().getKind(); - if (componentKind != Kind.Object) { - if (srcType.getComponentType() == destType.getComponentType()) { - return tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind)); - } - } else if (destType.getComponentType().isAssignableFrom(srcType.getComponentType()) && getDestination().objectStamp().isExactType()) { - return tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(Kind.Object)); - } + if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) { + return null; } - return null; + if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType()) || !getDestination().objectStamp().isExactType()) { + return null; + } + Kind componentKind = srcType.getComponentType().getKind(); + ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.getSnippetForKind(componentKind)); + return (StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class); } private static void unrollFixedLengthLoop(StructuredGraph snippetGraph, int length, LoweringTool tool) { @@ -83,32 +82,48 @@ } // the canonicalization before loop unrolling is needed to propagate the length into // additions, etc. - new CanonicalizerPhase(tool.getTarget(), tool.getRuntime(), tool.assumptions()).apply(snippetGraph); + new CanonicalizerPhase(tool.getRuntime(), tool.assumptions()).apply(snippetGraph); new LoopFullUnrollPhase(tool.getRuntime(), tool.assumptions()).apply(snippetGraph); - new CanonicalizerPhase(tool.getTarget(), tool.getRuntime(), tool.assumptions()).apply(snippetGraph); + new CanonicalizerPhase(tool.getRuntime(), tool.assumptions()).apply(snippetGraph); + } + + private static void replaceSnippetInvokes(StructuredGraph snippetGraph, ResolvedJavaMethod targetMethod, int bci) { + for (InvokeNode invoke : snippetGraph.getNodes(InvokeNode.class)) { + if (invoke.methodCallTarget().targetMethod() != targetMethod) { + throw new GraalInternalError("unexpected invoke in arraycopy snippet"); + } + if (invoke.stateAfter().bci == FrameState.INVALID_FRAMESTATE_BCI) { + InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.methodCallTarget(), bci)); + newInvoke.setStateAfter(snippetGraph.add(new FrameState(FrameState.AFTER_BCI))); + snippetGraph.replaceFixedWithFixed(invoke, newInvoke); + } else { + assert invoke.stateAfter().bci == FrameState.AFTER_BCI : invoke; + } + } } @Override - public void lower(LoweringTool tool) { - ResolvedJavaMethod snippetMethod = selectSnippet(tool); - if (snippetMethod == null) { - snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.increaseGenericCallCounterMethod); - // we will call the generic method. the generic snippet will only increase the counter, - // not call the actual method. therefore we create a second invoke here. - ((StructuredGraph) graph()).addAfterFixed(this, createInvoke()); - } - if (Debug.isLogEnabled()) { - Debug.log("%s > Intrinsify (%s)", Debug.currentScope(), snippetMethod.getSignature().getParameterType(0, snippetMethod.getDeclaringClass()).getComponentType()); + protected StructuredGraph getSnippetGraph(LoweringTool tool) { + if (!GraalOptions.IntrinsifyArrayCopy) { + return null; } - StructuredGraph snippetGraph = (StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class); - assert snippetGraph != null : "ArrayCopySnippets should be installed"; - if (getLength().isConstant()) { - snippetGraph = snippetGraph.copy(); - unrollFixedLengthLoop(snippetGraph, getLength().asConstant().asInt(), tool); + StructuredGraph snippetGraph = selectSnippet(tool); + if (snippetGraph == null) { + ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(ArrayCopySnippets.genericArraycopySnippet); + snippetGraph = ((StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class)).copy(); + assert snippetGraph != null : "ArrayCopySnippets should be installed"; + + replaceSnippetInvokes(snippetGraph, getTargetMethod(), getBci()); + } else { + assert snippetGraph != null : "ArrayCopySnippets should be installed"; + + if (getLength().isConstant()) { + snippetGraph = snippetGraph.copy(); + unrollFixedLengthLoop(snippetGraph, getLength().asConstant().asInt(), tool); + } } - InvokeNode invoke = replaceWithInvoke(); - InliningUtil.inline(invoke, snippetGraph, false); + return snippetGraph; } private static boolean checkBounds(int position, int length, VirtualObjectNode virtualObject) { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,6 @@ */ package com.oracle.graal.hotspot.snippets; -import static com.oracle.graal.api.code.DeoptimizationAction.*; -import static com.oracle.graal.api.meta.DeoptimizationReason.*; import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*; @@ -33,24 +31,21 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; -import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.nodes.*; 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.phases.*; import com.oracle.graal.snippets.*; import com.oracle.graal.snippets.Snippet.ConstantParameter; -import com.oracle.graal.snippets.Snippet.Fold; import com.oracle.graal.snippets.nodes.*; +import com.oracle.graal.word.*; @SuppressWarnings("unused") public class ArrayCopySnippets implements SnippetsInterface { private static final EnumMap arraycopyMethods = new EnumMap<>(Kind.class); - public static final Method increaseGenericCallCounterMethod; + public static final Method genericArraycopySnippet; private static void addArraycopySnippetMethod(Kind kind, Class arrayClass) throws NoSuchMethodException { arraycopyMethods.put(kind, ArrayCopySnippets.class.getDeclaredMethod("arraycopy", arrayClass, int.class, arrayClass, int.class, int.class)); @@ -67,7 +62,7 @@ addArraycopySnippetMethod(Kind.Float, float[].class); addArraycopySnippetMethod(Kind.Double, double[].class); addArraycopySnippetMethod(Kind.Object, Object[].class); - increaseGenericCallCounterMethod = ArrayCopySnippets.class.getDeclaredMethod("increaseGenericCallCounter", Object.class, int.class, Object.class, int.class, int.class); + genericArraycopySnippet = ArrayCopySnippets.class.getDeclaredMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class); } catch (SecurityException | NoSuchMethodException e) { throw new GraalInternalError(e); } @@ -81,7 +76,9 @@ 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) { - checkInputs(src, srcPos, dest, destPos, length); + checkNonNull(src); + checkNonNull(dest); + checkLimits(src, srcPos, dest, destPos, length); int header = arrayBaseOffset(baseKind); int elementSize = arrayIndexScale(baseKind); long byteLength = (long) length * elementSize; @@ -109,17 +106,24 @@ } } - public static void checkInputs(Object src, int srcPos, Object dest, int destPos, int length) { - if (src == null) { + public static void checkNonNull(Object obj) { + if (obj == null) { probability(DEOPT_PATH_PROBABILITY); checkNPECounter.inc(); DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); } - if (dest == null) { + } + + public static int checkArrayType(Word hub) { + int layoutHelper = readLayoutHelper(hub); + if (layoutHelper >= 0) { probability(DEOPT_PATH_PROBABILITY); - checkNPECounter.inc(); DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); } + return layoutHelper; + } + + public static void checkLimits(Object src, int srcPos, Object dest, int destPos, int length) { if (srcPos < 0) { probability(DEOPT_PATH_PROBABILITY); checkAIOOBECounter.inc(); @@ -187,7 +191,9 @@ @Snippet public static void arraycopy(long[] src, int srcPos, long[] dest, int destPos, int length) { longCounter.inc(); - checkInputs(src, srcPos, dest, destPos, length); + checkNonNull(src); + checkNonNull(dest); + checkLimits(src, srcPos, dest, destPos, length); Kind baseKind = Kind.Long; int header = arrayBaseOffset(baseKind); long byteLength = (long) length * arrayIndexScale(baseKind); @@ -209,7 +215,9 @@ @Snippet public static void arraycopy(double[] src, int srcPos, double[] dest, int destPos, int length) { doubleCounter.inc(); - checkInputs(src, srcPos, dest, destPos, length); + checkNonNull(src); + checkNonNull(dest); + checkLimits(src, srcPos, dest, destPos, length); Kind baseKind = Kind.Double; int header = arrayBaseOffset(baseKind); long byteLength = (long) length * arrayIndexScale(baseKind); @@ -232,7 +240,9 @@ @Snippet public static void arraycopy(Object[] src, int srcPos, Object[] dest, int destPos, int length) { objectCounter.inc(); - checkInputs(src, srcPos, dest, destPos, length); + checkNonNull(src); + checkNonNull(dest); + checkLimits(src, srcPos, dest, destPos, length); final int scale = arrayIndexScale(Kind.Object); int header = arrayBaseOffset(Kind.Object); if (src == dest && srcPos < destPos) { // bad aliased case @@ -262,12 +272,67 @@ } @Snippet - public static void increaseGenericCallCounter(Object src, int srcPos, Object dest, int destPos, int length) { - if (GraalOptions.SnippetCounters) { - if (src.getClass().getComponentType().isPrimitive()) { - genericPrimitiveCallCounter.inc(); - } else { - genericObjectCallCounter.inc(); + public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) { + + // loading the hubs also checks for nullness + Word srcHub = loadHub(src); + Word destHub = loadHub(dest); + + 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); + } else { + genericObjectCallCounter.inc(); + System.arraycopy(src, srcPos, dest, destPos, length); + } + } + + public static void arraycopyInnerloop(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper) { + int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); + int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); + + Word memory = (Word) Word.fromObject(src); + + Word srcOffset = (Word) Word.fromObject(src).add(headerSize).add(srcPos << log2ElementSize); + Word destOffset = (Word) Word.fromObject(dest).add(headerSize).add(destPos << log2ElementSize); + Word destStart = destOffset; + long sizeInBytes = ((long) length) << log2ElementSize; + Word destEnd = destOffset.add(Word.unsigned(length).shiftLeft(log2ElementSize)); + + int nonVectorBytes = (int) (sizeInBytes % VECTOR_SIZE); + Word destNonVectorEnd = destStart.add(nonVectorBytes); + + while (destOffset.belowThan(destNonVectorEnd)) { + destOffset.writeByte(0, srcOffset.readByte(0, UNKNOWN_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 = 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); + } } } } @@ -287,7 +352,8 @@ private static final SnippetCounter objectCounter = new SnippetCounter(counters, "Object[]", "arraycopy for Object[] arrays"); private static final SnippetCounter floatCounter = new SnippetCounter(counters, "float[]", "arraycopy for float[] arrays"); private static final SnippetCounter doubleCounter = new SnippetCounter(counters, "double[]", "arraycopy for double[] arrays"); - private static final SnippetCounter genericPrimitiveCallCounter = new SnippetCounter(counters, "genericPrimitive", "call to the generic, native arraycopy method"); + private static final SnippetCounter genericPrimitiveCallCounter = new SnippetCounter(counters, "genericPrimitive", "generic arraycopy snippet for primitive arrays"); + private static final SnippetCounter genericObjectExactCallCounter = new SnippetCounter(counters, "genericObjectExact", "generic arraycopy snippet for special object arrays"); private static final SnippetCounter genericObjectCallCounter = new SnippetCounter(counters, "genericObject", "call to the generic, native arraycopy method"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Thu Mar 21 14:11:13 2013 +0100 @@ -108,7 +108,7 @@ isNull.inc(); } else { Word objectHub = loadHub(object); - if (objectHub.readWord(superCheckOffset).notEqual(hub)) { + if (objectHub.readWord(superCheckOffset, FINAL_LOCATION).notEqual(hub)) { probability(DEOPT_PATH_PROBABILITY); displayMiss.inc(); DeoptimizeNode.deopt(InvalidateReprofile, ClassCastException); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CipherBlockChainingSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CipherBlockChainingSubstitutions.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CipherBlockChainingSubstitutions.java Thu Mar 21 14:11:13 2013 +0100 @@ -42,7 +42,7 @@ /** * Substitutions for {@code com.sun.crypto.provider.CipherBlockChaining} methods. */ -@ClassSubstitution(className = "com.sun.crypto.provider.CipherBlockChaining") +@ClassSubstitution(className = "com.sun.crypto.provider.CipherBlockChaining", optional = true) public class CipherBlockChainingSubstitutions { private static final long embeddedCipherOffset; @@ -66,7 +66,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)); + Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset), UNKNOWN_LOCATION); if (getAESCryptClass().isInstance(embeddedCipher)) { crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, true); } else { @@ -75,8 +75,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)).add(arrayBaseOffset(Kind.Byte)); - Word rAddr = Word.unsigned(GetObjectAddressNode.get(rcvr)).readWord(Word.unsigned(rOffset)).add(arrayBaseOffset(Kind.Byte)); + 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 inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset); Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset); if (encrypt) { @@ -89,7 +89,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)); + Object embeddedCipher = Word.fromObject(rcvr).readObject(Word.unsigned(embeddedCipherOffset), UNKNOWN_LOCATION); if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, false); } else { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSubstitutions.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSubstitutions.java Thu Mar 21 14:11:13 2013 +0100 @@ -45,7 +45,7 @@ // Class for primitive type return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC; } else { - return klass.readInt(klassModifierFlagsOffset()); + return klass.readInt(klassModifierFlagsOffset(), FINAL_LOCATION); } } @@ -55,7 +55,7 @@ if (klass.equal(0)) { return false; } else { - int accessFlags = klass.readInt(klassAccessFlagsOffset()); + int accessFlags = klass.readInt(klassAccessFlagsOffset(), FINAL_LOCATION); return (accessFlags & Modifier.INTERFACE) != 0; } } @@ -66,8 +66,7 @@ if (klass.equal(0)) { return false; } else { - int layoutHelper = klass.readInt(klassLayoutHelperOffset()); - return (layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0; + return (readLayoutHelper(klass) & arrayKlassLayoutHelperIdentifier()) != 0; } } @@ -81,17 +80,16 @@ public static Class getSuperclass(final Class thisObj) { Word klass = loadWordFromObject(thisObj, klassOffset()); if (klass.notEqual(0)) { - int accessFlags = klass.readInt(klassAccessFlagsOffset()); + int accessFlags = klass.readInt(klassAccessFlagsOffset(), FINAL_LOCATION); if ((accessFlags & Modifier.INTERFACE) == 0) { - int layoutHelper = klass.readInt(klassLayoutHelperOffset()); - if ((layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0) { + if ((readLayoutHelper(klass) & arrayKlassLayoutHelperIdentifier()) != 0) { return Object.class; } else { - Word superKlass = klass.readWord(klassSuperKlassOffset()); + Word superKlass = klass.readWord(klassSuperKlassOffset(), FINAL_LOCATION); if (superKlass.equal(0)) { return null; } else { - return unsafeCast(superKlass.readObject(classMirrorOffset()), Class.class, true, true); + return unsafeCast(superKlass.readObject(classMirrorOffset(), FINAL_LOCATION), Class.class, true, true); } } } @@ -103,9 +101,8 @@ public static Class getComponentType(final Class thisObj) { Word klass = loadWordFromObject(thisObj, klassOffset()); if (klass.notEqual(0)) { - int layoutHelper = klass.readInt(klassLayoutHelperOffset()); - if ((layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0) { - return unsafeCast(klass.readObject(arrayKlassComponentMirrorOffset()), Class.class, true, true); + if ((readLayoutHelper(klass) & arrayKlassLayoutHelperIdentifier()) != 0) { + return unsafeCast(klass.readObject(arrayKlassComponentMirrorOffset(), FINAL_LOCATION), Class.class, true, true); } } return null; @@ -113,6 +110,6 @@ @MethodSubstitution(isStatic = false) public static boolean isInstance(final Class thisObj, Object obj) { - return !thisObj.isPrimitive() && ConditionalNode.materializeIsInstance(thisObj, obj); + return !isPrimitive(thisObj) && ConditionalNode.materializeIsInstance(thisObj, obj); } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java Thu Mar 21 14:11:13 2013 +0100 @@ -23,6 +23,7 @@ package com.oracle.graal.hotspot.snippets; import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*; +import sun.misc.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; @@ -33,6 +34,7 @@ import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.snippets.Snippet.Fold; +import com.oracle.graal.snippets.nodes.*; import com.oracle.graal.word.*; //JaCoCo Exclude @@ -42,6 +44,10 @@ */ 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() { return HotSpotGraalRuntime.getInstance().getConfig(); } @@ -56,16 +62,49 @@ return config().verifyOops; } + public static final Object TLAB_TOP_LOCATION = LocationNode.createLocation("TlabTop"); + @Fold public static int threadTlabTopOffset() { return config().threadTlabTopOffset; } + public static final Object TLAB_END_LOCATION = LocationNode.createLocation("TlabEnd"); + @Fold - public static int threadTlabEndOffset() { + private static int threadTlabEndOffset() { return config().threadTlabEndOffset; } + public static final Object TLAB_START_LOCATION = LocationNode.createLocation("TlabStart"); + + @Fold + private static int threadTlabStartOffset() { + return config().threadTlabStartOffset; + } + + public static Word readTlabTop(Word thread) { + return thread.readWord(threadTlabTopOffset(), TLAB_TOP_LOCATION); + } + + public static Word readTlabEnd(Word thread) { + return thread.readWord(threadTlabEndOffset(), TLAB_END_LOCATION); + } + + public static Word readTlabStart(Word thread) { + return thread.readWord(threadTlabStartOffset(), TLAB_START_LOCATION); + } + + public static void writeTlabTop(Word thread, Word top) { + thread.writeWord(threadTlabTopOffset(), top, TLAB_TOP_LOCATION); + } + + public static void initializeTlab(Word thread, Word start, Word end) { + thread.writeWord(threadTlabStartOffset(), start, TLAB_START_LOCATION); + thread.writeWord(threadTlabTopOffset(), start, TLAB_TOP_LOCATION); + thread.writeWord(threadTlabEndOffset(), end, TLAB_END_LOCATION); + } + @Fold public static int threadObjectOffset() { return config().threadObjectOffset; @@ -103,9 +142,11 @@ @Fold public static int pageSize() { - return HotSpotGraalRuntime.getInstance().getTarget().pageSize; + return Unsafe.getUnsafe().pageSize(); } + public static final Object PROTOTYPE_MARK_WORD_LOCATION = LocationNode.createLocation("PrototypeMarkWord"); + @Fold public static int prototypeMarkWordOffset() { return config().prototypeMarkWordOffset; @@ -122,10 +163,14 @@ } @Fold - public static int klassLayoutHelperOffset() { + private static int klassLayoutHelperOffset() { return config().klassLayoutHelperOffset; } + public static int readLayoutHelper(Word hub) { + return hub.readInt(klassLayoutHelperOffset(), FINAL_LOCATION); + } + @Fold public static int arrayKlassLayoutHelperIdentifier() { return config().arrayKlassLayoutHelperIdentifier; @@ -141,11 +186,25 @@ return config().klassSuperKlassOffset; } + public static final Object MARK_WORD_LOCATION = LocationNode.createLocation("MarkWord"); + @Fold public static int markOffset() { return config().markOffset; } + public static final Object HUB_LOCATION = LocationNode.createLocation("Hub"); + + @Fold + private static int hubOffset() { + return config().hubOffset; + } + + public static void initializeObjectHeader(Word memory, Word markWord, Word hub) { + memory.writeWord(markOffset(), markWord, MARK_WORD_LOCATION); + memory.writeWord(hubOffset(), hub, HUB_LOCATION); + } + @Fold public static int unlockedMask() { return config().unlockedMask; @@ -192,11 +251,6 @@ } @Fold - public static int hubOffset() { - return config().hubOffset; - } - - @Fold public static int metaspaceArrayLengthOffset() { return config().metaspaceArrayLengthOffset; } @@ -266,16 +320,22 @@ return config().superCheckOffsetOffset; } + public static final Object SECONDARY_SUPER_CACHE_LOCATION = LocationNode.createLocation("SecondarySuperCache"); + @Fold public static int secondarySuperCacheOffset() { return config().secondarySuperCacheOffset; } + public static final Object SECONDARY_SUPERS_LOCATION = LocationNode.createLocation("SecondarySupers"); + @Fold public static int secondarySupersOffset() { return config().secondarySupersOffset; } + public static final Object DISPLACED_MARK_WORD_LOCATION = LocationNode.createLocation("DisplacedMarkWord"); + @Fold public static int lockDisplacedMarkOffset() { return config().basicLockDisplacedHeaderOffset; @@ -319,22 +379,22 @@ * Gets the value of the stack pointer register as a Word. */ public static Word stackPointer() { - return HotSpotSnippetUtils.registerAsWord(stackPointerRegister()); + return HotSpotSnippetUtils.registerAsWord(stackPointerRegister(), true, false); } /** * Gets the value of the thread register as a Word. */ public static Word thread() { - return HotSpotSnippetUtils.registerAsWord(threadRegister()); + return HotSpotSnippetUtils.registerAsWord(threadRegister(), true, false); } public static Word loadWordFromObject(Object object, int offset) { return loadWordFromObjectIntrinsic(object, 0, offset, wordKind()); } - @NodeIntrinsic(value = RegisterNode.class, setStampFromReturnType = true) - public static native Word registerAsWord(@ConstantNodeParameter Register register); + @NodeIntrinsic(value = ReadRegisterNode.class, setStampFromReturnType = true) + public static native Word registerAsWord(@ConstantNodeParameter Register register, @ConstantNodeParameter boolean directUse, @ConstantNodeParameter boolean incoming); @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true) private static native Word loadWordFromObjectIntrinsic(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind wordKind); @@ -347,12 +407,19 @@ return CodeUtil.log2(wordSize()); } + public static final Object CLASS_STATE_LOCATION = LocationNode.createLocation("ClassState"); + @Fold public static int klassStateOffset() { return config().klassStateOffset; } @Fold + public static int klassStateFullyInitialized() { + return config().klassStateFullyInitialized; + } + + @Fold public static int klassModifierFlagsOffset() { return config().klassModifierFlagsOffset; } @@ -372,22 +439,21 @@ return config().klassInstanceSizeOffset; } + public static final Object HEAP_TOP_LOCATION = LocationNode.createLocation("HeapTop"); + @Fold public static long heapTopAddress() { return config().heapTopAddress; } + public static final Object HEAP_END_LOCATION = LocationNode.createLocation("HeapEnd"); + @Fold public static long heapEndAddress() { return config().heapEndAddress; } @Fold - public static int threadTlabStartOffset() { - return config().threadTlabStartOffset; - } - - @Fold public static long tlabIntArrayMarkWord() { return config().tlabIntArrayMarkWord; } @@ -402,36 +468,43 @@ return config().tlabAlignmentReserve; } + public static final Object TLAB_SIZE_LOCATION = LocationNode.createLocation("TlabSize"); + @Fold public static int threadTlabSizeOffset() { return config().threadTlabSizeOffset; } + public static final Object TLAB_THREAD_ALLOCATED_BYTES_LOCATION = LocationNode.createLocation("TlabThreadAllocatedBytes"); + @Fold public static int threadAllocatedBytesOffset() { return config().threadAllocatedBytesOffset; } - @Fold - public static int klassStateFullyInitialized() { - return config().klassStateFullyInitialized; - } + public static final Object TLAB_REFILL_WASTE_LIMIT_LOCATION = LocationNode.createLocation("RefillWasteLimit"); @Fold public static int tlabRefillWasteLimitOffset() { return config().tlabRefillWasteLimitOffset; } + public static final Object TLAB_NOF_REFILLS_LOCATION = LocationNode.createLocation("TlabNOfRefills"); + @Fold public static int tlabNumberOfRefillsOffset() { return config().tlabNumberOfRefillsOffset; } + public static final Object TLAB_FAST_REFILL_WASTE_LOCATION = LocationNode.createLocation("TlabFastRefillWaste"); + @Fold public static int tlabFastRefillWasteOffset() { return config().tlabFastRefillWasteOffset; } + public static final Object TLAB_SLOW_ALLOCATIONS_LOCATION = LocationNode.createLocation("TlabSlowAllocations"); + @Fold public static int tlabSlowAllocationsOffset() { return config().tlabSlowAllocationsOffset; diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java Thu Mar 21 14:11:13 2013 +0100 @@ -99,7 +99,7 @@ return falseValue; } Word objectHub = loadHub(object); - if (objectHub.readWord(superCheckOffset).notEqual(hub)) { + if (objectHub.readWord(superCheckOffset, FINAL_LOCATION).notEqual(hub)) { probability(NOT_LIKELY_PROBABILITY); displayMiss.inc(); return falseValue; diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java Thu Mar 21 14:11:13 2013 +0100 @@ -40,6 +40,7 @@ import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; 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.nodes.spi.*; @@ -109,7 +110,7 @@ // The bias pattern is present in the object's mark word. Need to check // whether the bias owner and the epoch are both still current. Word hub = loadHub(object); - final Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset()); + final Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); final Word thread = thread(); final Word tmp = prototypeMarkWord.or(thread).xor(mark).and(~ageMaskInPlace()); trace(trace, "prototypeMarkWord: 0x%016lx\n", prototypeMarkWord); @@ -154,7 +155,7 @@ Word biasedMark = unbiasedMark.or(thread); trace(trace, " unbiasedMark: 0x%016lx\n", unbiasedMark); trace(trace, " biasedMark: 0x%016lx\n", biasedMark); - if (compareAndSwap(object, markOffset(), unbiasedMark, biasedMark).equal(unbiasedMark)) { + if (compareAndSwap(object, markOffset(), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark)) { // Object is now biased to current thread -> done traceObject(trace, "+lock{bias:acquired}", object); return; @@ -175,7 +176,7 @@ // the bias from one thread to another directly in this situation. Word biasedMark = prototypeMarkWord.or(thread); trace(trace, " biasedMark: 0x%016lx\n", biasedMark); - if (compareAndSwap(object, markOffset(), mark, biasedMark).equal(mark)) { + if (compareAndSwap(object, markOffset(), mark, biasedMark, MARK_WORD_LOCATION).equal(mark)) { // Object is now biased to current thread -> done traceObject(trace, "+lock{bias:transfer}", object); return; @@ -197,7 +198,7 @@ // that another thread raced us for the privilege of revoking the // bias of this particular object, so it's okay to continue in the // normal locking code. - Word result = compareAndSwap(object, markOffset(), mark, prototypeMarkWord); + Word result = compareAndSwap(object, markOffset(), mark, prototypeMarkWord, MARK_WORD_LOCATION); // Fall through to the normal CAS-based lock, because no matter what // the result of the above CAS, some thread must have succeeded in @@ -215,11 +216,11 @@ trace(trace, " unlockedMark: 0x%016lx\n", unlockedMark); // Copy this unlocked mark word into the lock slot on the stack - lock.writeWord(lockDisplacedMarkOffset(), unlockedMark); + lock.writeWord(lockDisplacedMarkOffset(), unlockedMark, DISPLACED_MARK_WORD_LOCATION); // Test if the object's mark word is unlocked, and if so, store the // (address of) the lock slot into the object's mark word. - Word currentMark = compareAndSwap(object, markOffset(), unlockedMark, lock); + Word currentMark = compareAndSwap(object, markOffset(), unlockedMark, lock, MARK_WORD_LOCATION); if (currentMark.notEqual(unlockedMark)) { trace(trace, " currentMark: 0x%016lx\n", currentMark); // The mark word in the object header was not the same. @@ -247,7 +248,7 @@ return; } else { // Recursively locked => write 0 to the lock slot - lock.writeWord(lockDisplacedMarkOffset(), Word.zero()); + lock.writeWord(lockDisplacedMarkOffset(), Word.zero(), DISPLACED_MARK_WORD_LOCATION); traceObject(trace, "+lock{recursive}", object); } } else { @@ -302,7 +303,7 @@ final Word lock = CurrentLockNode.currentLock(); // Load displaced mark - final Word displacedMark = lock.readWord(lockDisplacedMarkOffset()); + final Word displacedMark = lock.readWord(lockDisplacedMarkOffset(), DISPLACED_MARK_WORD_LOCATION); trace(trace, " displacedMark: 0x%016lx\n", displacedMark); if (displacedMark.equal(0)) { @@ -313,7 +314,7 @@ // Test if object's mark word is pointing to the displaced mark word, and if so, restore // the displaced mark in the object - if the object's mark word is not pointing to // the displaced mark word, do unlocking via runtime call. - if (DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark).notEqual(lock)) { + if (DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark, MARK_WORD_LOCATION).notEqual(lock)) { // The object's mark word was not pointing to the displaced header, // we do unlocking via runtime call. probability(DEOPT_PATH_PROBABILITY); @@ -365,35 +366,37 @@ */ private static final boolean ENABLE_BREAKPOINT = false; + private static final Object MONITOR_COUNTER_LOCATION = LocationNode.createLocation("MonitorCounter"); + @NodeIntrinsic(BreakpointNode.class) static native void bkpt(Object object, Word mark, Word tmp, Word value); private static void incCounter() { if (CHECK_BALANCED_MONITORS) { final Word counter = MonitorCounterNode.counter(); - final int count = counter.readInt(0); - counter.writeInt(0, count + 1); + final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION); + counter.writeInt(0, count + 1, MONITOR_COUNTER_LOCATION); } } private static void decCounter() { if (CHECK_BALANCED_MONITORS) { final Word counter = MonitorCounterNode.counter(); - final int count = counter.readInt(0); - counter.writeInt(0, count - 1); + final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION); + counter.writeInt(0, count - 1, MONITOR_COUNTER_LOCATION); } } @Snippet private static void initCounter() { final Word counter = MonitorCounterNode.counter(); - counter.writeInt(0, 0); + counter.writeInt(0, 0, MONITOR_COUNTER_LOCATION); } @Snippet private static void checkCounter(String errMsg) { final Word counter = MonitorCounterNode.counter(); - final int count = counter.readInt(0); + final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION); if (count != 0) { vmError(errMsg, count); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java Thu Mar 21 14:11:13 2013 +0100 @@ -62,13 +62,13 @@ @Snippet public static Word allocate(@Parameter("size") int size) { Word thread = thread(); - Word top = thread.readWord(threadTlabTopOffset()); - Word end = thread.readWord(threadTlabEndOffset()); + 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) if (newTop.belowOrEqual(end)) { probability(FAST_PATH_PROBABILITY); - thread.writeWord(threadTlabTopOffset(), newTop); + writeTlabTop(thread, newTop); return top; } return Word.zero(); @@ -178,7 +178,7 @@ Word dims = DimensionsNode.allocaDimsArray(rank); ExplodeLoopNode.explodeLoop(); for (int i = 0; i < rank; i++) { - dims.writeInt(i * 4, dimensions[i]); + dims.writeInt(i * 4, dimensions[i], ANY_LOCATION); } return NewMultiArrayStubCall.call(hub, rank, dims); } @@ -194,20 +194,19 @@ * Formats some allocated memory with an object header zeroes out the rest. */ private static void formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents) { - Word prototypeMarkWord = useBiasedLocking() ? hub.readWord(prototypeMarkWordOffset()) : compileTimePrototypeMarkWord; - memory.writeWord(markOffset(), prototypeMarkWord); - memory.writeWord(hubOffset(), hub); + Word prototypeMarkWord = useBiasedLocking() ? hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord; + initializeObjectHeader(memory, prototypeMarkWord, hub); if (fillContents) { if (size <= MAX_UNROLLED_OBJECT_ZEROING_SIZE) { new_seqInit.inc(); explodeLoop(); for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) { - memory.writeWord(offset, Word.zero()); + memory.writeWord(offset, Word.zero(), ANY_LOCATION); } } else { new_loopInit.inc(); for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) { - memory.writeWord(offset, Word.zero()); + memory.writeWord(offset, Word.zero(), ANY_LOCATION); } } } @@ -217,13 +216,12 @@ * Formats some allocated memory with an object header zeroes out the rest. */ public static void formatArray(Word hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents) { - memory.writeWord(markOffset(), prototypeMarkWord); - memory.writeInt(arrayLengthOffset(), length); + memory.writeInt(arrayLengthOffset(), length, ANY_LOCATION); // store hub last as the concurrent garbage collectors assume length is valid if hub field is not null - memory.writeWord(hubOffset(), hub); + initializeObjectHeader(memory, prototypeMarkWord, hub); if (fillContents) { for (int offset = headerSize; offset < allocationSize; offset += wordSize()) { - memory.writeWord(offset, Word.zero()); + memory.writeWord(offset, Word.zero(), ANY_LOCATION); } } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -26,7 +26,6 @@ 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.java.*; @@ -34,7 +33,6 @@ import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; -import com.oracle.graal.phases.common.*; import com.oracle.graal.snippets.nodes.*; public class ObjectCloneNode extends MacroNode implements VirtualizableAllocation, ArrayLengthProvider { @@ -52,33 +50,30 @@ return arguments.get(0); } - private Method selectSnippetMethod(LoweringTool tool) { - ResolvedJavaType type = getObject().objectStamp().type(); - if (type.isArray()) { - return ObjectCloneSnippets.arrayCloneMethod; - } else if (type.isAssignableFrom(tool.getRuntime().lookupJavaType(Object[].class))) { - // arrays are assignable to Object, Cloneable and Serializable - return ObjectCloneSnippets.genericCloneMethod; - } else { - return ObjectCloneSnippets.instanceCloneMethod; - } - } - @Override - public void lower(LoweringTool tool) { + protected StructuredGraph getSnippetGraph(LoweringTool tool) { if (!GraalOptions.IntrinsifyObjectClone) { - super.lower(tool); - return; - } - ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(selectSnippetMethod(tool)); - if (Debug.isLogEnabled()) { - Debug.log("%s > Intrinsify (%s)", Debug.currentScope(), snippetMethod.getSignature().getParameterType(0, snippetMethod.getDeclaringClass()).getComponentType()); + return null; } + ResolvedJavaType type = getObject().objectStamp().type(); + Method method; + /* + * The first condition tests if the parameter is an array, the second condition tests if the + * parameter can be an array. Otherwise, the parameter is known to be a non-array object. + */ + if (type.isArray()) { + method = ObjectCloneSnippets.arrayCloneMethod; + } else if (type == null || type.isAssignableFrom(tool.getRuntime().lookupJavaType(Object[].class))) { + method = ObjectCloneSnippets.genericCloneMethod; + } else { + method = ObjectCloneSnippets.instanceCloneMethod; + } + ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(method); StructuredGraph snippetGraph = (StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class); + assert snippetGraph != null : "ObjectCloneSnippets should be installed"; - InvokeNode invoke = replaceWithInvoke(); - InliningUtil.inline(invoke, snippetGraph, false); + return snippetGraph; } private static boolean isCloneableType(ResolvedJavaType type, MetaAccessProvider metaAccess) { @@ -86,7 +81,7 @@ } private static ResolvedJavaType getConcreteType(ObjectStamp stamp, Assumptions assumptions) { - if (stamp.isExactType()) { + if (stamp.isExactType() || stamp.type() == null) { return stamp.type(); } else { ResolvedJavaType type = stamp.type().findUniqueConcreteSubtype(); @@ -121,14 +116,15 @@ ResolvedJavaType type = getConcreteType(obj.objectStamp(), tool.getAssumptions()); if (isCloneableType(type, tool.getMetaAccessProvider())) { if (!type.isArray()) { - ResolvedJavaField[] fields = type.getInstanceFields(true); + VirtualInstanceNode newVirtual = new VirtualInstanceNode(type); + ResolvedJavaField[] fields = newVirtual.getFields(); + ValueNode[] state = new ValueNode[fields.length]; final LoadFieldNode[] loads = new LoadFieldNode[fields.length]; for (int i = 0; i < fields.length; i++) { state[i] = loads[i] = graph().add(new LoadFieldNode(obj, fields[i])); } - VirtualObjectNode newVirtual = new VirtualInstanceNode(type, fields); final StructuredGraph structuredGraph = (StructuredGraph) graph(); tool.customAction(new Runnable() { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneSnippets.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneSnippets.java Thu Mar 21 14:11:13 2013 +0100 @@ -53,12 +53,12 @@ private static Object instanceClone(Object src, Word hub, int layoutHelper) { int instanceSize = layoutHelper; Pointer memory = NewObjectSnippets.allocate(instanceSize); - Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset()); + Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); Object result = NewObjectSnippets.initializeObject((Word) memory, hub, prototypeMarkWord, instanceSize, false, false); memory = Word.fromObject(result); for (int offset = 2 * wordSize(); offset < instanceSize; offset += wordSize()) { - memory.writeWord(offset, Word.fromObject(src).readWord(offset)); + memory.writeWord(offset, Word.fromObject(src).readWord(offset, UNKNOWN_LOCATION), ANY_LOCATION); } return result; @@ -71,12 +71,12 @@ int sizeInBytes = NewObjectSnippets.computeArrayAllocationSize(arrayLength, wordSize(), headerSize, log2ElementSize); Pointer memory = NewObjectSnippets.allocate(sizeInBytes); - Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset()); + Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); Object result = NewObjectSnippets.initializeArray((Word) memory, hub, arrayLength, sizeInBytes, prototypeMarkWord, headerSize, false, false); memory = Word.fromObject(result); for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) { - memory.writeWord(offset, Word.fromObject(src).readWord(offset)); + memory.writeWord(offset, Word.fromObject(src).readWord(offset, UNKNOWN_LOCATION), ANY_LOCATION); } return result; } @@ -94,14 +94,14 @@ public static Object instanceClone(Object src) { instanceCloneCounter.inc(); Word hub = getAndCheckHub(src); - return instanceClone(src, hub, hub.readInt(layoutHelperOffset())); + return instanceClone(src, hub, hub.readInt(layoutHelperOffset(), FINAL_LOCATION)); } @Snippet public static Object arrayClone(Object src) { arrayCloneCounter.inc(); Word hub = getAndCheckHub(src); - int layoutHelper = hub.readInt(layoutHelperOffset()); + int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION); return arrayClone(src, hub, layoutHelper); } @@ -109,7 +109,7 @@ public static Object genericClone(Object src) { genericCloneCounter.inc(); Word hub = getAndCheckHub(src); - int layoutHelper = hub.readInt(layoutHelperOffset()); + int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION); if (layoutHelper < 0) { probability(LIKELY_PROBABILITY); genericArrayCloneCounter.inc(); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSubstitutions.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSubstitutions.java Thu Mar 21 14:11:13 2013 +0100 @@ -25,8 +25,10 @@ import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.snippets.*; -import com.oracle.graal.snippets.ClassSubstitution.*; +import com.oracle.graal.snippets.ClassSubstitution.MacroSubstitution; +import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution; import com.oracle.graal.word.*; /** @@ -38,7 +40,7 @@ @MethodSubstitution(isStatic = false) public static Class getClass(final Object thisObj) { Word hub = loadHub(thisObj); - return unsafeCast(hub.readFinalObject(Word.signed(classMirrorOffset())), Class.class, true, true); + return unsafeCast(hub.readObject(Word.signed(classMirrorOffset()), LocationNode.FINAL_LOCATION), Class.class, true, true); } @MethodSubstitution(isStatic = false) diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ThreadSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ThreadSubstitutions.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ThreadSubstitutions.java Thu Mar 21 14:11:13 2013 +0100 @@ -43,10 +43,10 @@ @MethodSubstitution(isStatic = false) private static boolean isInterrupted(final Thread thisObject, boolean clearInterrupted) { Word rawThread = HotSpotCurrentRawThreadNode.get(); - Thread thread = (Thread) rawThread.readObject(threadObjectOffset()); + Thread thread = (Thread) rawThread.readObject(threadObjectOffset(), FINAL_LOCATION); if (thisObject == thread) { - Word osThread = rawThread.readWord(osThreadOffset()); - boolean interrupted = osThread.readInt(osThreadInterruptedOffset()) != 0; + Word osThread = rawThread.readWord(osThreadOffset(), FINAL_LOCATION); + boolean interrupted = osThread.readInt(osThreadInterruptedOffset(), UNKNOWN_LOCATION) != 0; if (!interrupted || !clearInterrupted) { return interrupted; } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/TypeCheckSnippetUtils.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/TypeCheckSnippetUtils.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/TypeCheckSnippetUtils.java Thu Mar 21 14:11:13 2013 +0100 @@ -30,6 +30,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.phases.*; import com.oracle.graal.snippets.*; import com.oracle.graal.word.*; @@ -39,9 +40,11 @@ */ public class TypeCheckSnippetUtils { + public static final Object TYPE_DISPLAY_LOCATION = LocationNode.createLocation("TypeDisplay"); + static boolean checkSecondarySubType(Word t, Word s) { // if (S.cache == T) return true - if (s.readWord(secondarySuperCacheOffset()).equal(t)) { + if (s.readWord(secondarySuperCacheOffset(), SECONDARY_SUPER_CACHE_LOCATION).equal(t)) { cacheHit.inc(); return true; } @@ -51,11 +54,11 @@ static boolean checkUnknownSubType(Word t, Word s) { // int off = T.offset - int superCheckOffset = t.readInt(superCheckOffsetOffset()); + int superCheckOffset = t.readInt(superCheckOffsetOffset(), FINAL_LOCATION); boolean primary = superCheckOffset != secondarySuperCacheOffset(); // if (T = S[off]) return true - if (s.readWord(superCheckOffset).equal(t)) { + if (s.readWord(superCheckOffset, TYPE_DISPLAY_LOCATION).equal(t)) { if (primary) { cacheHit.inc(); } else { @@ -81,12 +84,12 @@ } // if (S.scan_s_s_array(T)) { S.cache = T; return true; } - Word secondarySupers = s.readWord(secondarySupersOffset()); - int length = secondarySupers.readInt(metaspaceArrayLengthOffset()); + Word secondarySupers = s.readWord(secondarySupersOffset(), SECONDARY_SUPERS_LOCATION); + int length = secondarySupers.readInt(metaspaceArrayLengthOffset(), FINAL_LOCATION); for (int i = 0; i < length; i++) { - if (t.equal(loadWordElement(secondarySupers, i))) { + if (t.equal(loadSecondarySupersElement(secondarySupers, i))) { probability(NOT_LIKELY_PROBABILITY); - s.writeWord(secondarySuperCacheOffset(), t); + s.writeWord(secondarySuperCacheOffset(), t, SECONDARY_SUPER_CACHE_LOCATION); secondariesHit.inc(); return true; } @@ -103,8 +106,8 @@ return hintHubs; } - static Word loadWordElement(Word metaspaceArray, int index) { - return metaspaceArray.readWord(metaspaceArrayBaseOffset() + index * wordSize()); + static Word loadSecondarySupersElement(Word metaspaceArray, int index) { + return metaspaceArray.readWord(metaspaceArrayBaseOffset() + index * wordSize(), FINAL_LOCATION); } private static final SnippetCounter.Group counters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("TypeCheck") : null; diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Thu Mar 21 14:11:13 2013 +0100 @@ -67,7 +67,7 @@ */ @Snippet private static Object newArray(@Parameter("hub") Word hub, @Parameter("length") int length, @ConstantParameter("intArrayHub") Word intArrayHub, @ConstantParameter("log") boolean log) { - int layoutHelper = hub.readInt(layoutHelperOffset()); + int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION); int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); int elementKind = (layoutHelper >> layoutHelperElementTypeShift()) & layoutHelperElementTypeMask(); diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Thu Mar 21 14:11:13 2013 +0100 @@ -67,16 +67,15 @@ */ @Snippet private static Object newInstance(@Parameter("hub") Word hub, @ConstantParameter("intArrayHub") Word intArrayHub, @ConstantParameter("log") boolean log) { - int sizeInBytes = hub.readInt(klassInstanceSizeOffset()); + int sizeInBytes = hub.readInt(klassInstanceSizeOffset(), FINAL_LOCATION); if (!forceSlowPath() && inlineContiguousAllocationSupported()) { - if (hub.readInt(klassStateOffset()) == klassStateFullyInitialized()) { + if (hub.readInt(klassStateOffset(), CLASS_STATE_LOCATION) == klassStateFullyInitialized()) { Word memory = refillAllocate(intArrayHub, sizeInBytes, log); if (memory.notEqual(0)) { - Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset()); - memory.writeWord(markOffset(), prototypeMarkWord); - memory.writeWord(hubOffset(), hub); + Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); + initializeObjectHeader(memory, prototypeMarkWord, hub); for (int offset = 2 * wordSize(); offset < sizeInBytes; offset += wordSize()) { - memory.writeWord(offset, Word.zero()); + memory.writeWord(offset, Word.zero(), ANY_LOCATION); } return verifyOop(memory.toObject()); } @@ -105,8 +104,8 @@ int alignmentReserveInBytes = tlabAlignmentReserveInHeapWords() * wordSize(); Word thread = thread(); - Word top = thread.readWord(threadTlabTopOffset()); - Word end = thread.readWord(threadTlabEndOffset()); + Word top = readTlabTop(thread); + Word end = readTlabEnd(thread); // calculate amount of free space Word tlabFreeSpaceInBytes = end.subtract(top); @@ -120,16 +119,16 @@ // Retain TLAB and allocate object in shared space if // the amount free in the TLAB is too large to discard. - Word refillWasteLimit = thread.readWord(tlabRefillWasteLimitOffset()); + Word refillWasteLimit = thread.readWord(tlabRefillWasteLimitOffset(), TLAB_REFILL_WASTE_LIMIT_LOCATION); if (tlabFreeSpaceInWords.belowOrEqual(refillWasteLimit)) { if (tlabStats()) { // increment number of refills - thread.writeInt(tlabNumberOfRefillsOffset(), thread.readInt(tlabNumberOfRefillsOffset()) + 1); - log(log, "thread: %p -- number_of_refills %d\n", thread, thread.readInt(tlabNumberOfRefillsOffset())); + thread.writeInt(tlabNumberOfRefillsOffset(), thread.readInt(tlabNumberOfRefillsOffset(), TLAB_NOF_REFILLS_LOCATION) + 1, TLAB_NOF_REFILLS_LOCATION); + log(log, "thread: %p -- number_of_refills %d\n", thread, thread.readInt(tlabNumberOfRefillsOffset(), TLAB_NOF_REFILLS_LOCATION)); // accumulate wastage - Word wastage = thread.readWord(tlabFastRefillWasteOffset()).add(tlabFreeSpaceInWords); + Word wastage = thread.readWord(tlabFastRefillWasteOffset(), TLAB_FAST_REFILL_WASTE_LOCATION).add(tlabFreeSpaceInWords); log(log, "thread: %p -- accumulated wastage %d\n", thread, wastage); - thread.writeWord(tlabFastRefillWasteOffset(), wastage); + thread.writeWord(tlabFastRefillWasteOffset(), wastage, TLAB_FAST_REFILL_WASTE_LOCATION); } // if TLAB is currently allocated (top or end != null) then @@ -142,22 +141,19 @@ int length = ((alignmentReserveInBytes - headerSize) >>> 2) + tlabFreeSpaceInInts; NewObjectSnippets.formatArray(intArrayHub, -1, length, headerSize, top, intArrayMarkWord, false); - Word allocated = thread.readWord(threadAllocatedBytesOffset()); - allocated = allocated.add(top.subtract(thread.readWord(threadTlabStartOffset()))); - thread.writeWord(threadAllocatedBytesOffset(), allocated); + Word allocated = thread.readWord(threadAllocatedBytesOffset(), TLAB_THREAD_ALLOCATED_BYTES_LOCATION); + allocated = allocated.add(top.subtract(readTlabStart(thread))); + thread.writeWord(threadAllocatedBytesOffset(), allocated, TLAB_THREAD_ALLOCATED_BYTES_LOCATION); } // refill the TLAB with an eden allocation - Word tlabRefillSizeInWords = thread.readWord(threadTlabSizeOffset()); + Word tlabRefillSizeInWords = thread.readWord(threadTlabSizeOffset(), TLAB_SIZE_LOCATION); Word tlabRefillSizeInBytes = tlabRefillSizeInWords.multiply(wordSize()); // allocate new TLAB, address returned in top top = edenAllocate(tlabRefillSizeInBytes, log); if (top.notEqual(0)) { - thread.writeWord(threadTlabStartOffset(), top); - thread.writeWord(threadTlabTopOffset(), top); - end = top.add(tlabRefillSizeInBytes.subtract(alignmentReserveInBytes)); - thread.writeWord(threadTlabEndOffset(), end); + initializeTlab(thread, top, end); return allocate(sizeInBytes); } else { @@ -166,11 +162,11 @@ } else { // Retain TLAB Word newRefillWasteLimit = refillWasteLimit.add(tlabRefillWasteIncrement()); - thread.writeWord(tlabRefillWasteLimitOffset(), newRefillWasteLimit); + thread.writeWord(tlabRefillWasteLimitOffset(), newRefillWasteLimit, TLAB_REFILL_WASTE_LIMIT_LOCATION); log(log, "refillTLAB: retaining TLAB - newRefillWasteLimit=%p\n", newRefillWasteLimit); if (tlabStats()) { - thread.writeInt(tlabSlowAllocationsOffset(), thread.readInt(tlabSlowAllocationsOffset()) + 1); + thread.writeInt(tlabSlowAllocationsOffset(), thread.readInt(tlabSlowAllocationsOffset(), TLAB_SLOW_ALLOCATIONS_LOCATION) + 1, TLAB_SLOW_ALLOCATIONS_LOCATION); } return edenAllocate(Word.unsigned(sizeInBytes), log); @@ -189,18 +185,18 @@ Word heapEndAddress = Word.unsigned(heapEndAddress()); while (true) { - Word heapTop = heapTopAddress.readWord(0); + Word heapTop = heapTopAddress.readWord(0, HEAP_TOP_LOCATION); Word newHeapTop = heapTop.add(sizeInBytes); if (newHeapTop.belowOrEqual(heapTop)) { return Word.zero(); } - Word heapEnd = heapEndAddress.readWord(0); + Word heapEnd = heapEndAddress.readWord(0, HEAP_END_LOCATION); if (newHeapTop.aboveThan(heapEnd)) { return Word.zero(); } - if (compareAndSwap(heapTopAddress, 0, heapTop, newHeapTop).equal(heapTop)) { + if (compareAndSwap(heapTopAddress, 0, heapTop, newHeapTop, HEAP_TOP_LOCATION).equal(heapTop)) { return heapTop; } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java Thu Mar 21 14:11:13 2013 +0100 @@ -31,6 +31,7 @@ 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.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.hotspot.*; @@ -69,8 +70,8 @@ protected InstalledCode stubCode; /** - * Creates a new stub container. The new stub still needs to be - * {@linkplain #install(GraalCompiler) installed}. + * Creates a new stub container. The new stub still needs to be {@linkplain #install(Backend) + * installed}. * * @param descriptor linkage details for a call to the stub */ @@ -106,7 +107,7 @@ * Compiles the code for this stub, installs it and initializes the address used for calls to * it. */ - public void install(GraalCompiler compiler) { + public void install(Backend backend) { StructuredGraph graph = (StructuredGraph) stubMethod.getCompilerStorage().get(Graph.class); Key key = new Key(stubMethod); @@ -117,24 +118,24 @@ PhasePlan phasePlan = new PhasePlan(); GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL); phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase); - final CompilationResult compResult = compiler.compileMethod(stubMethod, graph, null, phasePlan, OptimisticOptimizations.ALL); + final CompilationResult compResult = GraalCompiler.compileMethod(runtime(), backend, runtime().getTarget(), stubMethod, graph, null, phasePlan, OptimisticOptimizations.ALL, + new SpeculationLog()); - final CodeInfo[] info = new CodeInfo[1]; - stubCode = Debug.scope("CodeInstall", new Object[]{compiler, stubMethod}, new Callable() { + stubCode = Debug.scope("CodeInstall", new Object[]{runtime(), stubMethod}, new Callable() { @Override public InstalledCode call() { - InstalledCode installedCode = runtime().addMethod(stubMethod, compResult, info); + InstalledCode installedCode = runtime().addMethod(stubMethod, compResult); assert installedCode != null : "error installing stub " + stubMethod; if (Debug.isDumpEnabled()) { - Debug.dump(new Object[]{compResult, info[0]}, "After code installation"); + Debug.dump(new Object[]{compResult, installedCode}, "After code installation"); } return installedCode; } }); assert stubCode != null : "error installing stub " + stubMethod; - linkage.setAddress(info[0].getStart()); + linkage.setAddress(stubCode.getStart()); } /** diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Thu Mar 21 14:11:13 2013 +0100 @@ -345,7 +345,8 @@ case INVOKEINTERFACE: case INVOKESPECIAL: case INVOKESTATIC: - case INVOKEVIRTUAL: { + case INVOKEVIRTUAL: + case INVOKEDYNAMIC: { current = null; addSuccessor(bci, makeBlock(stream.nextBCI())); ExceptionDispatchBlock handler = handleExceptions(bci); @@ -757,7 +758,7 @@ if (blockChanged) { block.localsLiveIn.clear(); block.localsLiveIn.or(block.localsLiveOut); - block.localsLiveIn.xor(block.localsLiveKill); + block.localsLiveIn.andNot(block.localsLiveKill); block.localsLiveIn.or(block.localsLiveGen); Debug.log(" end B%d [%d, %d] in: %s out: %s gen: %s kill: %s", block.blockID, block.startBci, block.endBci, block.localsLiveIn, block.localsLiveOut, block.localsLiveGen, block.localsLiveKill); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java Thu Mar 21 14:11:13 2013 +0100 @@ -203,16 +203,16 @@ } private void propagateDelete(FloatingNode node) { - assert node instanceof PhiNode || node instanceof ValueProxyNode; + assert node instanceof PhiNode || node instanceof ProxyNode; if (node.isDeleted()) { return; } // Collect all phi functions that use this phi so that we can delete them recursively (after // we delete ourselves to avoid circles). - List propagateUsages = node.usages().filter(FloatingNode.class).filter(isA(PhiNode.class).or(ValueProxyNode.class)).snapshot(); + List propagateUsages = node.usages().filter(FloatingNode.class).filter(isA(PhiNode.class).or(ProxyNode.class)).snapshot(); // Remove the phi function from all FrameStates where it is used and then delete it. - assert node.usages().filter(isNotA(FrameState.class).nor(PhiNode.class).nor(ValueProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states"; + assert node.usages().filter(isNotA(FrameState.class).nor(PhiNode.class).nor(ProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states"; node.replaceAtUsages(null); node.safeDelete(); @@ -235,21 +235,21 @@ ValueNode value = localAt(i); if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { Debug.log(" inserting proxy for %s", value); - storeLocal(i, graph.unique(new ValueProxyNode(value, loopExit, PhiType.Value))); + storeLocal(i, graph.unique(new ProxyNode(value, loopExit, PhiType.Value))); } } for (int i = 0; i < stackSize(); i++) { ValueNode value = stackAt(i); if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { Debug.log(" inserting proxy for %s", value); - storeStack(i, graph.unique(new ValueProxyNode(value, loopExit, PhiType.Value))); + storeStack(i, graph.unique(new ProxyNode(value, loopExit, PhiType.Value))); } } for (int i = 0; i < locks.length; i++) { ValueNode value = locks[i]; if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { Debug.log(" inserting proxy for %s", value); - locks[i] = graph.unique(new ValueProxyNode(value, loopExit, PhiType.Value)); + locks[i] = graph.unique(new ProxyNode(value, loopExit, PhiType.Value)); } } } @@ -259,21 +259,21 @@ ValueNode value = localAt(i); if (value != null) { Debug.log(" inserting proxy for %s", value); - storeLocal(i, graph.unique(new ValueProxyNode(value, begin, PhiType.Value))); + storeLocal(i, graph.unique(new ProxyNode(value, begin, PhiType.Value))); } } for (int i = 0; i < stackSize(); i++) { ValueNode value = stackAt(i); if (value != null) { Debug.log(" inserting proxy for %s", value); - storeStack(i, graph.unique(new ValueProxyNode(value, begin, PhiType.Value))); + storeStack(i, graph.unique(new ProxyNode(value, begin, PhiType.Value))); } } for (int i = 0; i < locks.length; i++) { ValueNode value = locks[i]; if (value != null) { Debug.log(" inserting proxy for %s", value); - locks[i] = graph.unique(new ValueProxyNode(value, begin, PhiType.Value)); + locks[i] = graph.unique(new ProxyNode(value, begin, PhiType.Value)); } } } @@ -292,7 +292,7 @@ public void cleanupDeletedPhis() { for (int i = 0; i < localsSize(); i++) { if (localAt(i) != null && localAt(i).isDeleted()) { - assert localAt(i) instanceof PhiNode || localAt(i) instanceof ValueProxyNode : "Only phi and value proxies can be deleted during parsing: " + localAt(i); + assert localAt(i) instanceof PhiNode || localAt(i) instanceof ProxyNode : "Only phi and value proxies can be deleted during parsing: " + localAt(i); storeLocal(i, null); } } @@ -479,15 +479,6 @@ } /** - * Pushes a value onto the stack and checks that it is a JSR return address. - * - * @param x the instruction to push onto the stack - */ - public void jpush(ValueNode x) { - xpush(assertJsr(x)); - } - - /** * Pushes a value onto the stack and checks that it is a long. * * @param x the instruction to push onto the stack @@ -566,15 +557,6 @@ } /** - * Pops a value off of the stack and checks that it is a JSR return address. - * - * @return x the instruction popped off the stack - */ - public ValueNode jpop() { - return assertJsr(xpop()); - } - - /** * Pops a value off of the stack and checks that it is a long. * * @return x the instruction popped off the stack diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java Thu Mar 21 14:11:13 2013 +0100 @@ -23,21 +23,16 @@ package com.oracle.graal.java; import com.oracle.graal.api.meta.*; -import com.oracle.graal.phases.*; public class GraphBuilderConfiguration { - public static enum ResolvePolicy { - Default, EagerForSnippets, Eager, - } - - private final ResolvePolicy resolving; - private final PhasePlan plan; + private final boolean eagerResolving; + private final boolean omitAllExceptionEdges; private ResolvedJavaType[] skippedExceptionTypes; - public GraphBuilderConfiguration(ResolvePolicy resolving, PhasePlan plan) { - this.resolving = resolving; - this.plan = plan; + protected GraphBuilderConfiguration(boolean eagerResolving, boolean omitAllExceptionEdges) { + this.eagerResolving = eagerResolving; + this.omitAllExceptionEdges = omitAllExceptionEdges; } public void setSkippedExceptionTypes(ResolvedJavaType[] skippedExceptionTypes) { @@ -48,31 +43,32 @@ return skippedExceptionTypes; } - public boolean eagerResolvingForSnippets() { - return (resolving == ResolvePolicy.EagerForSnippets || resolving == ResolvePolicy.Eager); + public boolean eagerResolving() { + return eagerResolving; } - public boolean eagerResolving() { - return (resolving == ResolvePolicy.Eager); - } - - public PhasePlan plan() { - return plan; + public boolean omitAllExceptionEdges() { + return omitAllExceptionEdges; } public static GraphBuilderConfiguration getDefault() { - return getDefault(null); + return new GraphBuilderConfiguration(false, false); } - public static GraphBuilderConfiguration getDefault(PhasePlan plan) { - return new GraphBuilderConfiguration(ResolvePolicy.Default, plan); + public static GraphBuilderConfiguration getEagerDefault() { + return new GraphBuilderConfiguration(true, false); } public static GraphBuilderConfiguration getSnippetDefault() { - return getSnippetDefault(null); + return new GraphBuilderConfiguration(true, true); } - public static GraphBuilderConfiguration getSnippetDefault(PhasePlan plan) { - return new GraphBuilderConfiguration(ResolvePolicy.EagerForSnippets, plan); + /** + * 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 dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.java; +import static com.oracle.graal.api.code.DeoptimizationAction.*; +import static com.oracle.graal.api.meta.DeoptimizationReason.*; import static com.oracle.graal.bytecode.Bytecodes.*; import static java.lang.reflect.Modifier.*; @@ -52,7 +54,7 @@ /** * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph. */ -public final class GraphBuilderPhase extends Phase { +public class GraphBuilderPhase extends Phase { public static final class RuntimeCalls { @@ -72,7 +74,7 @@ */ public static final int TRACELEVEL_STATE = 2; - private StructuredGraph currentGraph; + protected StructuredGraph currentGraph; private final MetaAccessProvider runtime; private ConstantPool constantPool; @@ -82,7 +84,7 @@ private BytecodeStream stream; // the bytecode stream - private FrameStateBuilder frameState; // the current execution state + protected FrameStateBuilder frameState; // the current execution state private Block currentBlock; private ValueNode methodSynchronizedObject; @@ -114,6 +116,20 @@ private Block[] loopHeaders; + /** + * Gets the current frame state being processed by this builder. + */ + protected FrameStateBuilder getCurrentFrameState() { + return frameState; + } + + /** + * Gets the graph being processed by this builder. + */ + protected StructuredGraph getGraph() { + return currentGraph; + } + public GraphBuilderPhase(MetaAccessProvider runtime, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) { this.graphBuilderConfig = graphBuilderConfig; this.optimisticOpts = optimisticOpts; @@ -182,11 +198,12 @@ currentBlock = blockMap.startBlock; blockMap.startBlock.entryState = frameState; if (blockMap.startBlock.isLoopHeader) { - // TODO(lstadler,gduboscq) createTarget might not be safe at this position, since it - // expects currentBlock, - // etc. to be set up correctly. A better solution to this problem of start blocks that - // are loop headers - // would be to create a dummy block in BciBlockMapping. + /* + * TODO(lstadler,gduboscq) createTarget might not be safe at this position, since it + * expects currentBlock, etc. to be set up correctly. A better solution to this problem + * of start blocks that are loop headers would be to create a dummy block in + * BciBlockMapping. + */ appendGoto(createTarget(blockMap.startBlock, frameState)); } else { blockMap.startBlock.firstInstruction = lastInstr; @@ -260,6 +277,99 @@ return handler.catchTypeCPI() == 0; } + /** + * @param type the unresolved type of the constant + */ + protected void handleUnresolvedLoadConstant(JavaType type) { + append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved))); + frameState.push(Kind.Object, append(ConstantNode.forObject(null, runtime, currentGraph))); + } + + /** + * @param type the unresolved type of the type check + * @param object the object value whose type is being checked against {@code type} + */ + protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) { + append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(object)), Unresolved, InvalidateRecompile))); + frameState.apush(appendConstant(Constant.NULL_OBJECT)); + } + + /** + * @param type the unresolved type of the type check + * @param object the object value whose type is being checked against {@code type} + */ + protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) { + BlockPlaceholderNode successor = currentGraph.add(new BlockPlaceholderNode()); + DeoptimizeNode deopt = currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new IsNullNode(object)), successor, deopt, 1)); + append(ifNode); + lastInstr = successor; + frameState.ipush(appendConstant(Constant.INT_0)); + } + + /** + * @param type the type being instantiated + */ + protected void handleUnresolvedNewInstance(JavaType type) { + append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved))); + frameState.apush(appendConstant(Constant.NULL_OBJECT)); + } + + /** + * @param type the type of the array being instantiated + * @param length the length of the array + */ + protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) { + append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved))); + frameState.apush(appendConstant(Constant.NULL_OBJECT)); + } + + /** + * @param type the type being instantiated + * @param dims the dimensions for the multi-array + */ + protected void handleUnresolvedNewMultiArray(JavaType type, ValueNode[] dims) { + append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved))); + frameState.apush(appendConstant(Constant.NULL_OBJECT)); + } + + /** + * @param field the unresolved field + * @param receiver the object containing the field or {@code null} if {@code field} is static + */ + protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) { + Kind kind = field.getKind(); + append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved))); + frameState.push(kind.getStackKind(), append(ConstantNode.defaultForKind(kind, currentGraph))); + } + + /** + * @param field the unresolved field + * @param value the value being stored to the field + * @param receiver the object containing the field or {@code null} if {@code field} is static + */ + protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) { + append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved))); + } + + /** + * @param representation + * @param type + */ + protected void handleUnresolvedExceptionType(Representation representation, JavaType type) { + append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved))); + } + + protected void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind) { + boolean withReceiver = invokeKind != InvokeKind.Static; + append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved))); + frameState.popArguments(javaMethod.getSignature().getParameterSlots(withReceiver), javaMethod.getSignature().getParameterCount(withReceiver)); + Kind kind = javaMethod.getSignature().getReturnKind(); + if (kind != Kind.Void) { + frameState.push(kind.getStackKind(), append(ConstantNode.defaultForKind(kind, currentGraph))); + } + } + private DispatchBeginNode handleException(ValueNode exceptionObject, int bci) { assert bci == FrameState.BEFORE_BCI || bci == bci() : "invalid bci"; Debug.log("Creating exception dispatch edges at %d, exception object=%s, exception seen=%s", bci, exceptionObject, profilingInfo.getExceptionSeen(bci)); @@ -306,8 +416,7 @@ if (type instanceof ResolvedJavaType) { frameState.push(Kind.Object, append(ConstantNode.forConstant(((ResolvedJavaType) type).getEncoding(Representation.JavaClass), runtime, currentGraph))); } else { - append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved))); - frameState.push(Kind.Object, append(ConstantNode.forObject(null, runtime, currentGraph))); + handleUnresolvedLoadConstant(type); } } else if (con instanceof Constant) { Constant constant = (Constant) con; @@ -626,8 +735,7 @@ private void genThrow() { ValueNode exception = frameState.apop(); - FixedGuardNode node = currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(exception)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, - true)); + FixedGuardNode node = currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true)); append(node); append(handleException(exception, bci())); } @@ -635,21 +743,21 @@ private JavaType lookupType(int cpi, int bytecode) { eagerResolvingForSnippets(cpi, bytecode); JavaType result = constantPool.lookupType(cpi, bytecode); - assert !graphBuilderConfig.eagerResolvingForSnippets() || result instanceof ResolvedJavaType; + assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaType; return result; } private JavaMethod lookupMethod(int cpi, int opcode) { eagerResolvingForSnippets(cpi, opcode); JavaMethod result = constantPool.lookupMethod(cpi, opcode); - assert !graphBuilderConfig.eagerResolvingForSnippets() || ((result instanceof ResolvedJavaMethod) && ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized()) : result; + assert !graphBuilderConfig.unresolvedIsError() || ((result instanceof ResolvedJavaMethod) && ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized()) : result; return result; } private JavaField lookupField(int cpi, int opcode) { eagerResolvingForSnippets(cpi, opcode); JavaField result = constantPool.lookupField(cpi, opcode); - assert !graphBuilderConfig.eagerResolvingForSnippets() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result; + assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result; return result; } @@ -660,14 +768,8 @@ return result; } - // private void eagerResolving(int cpi, int bytecode) { - // if (graphBuilderConfig.eagerResolving()) { - // constantPool.loadReferencedType(cpi, bytecode); - // } - // } - private void eagerResolvingForSnippets(int cpi, int bytecode) { - if (graphBuilderConfig.eagerResolvingForSnippets()) { + if (graphBuilderConfig.eagerResolving()) { constantPool.loadReferencedType(cpi, bytecode); } } @@ -688,16 +790,13 @@ private void genCheckCast() { int cpi = stream().readCPI(); JavaType type = lookupType(cpi, CHECKCAST); - boolean initialized = type instanceof ResolvedJavaType; - if (initialized) { - ValueNode object = frameState.apop(); + ValueNode object = frameState.apop(); + if (type instanceof ResolvedJavaType) { CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) type, object, getProfileForTypeCheck((ResolvedJavaType) type))); append(checkCast); frameState.apush(checkCast); } else { - ValueNode object = frameState.apop(); - append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(object)), DeoptimizationReason.Unresolved, DeoptimizationAction.InvalidateRecompile))); - frameState.apush(appendConstant(Constant.NULL_OBJECT)); + handleUnresolvedCheckCast(type, object); } } @@ -711,12 +810,7 @@ ConditionalNode conditional = currentGraph.unique(new ConditionalNode(currentGraph.unique(instanceOfNode), ConstantNode.forInt(1, currentGraph), ConstantNode.forInt(0, currentGraph))); frameState.ipush(append(conditional)); } else { - BlockPlaceholderNode successor = currentGraph.add(new BlockPlaceholderNode()); - DeoptimizeNode deopt = currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved)); - IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new IsNullNode(object)), successor, deopt, 1)); - append(ifNode); - lastInstr = successor; - frameState.ipush(appendConstant(Constant.INT_0)); + handleUnresolvedInstanceOf(type, object); } } @@ -726,8 +820,7 @@ NewInstanceNode n = currentGraph.add(new NewInstanceNode((ResolvedJavaType) type, true, false)); frameState.apush(append(n)); } else { - append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved))); - frameState.apush(appendConstant(Constant.NULL_OBJECT)); + handleUnresolvedNewInstance(type); } } @@ -777,8 +870,7 @@ NewArrayNode n = currentGraph.add(new NewArrayNode((ResolvedJavaType) type, length, true, false)); frameState.apush(append(n)); } else { - append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved))); - frameState.apush(appendConstant(Constant.NULL_OBJECT)); + handleUnresolvedNewObjectArray(type, length); } } @@ -794,8 +886,7 @@ FixedWithNextNode n = currentGraph.add(new NewMultiArrayNode((ResolvedJavaType) type, dims)); frameState.apush(append(n)); } else { - append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved))); - frameState.apush(appendConstant(Constant.NULL_OBJECT)); + handleUnresolvedNewMultiArray(type, dims); } } @@ -808,8 +899,7 @@ LoadFieldNode load = currentGraph.add(new LoadFieldNode(receiver, (ResolvedJavaField) field)); appendOptimizedLoadField(kind, load); } else { - append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved))); - frameState.push(kind.getStackKind(), append(ConstantNode.defaultForKind(kind, currentGraph))); + handleUnresolvedLoadField(field, receiver); } } @@ -872,9 +962,9 @@ } } - private void emitExplicitExceptions(ValueNode receiver, ValueNode outOfBoundsIndex) { + protected void emitExplicitExceptions(ValueNode receiver, ValueNode outOfBoundsIndex) { assert receiver != null; - if (!GraalOptions.AllowExplicitExceptionChecks || (optimisticOpts.useExceptionProbability() && profilingInfo.getExceptionSeen(bci()) == ExceptionSeen.FALSE)) { + if (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == ExceptionSeen.FALSE) { return; } @@ -895,7 +985,7 @@ StoreFieldNode store = currentGraph.add(new StoreFieldNode(receiver, (ResolvedJavaField) field, value)); appendOptimizedStoreField(store); } else { - append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved))); + handleUnresolvedStoreField(field, value, receiver); } } @@ -910,8 +1000,7 @@ appendOptimizedLoadField(kind, load); } } else { - append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved))); - frameState.push(kind.getStackKind(), append(ConstantNode.defaultForKind(kind, currentGraph))); + handleUnresolvedLoadField(field, null); } } @@ -921,15 +1010,15 @@ StoreFieldNode store = currentGraph.add(new StoreFieldNode(null, (ResolvedJavaField) field, value)); appendOptimizedStoreField(store); } else { - append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved))); + handleUnresolvedStoreField(field, value, null); } } - private ConstantNode genTypeOrDeopt(Representation representation, JavaType holder, boolean initialized) { + private ConstantNode genTypeOrDeopt(Representation representation, JavaType type, boolean initialized) { if (initialized) { - return appendConstant(((ResolvedJavaType) holder).getEncoding(representation)); + return appendConstant(((ResolvedJavaType) type).getEncoding(representation)); } else { - append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved))); + handleUnresolvedExceptionType(representation, type); return null; } } @@ -949,13 +1038,13 @@ ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target; ResolvedJavaType holder = resolvedTarget.getDeclaringClass(); if (!holder.isInitialized() && GraalOptions.ResolveClassBeforeStaticInvoke) { - genInvokeDeopt(target, false); + handleUnresolvedInvoke(target, InvokeKind.Static); } else { ValueNode[] args = frameState.popArguments(resolvedTarget.getSignature().getParameterSlots(false), resolvedTarget.getSignature().getParameterCount(false)); appendInvoke(InvokeKind.Static, resolvedTarget, args); } } else { - genInvokeDeopt(target, false); + handleUnresolvedInvoke(target, InvokeKind.Static); } } @@ -964,7 +1053,7 @@ ValueNode[] args = frameState.popArguments(target.getSignature().getParameterSlots(true), target.getSignature().getParameterCount(true)); genInvokeIndirect(InvokeKind.Interface, (ResolvedJavaMethod) target, args); } else { - genInvokeDeopt(target, true); + handleUnresolvedInvoke(target, InvokeKind.Interface); } } @@ -973,7 +1062,7 @@ ValueNode[] args = frameState.popArguments(target.getSignature().getParameterSlots(true), target.getSignature().getParameterCount(true)); genInvokeIndirect(InvokeKind.Virtual, (ResolvedJavaMethod) target, args); } else { - genInvokeDeopt(target, true); + handleUnresolvedInvoke(target, InvokeKind.Virtual); } } @@ -985,16 +1074,7 @@ ValueNode[] args = frameState.popArguments(target.getSignature().getParameterSlots(true), target.getSignature().getParameterCount(true)); invokeDirect((ResolvedJavaMethod) target, args); } else { - genInvokeDeopt(target, true); - } - } - - private void genInvokeDeopt(JavaMethod unresolvedTarget, boolean withReceiver) { - append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved))); - frameState.popArguments(unresolvedTarget.getSignature().getParameterSlots(withReceiver), unresolvedTarget.getSignature().getParameterCount(withReceiver)); - Kind kind = unresolvedTarget.getSignature().getReturnKind(); - if (kind != Kind.Void) { - frameState.push(kind.getStackKind(), append(ConstantNode.defaultForKind(kind, currentGraph))); + handleUnresolvedInvoke(target, InvokeKind.Special); } } @@ -1030,21 +1110,20 @@ private void appendInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args) { Kind resultType = targetMethod.getSignature().getReturnKind(); if (GraalOptions.DeoptALot) { - DeoptimizeNode deoptimize = currentGraph.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint)); - deoptimize.setMessage(targetMethod.getName()); + DeoptimizeNode deoptimize = currentGraph.add(new DeoptimizeNode(DeoptimizationAction.None, RuntimeConstraint)); append(deoptimize); frameState.pushReturn(resultType, ConstantNode.defaultForKind(resultType, currentGraph)); return; } JavaType returnType = targetMethod.getSignature().getReturnType(method.getDeclaringClass()); - if (graphBuilderConfig.eagerResolvingForSnippets()) { + if (graphBuilderConfig.eagerResolving()) { returnType = returnType.resolve(targetMethod.getDeclaringClass()); } MethodCallTargetNode callTarget = currentGraph.add(new MethodCallTargetNode(invokeKind, targetMethod, args, returnType)); // be conservative if information was not recorded (could result in endless recompiles // otherwise) - if (optimisticOpts.useExceptionProbability() && profilingInfo.getExceptionSeen(bci()) == ExceptionSeen.FALSE) { + if (graphBuilderConfig.omitAllExceptionEdges() || (optimisticOpts.useExceptionProbability() && profilingInfo.getExceptionSeen(bci()) == ExceptionSeen.FALSE)) { ValueNode result = appendWithBCI(currentGraph.add(new InvokeNode(callTarget, bci()))); frameState.pushReturn(resultType, result); @@ -1103,7 +1182,7 @@ if (successor.jsrScope.nextReturnAddress() != stream().nextBCI()) { throw new JsrNotSupportedBailout("unstructured control flow (internal limitation)"); } - frameState.push(Kind.Jsr, ConstantNode.forJsr(stream().nextBCI(), currentGraph)); + frameState.push(Kind.Int, ConstantNode.forInt(stream().nextBCI(), currentGraph)); appendGoto(createTarget(successor, frameState)); } @@ -1112,8 +1191,7 @@ ValueNode local = frameState.loadLocal(localIndex); JsrScope scope = currentBlock.jsrScope; int retAddress = scope.nextReturnAddress(); - append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new IntegerEqualsNode(local, ConstantNode.forJsr(retAddress, currentGraph))), DeoptimizationReason.JavaSubroutineMismatch, - DeoptimizationAction.InvalidateReprofile))); + append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new IntegerEqualsNode(local, ConstantNode.forInt(retAddress, currentGraph))), JavaSubroutineMismatch, InvalidateReprofile))); if (!successor.jsrScope.equals(scope.pop())) { throw new JsrNotSupportedBailout("unstructured control flow (ret leaves more than one scope)"); } @@ -1219,7 +1297,7 @@ } } - private ConstantNode appendConstant(Constant constant) { + protected ConstantNode appendConstant(Constant constant) { assert constant != null; return ConstantNode.forConstant(constant, runtime, currentGraph); } @@ -1230,7 +1308,7 @@ return fixed; } - private ValueNode append(FixedWithNextNode x) { + protected ValueNode append(FixedWithNextNode x) { return appendWithBCI(x); } @@ -1238,7 +1316,7 @@ return v; } - private ValueNode appendWithBCI(FixedWithNextNode x) { + protected ValueNode appendWithBCI(FixedWithNextNode x) { assert x.predecessor() == null : "instruction should not have been appended yet"; assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")"; lastInstr.setNext(x); @@ -1313,7 +1391,7 @@ private FixedNode createTarget(double probability, Block block, FrameStateBuilder stateAfter) { assert probability >= 0 && probability <= 1.01 : probability; if (isNeverExecutedCode(probability)) { - return currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.UnreachedCode)); + return currentGraph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode)); } else { assert block != null; return createTarget(block, stateAfter); @@ -1474,8 +1552,11 @@ private void createUnwind() { assert frameState.stackSize() == 1 : frameState; + ValueNode exception = frameState.apop(); + FixedGuardNode guard = currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true)); + append(guard); synchronizedEpilogue(FrameState.AFTER_EXCEPTION_BCI); - UnwindNode unwindNode = currentGraph.add(new UnwindNode(frameState.apop())); + UnwindNode unwindNode = currentGraph.add(new UnwindNode(exception)); append(unwindNode); } @@ -1487,9 +1568,8 @@ ValueNode x = returnKind == Kind.Void ? null : frameState.pop(returnKind); assert frameState.stackSize() == 0; - // TODO (gdub) remove this when FloatingRead can handle this case if (Modifier.isSynchronized(method.getModifiers())) { - append(currentGraph.add(new ValueAnchorNode(x))); + append(currentGraph.add(new ValueAnchorNode(true, x))); assert !frameState.rethrowException(); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -48,6 +48,10 @@ */ Object[] argsToBind; + public JTTTest() { + Assert.assertNotNull(runtime); + } + @Override protected StructuredGraph parse(Method m) { StructuredGraph graph = super.parse(m); @@ -89,10 +93,14 @@ } protected void runTest(String name, Object... args) { - // System.out.println(getClass().getSimpleName() + "." + name); - super.test(name, args); + Method method = getMethod(name); + Object receiver = Modifier.isStatic(method.getModifiers()) ? null : this; + + Result expect = executeExpected(method, receiver, args); + + test(method, expect, receiver, args); this.argsToBind = args; - super.test(name, args); + test(method, expect, receiver, args); this.argsToBind = null; } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_d2l03.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_d2l03.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2009, 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.jtt.bytecode; + +import com.oracle.graal.jtt.*; +import org.junit.*; + +/* + */ +public class BC_d2l03 extends JTTTest { + + public static long test(double divider) { + return (long) (((long) divider) * divider); + } + + @Test + public void run0() throws Throwable { + runTest("test", 34.5D); + } + +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_NPE_07.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_NPE_07.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_NPE_07.java Thu Mar 21 14:11:13 2013 +0100 @@ -23,12 +23,11 @@ package com.oracle.graal.jtt.except; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ - public class Catch_NPE_07 extends JTTTest { @SuppressWarnings("serial") @@ -62,12 +61,12 @@ } } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two02.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two02.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.except; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -49,17 +49,17 @@ } } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 3); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two03.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two03.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Catch_Two03.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.except; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -56,17 +56,17 @@ } } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Except_Synchronized05.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Except_Synchronized05.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Except_Synchronized05.java Thu Mar 21 14:11:13 2013 +0100 @@ -29,29 +29,11 @@ public class Except_Synchronized05 extends JTTTest { - Object field; - - public static int test(int arg) { - Except_Synchronized05 obj = new Except_Synchronized05(); - int a = obj.bar(arg) != null ? 1 : 0; - int b = obj.baz(arg) != null ? 1 : 0; - return a + b; - } + static class Foo { - public synchronized Object bar(int arg) { - try { - String f = foo1(arg); - if (f == null) { - field = new Object(); - } - } catch (NullPointerException e) { - // do nothing - } - return field; - } + Object field; - public Object baz(int arg) { - synchronized (this) { + public synchronized Object bar(int arg) { try { String f = foo1(arg); if (f == null) { @@ -62,14 +44,36 @@ } return field; } + + public Object baz(int arg) { + synchronized (this) { + try { + String f = foo1(arg); + if (f == null) { + field = new Object(); + } + } catch (NullPointerException e) { + // do nothing + } + return field; + } + } + + @SuppressWarnings("static-method") + private String foo1(int arg) { + if (arg == 0) { + throw null; + } + return null; + } + } - @SuppressWarnings("static-method") - private String foo1(int arg) { - if (arg == 0) { - throw null; - } - return null; + public static int test(int arg) { + Foo obj = new Foo(); + int a = obj.bar(arg) != null ? 1 : 0; + int b = obj.baz(arg) != null ? 1 : 0; + return a + b; } @Test diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_InNested.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_InNested.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_InNested.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.except; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public class Throw_InNested extends JTTTest { @@ -48,12 +48,12 @@ return i; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.except; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public class Throw_Synchronized01 extends JTTTest { @@ -38,12 +38,12 @@ throw new Exception(); } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized02.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized02.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.except; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public class Throw_Synchronized02 extends JTTTest { @@ -36,12 +36,12 @@ throw new Exception(); } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized03.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized03.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Throw_Synchronized03.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.except; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public class Throw_Synchronized03 extends JTTTest { @@ -41,12 +41,12 @@ throw new Exception(); } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_allocate01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_allocate01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_allocate01.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.hotpath; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -37,27 +37,27 @@ return sum; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 80); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field04.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field04.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_field04.java Thu Mar 21 14:11:13 2013 +0100 @@ -23,8 +23,8 @@ // Checkstyle: stop package com.oracle.graal.jtt.hotpath; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -55,12 +55,12 @@ return (int) (b + c + s + i + l + f + d); } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 40); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1000); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_idea.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_idea.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_idea.java Thu Mar 21 14:11:13 2013 +0100 @@ -372,7 +372,7 @@ /* * private int mul(int a, int b) throws ArithmeticException { long p; // Large enough to catch 16-bit multiply // - * without hitting sign bit. if (a != 0) { if(b != 0) { p = (long) a * b; b = (int) p & 0xFFFF; // Lower 16 bits. a + * without hitting sign bit. if (a != 0) { if (b != 0) { p = (long) a * b; b = (int) p & 0xFFFF; // Lower 16 bits. a * = (int) p >>> 16; // Upper 16 bits. * * return (b - a + (b < a ? 1 : 0) & 0xFFFF); } else return ((1 - a) & 0xFFFF); // If b = 0, then same as // 0x10001 diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_invoke01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_invoke01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_invoke01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ package com.oracle.graal.jtt.hotpath; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -104,12 +104,12 @@ } } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 40); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 80); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_life.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_life.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_life.java Thu Mar 21 14:11:13 2013 +0100 @@ -25,8 +25,8 @@ import java.util.*; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -107,7 +107,7 @@ } } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 5); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_nest02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_nest02.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_nest02.java Thu Mar 21 14:11:13 2013 +0100 @@ -23,8 +23,8 @@ // Checkstyle: stop package com.oracle.graal.jtt.hotpath; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -48,7 +48,7 @@ return sum; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 15); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6196102.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6196102.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6196102.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,11 +22,11 @@ */ package com.oracle.graal.jtt.hotspot; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /** - * @test + * @LongTest * @bug 6196102 * @summary Integer seems to be greater than Integer.MAX_VALUE * @@ -48,7 +48,7 @@ return "ok"; } - @Test + @LongTest public void run0() throws Throwable { runTest("test"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6850611.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6850611.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6850611.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.hotspot; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; //@formatter:off @@ -50,7 +50,7 @@ return 95; } - @Test + @LongTest public void run0() throws Throwable { runTest("test"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/EnumMap02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/EnumMap02.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/EnumMap02.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ import java.util.*; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -43,17 +43,17 @@ A, B, C } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/System_setOut.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ import java.io.*; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -56,7 +56,7 @@ System.out.println(test(10000)); } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 10000); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/UnsafeAccess01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/UnsafeAccess01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/UnsafeAccess01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ import java.lang.reflect.*; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; import sun.misc.*; @@ -55,7 +55,7 @@ } } - @Test + @LongTest public void run0() throws Throwable { runTest("test"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/ClassLoader_loadClass01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/ClassLoader_loadClass01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/ClassLoader_loadClass01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ import java.net.*; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -43,22 +43,22 @@ return null; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 5); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_Literal01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_Literal01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_Literal01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.lang; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public final class Class_Literal01 extends JTTTest { @@ -45,27 +45,27 @@ return null; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_asSubclass01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_asSubclass01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_asSubclass01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.lang; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public final class Class_asSubclass01 extends JTTTest { @@ -53,27 +53,27 @@ return i; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_cast01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_cast01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_cast01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.lang; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public final class Class_cast01 extends JTTTest { @@ -57,27 +57,27 @@ return i; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.lang; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public final class Class_forName01 extends JTTTest { @@ -45,27 +45,27 @@ return null; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName02.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName02.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.lang; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public final class Class_forName02 extends JTTTest { @@ -51,27 +51,27 @@ return null; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName03.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName03.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName03.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ import java.net.*; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -56,32 +56,32 @@ return null; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } - @Test + @LongTest public void run5() throws Throwable { runTest("test", 5); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName04.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName04.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName04.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.lang; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -48,32 +48,32 @@ return null; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } - @Test + @LongTest public void run5() throws Throwable { runTest("test", 5); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName05.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName05.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_forName05.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ import java.net.*; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -41,17 +41,17 @@ return null; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 5); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_getInterfaces01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_getInterfaces01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Class_getInterfaces01.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,12 +22,11 @@ */ package com.oracle.graal.jtt.lang; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ - public final class Class_getInterfaces01 extends JTTTest { public static String test(int i) { @@ -82,27 +81,27 @@ } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_getClass01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_getClass01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_getClass01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.lang; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public final class Object_getClass01 extends JTTTest { @@ -49,27 +49,27 @@ return null; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_toString01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_toString01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Object_toString01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.lang; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public class Object_toString01 extends JTTTest { @@ -47,17 +47,17 @@ return string; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern02.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern02.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.lang; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -33,17 +33,17 @@ return ("id" + i).intern() == ("id" + i).intern(); } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern03.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern03.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/String_intern03.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.lang; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -33,17 +33,17 @@ return ("id" + i).intern().equals("id" + i); } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopParseLong.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopParseLong.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopParseLong.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.loop; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public class LoopParseLong extends JTTTest { @@ -79,7 +79,7 @@ return negative ? result : -result; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", "7", 10); runTest("test", "-100", 10); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopSwitch01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopSwitch01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopSwitch01.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.loop; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -58,7 +58,7 @@ return "" + ('a' + count); } - @Test + @LongTest public void run0() throws Throwable { runTest("test"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/BigObjectParams02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/BigObjectParams02.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/BigObjectParams02.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.micro; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -33,7 +33,7 @@ return p0 + p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/Matrix01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/Matrix01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/Matrix01.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.micro; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -155,32 +155,32 @@ ((Matrix[]) array)[val % array.length] = new Matrix(number); } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } - @Test + @LongTest public void run5() throws Throwable { runTest("test", 5); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/ReferenceMap01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/ReferenceMap01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/ReferenceMap01.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.micro; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -57,7 +57,7 @@ return Integer.valueOf(foo(new String[]{"asdf"})); } - @Test + @LongTest public void run0() throws Throwable { runTest("test"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/StrangeFrames.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/StrangeFrames.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/StrangeFrames.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.micro; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -58,7 +58,7 @@ Object c = b; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Conditional01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Conditional01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Conditional01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ import java.util.*; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -117,22 +117,22 @@ return c2 ? 1 : 0; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 10); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 20); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 40); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_FlowSensitive05.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_FlowSensitive05.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/NCE_FlowSensitive05.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.optimize; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -40,7 +40,7 @@ return (String) arg; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", (Object) null); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_InstanceOf02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_InstanceOf02.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/VN_InstanceOf02.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.optimize; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* * Tests value numbering of instanceof operations. @@ -76,17 +76,17 @@ return false; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField01.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.reflect; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -37,22 +37,22 @@ return Class_getField01.class.getField(input).getName(); } - @Test + @LongTest public void run0() throws Throwable { runTest("test", "test"); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", "field"); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", "field2"); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", "field3"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField02.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getField02.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.reflect; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -42,27 +42,27 @@ public String field4; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", "test"); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", "field"); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", "field2"); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", "field3"); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", "field4"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod01.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.reflect; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -39,17 +39,17 @@ field = args[0]; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", "test"); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", "main"); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", "xx"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod02.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_getMethod02.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.reflect; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -52,37 +52,37 @@ field = args[0]; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } - @Test + @LongTest public void run5() throws Throwable { runTest("test", 5); } - @Test + @LongTest public void run6() throws Throwable { runTest("test", 6); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_newInstance03.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_newInstance03.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Class_newInstance03.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.reflect; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public class Class_newInstance03 extends JTTTest { @@ -45,27 +45,27 @@ return false; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get01.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.reflect; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -59,47 +59,47 @@ return false; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } - @Test + @LongTest public void run5() throws Throwable { runTest("test", 5); } - @Test + @LongTest public void run6() throws Throwable { runTest("test", 6); } - @Test + @LongTest public void run7() throws Throwable { runTest("test", 7); } - @Test + @LongTest public void run8() throws Throwable { runTest("test", 8); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get02.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get02.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.reflect; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -61,47 +61,47 @@ return false; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } - @Test + @LongTest public void run5() throws Throwable { runTest("test", 5); } - @Test + @LongTest public void run6() throws Throwable { runTest("test", 6); } - @Test + @LongTest public void run7() throws Throwable { runTest("test", 7); } - @Test + @LongTest public void run8() throws Throwable { runTest("test", 8); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get03.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ import java.lang.reflect.*; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -89,47 +89,47 @@ return false; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } - @Test + @LongTest public void run5() throws Throwable { runTest("test", 5); } - @Test + @LongTest public void run6() throws Throwable { runTest("test", 6); } - @Test + @LongTest public void run7() throws Throwable { runTest("test", 7); } - @Test + @LongTest public void run8() throws Throwable { runTest("test", 8); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get04.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get04.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_get04.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.reflect; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -61,47 +61,47 @@ return false; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } - @Test + @LongTest public void run5() throws Throwable { runTest("test", 5); } - @Test + @LongTest public void run6() throws Throwable { runTest("test", 6); } - @Test + @LongTest public void run7() throws Throwable { runTest("test", 7); } - @Test + @LongTest public void run8() throws Throwable { runTest("test", 8); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_getType01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_getType01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_getType01.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.reflect; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -59,47 +59,47 @@ return false; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } - @Test + @LongTest public void run5() throws Throwable { runTest("test", 5); } - @Test + @LongTest public void run6() throws Throwable { runTest("test", 6); } - @Test + @LongTest public void run7() throws Throwable { runTest("test", 7); } - @Test + @LongTest public void run8() throws Throwable { runTest("test", 8); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set01.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.reflect; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -67,47 +67,47 @@ return false; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } - @Test + @LongTest public void run5() throws Throwable { runTest("test", 5); } - @Test + @LongTest public void run6() throws Throwable { runTest("test", 6); } - @Test + @LongTest public void run7() throws Throwable { runTest("test", 7); } - @Test + @LongTest public void run8() throws Throwable { runTest("test", 8); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set02.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set02.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.reflect; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -69,47 +69,47 @@ return false; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } - @Test + @LongTest public void run5() throws Throwable { runTest("test", 5); } - @Test + @LongTest public void run6() throws Throwable { runTest("test", 6); } - @Test + @LongTest public void run7() throws Throwable { runTest("test", 7); } - @Test + @LongTest public void run8() throws Throwable { runTest("test", 8); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set03.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set03.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Field_set03.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.reflect; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -69,47 +69,47 @@ return false; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } - @Test + @LongTest public void run5() throws Throwable { runTest("test", 5); } - @Test + @LongTest public void run6() throws Throwable { runTest("test", 6); } - @Test + @LongTest public void run7() throws Throwable { runTest("test", 7); } - @Test + @LongTest public void run8() throws Throwable { runTest("test", 8); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_except01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_except01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_except01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ import java.lang.reflect.*; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -56,27 +56,27 @@ return arg.length; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ import java.lang.reflect.*; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -44,12 +44,12 @@ field = args[0]; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", "test1"); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", "test2"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main03.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main03.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Invoke_main03.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ import java.lang.reflect.*; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -48,12 +48,12 @@ field = args[0]; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", "test1"); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", "test2"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getParameterTypes01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getParameterTypes01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getParameterTypes01.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.reflect; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -51,22 +51,22 @@ public void method3(int arg1, Object arg2) { } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getReturnType01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getReturnType01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/reflect/Method_getReturnType01.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.reflect; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -51,22 +51,22 @@ public void method3() { } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_contended01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_contended01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_contended01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public final class Monitor_contended01 extends JTTTest implements Runnable { @@ -71,7 +71,7 @@ } } - @Test + @LongTest public void run0() throws Throwable { runTest("test"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_notowner01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_notowner01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Monitor_notowner01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public class Monitor_notowner01 extends JTTTest { @@ -62,7 +62,7 @@ } } - @Test + @LongTest public void run0() throws Throwable { runTest("test"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public class Object_wait01 extends JTTTest implements Runnable { @@ -57,22 +57,22 @@ } } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 15); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait02.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait02.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public class Object_wait02 extends JTTTest implements Runnable { @@ -57,17 +57,17 @@ } } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait03.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait03.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait03.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public class Object_wait03 extends JTTTest implements Runnable { @@ -63,17 +63,17 @@ } } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait04.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait04.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Object_wait04.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public class Object_wait04 extends JTTTest implements Runnable { @@ -67,32 +67,32 @@ } } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } - @Test + @LongTest public void run5() throws Throwable { runTest("test", 5); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/ThreadLocal03.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/ThreadLocal03.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/ThreadLocal03.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -59,22 +59,22 @@ } } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_getState02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_getState02.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_getState02.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public final class Thread_getState02 extends JTTTest { @@ -33,7 +33,7 @@ return new Thread().getState() == Thread.State.NEW; } - @Test + @LongTest public void run0() throws Throwable { runTest("test"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted02.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted02.java Thu Mar 21 14:11:13 2013 +0100 @@ -26,8 +26,8 @@ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; //Test all, mainly monitors public class Thread_isInterrupted02 extends JTTTest { @@ -85,12 +85,12 @@ } } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0, 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1, 500); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted03.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted03.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted03.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -68,7 +68,7 @@ } } - @Test + @LongTest public void run0() throws Throwable { runTest("test"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted04.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -66,7 +66,7 @@ } - @Test + @LongTest public void run0() throws Throwable { runTest("test"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted05.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted05.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_isInterrupted05.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,8 @@ */ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; /* */ @@ -66,7 +66,7 @@ } } - @Test + @LongTest public void run0() throws Throwable { runTest("test"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public class Thread_join01 extends JTTTest implements Runnable { @@ -43,7 +43,7 @@ cont = false; } - @Test + @LongTest public void run0() throws Throwable { runTest("test"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join02.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join02.java Thu Mar 21 14:11:13 2013 +0100 @@ -27,8 +27,8 @@ */ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public class Thread_join02 extends JTTTest implements Runnable { @@ -50,7 +50,7 @@ cont = false; } - @Test + @LongTest public void run0() throws Throwable { runTest("test"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join03.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join03.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_join03.java Thu Mar 21 14:11:13 2013 +0100 @@ -27,8 +27,8 @@ */ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public class Thread_join03 extends JTTTest implements Runnable { @@ -47,7 +47,7 @@ cont = false; } - @Test + @LongTest public void run0() throws Throwable { runTest("test"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public final class Thread_new01 extends JTTTest { @@ -45,27 +45,27 @@ return false; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new02.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new02.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_new02.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public class Thread_new02 extends JTTTest implements Runnable { @@ -51,27 +51,27 @@ // do nothing. } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 0); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 1); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 2); } - @Test + @LongTest public void run3() throws Throwable { runTest("test", 3); } - @Test + @LongTest public void run4() throws Throwable { runTest("test", 4); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_sleep01.java --- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_sleep01.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/threads/Thread_sleep01.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,8 @@ */ package com.oracle.graal.jtt.threads; +import com.oracle.graal.test.*; import com.oracle.graal.jtt.*; -import org.junit.*; public final class Thread_sleep01 extends JTTTest { @@ -35,17 +35,17 @@ return System.currentTimeMillis() - before >= i; } - @Test + @LongTest public void run0() throws Throwable { runTest("test", 10); } - @Test + @LongTest public void run1() throws Throwable { runTest("test", 20); } - @Test + @LongTest public void run2() throws Throwable { runTest("test", 100); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,103 @@ +/* + * 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.amd64; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Address.Scale; +import com.oracle.graal.lir.*; + +public class AMD64AddressValue extends CompositeValue { + + private static final long serialVersionUID = -4444600052487578694L; + + @Component({REG, UNUSED}) protected AllocatableValue base; + @Component({REG, UNUSED}) protected AllocatableValue index; + protected final Scale scale; + protected final int displacement; + + public AMD64AddressValue(Kind kind, AllocatableValue base, int displacement) { + this(kind, base, AllocatableValue.UNUSED, Scale.Times1, displacement); + } + + public AMD64AddressValue(Kind kind, AllocatableValue base, AllocatableValue index, Scale scale, int displacement) { + super(kind); + this.base = base; + this.index = index; + this.scale = scale; + this.displacement = displacement; + } + + private static Register toRegister(AllocatableValue value) { + if (value == AllocatableValue.UNUSED) { + return Register.None; + } else { + RegisterValue reg = (RegisterValue) value; + return reg.getRegister(); + } + } + + public AMD64Address toAddress() { + return new AMD64Address(toRegister(base), toRegister(index), scale, displacement); + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder(); + s.append(getKind().getJavaName()).append("["); + String sep = ""; + if (isLegal(base)) { + s.append(base); + sep = " + "; + } + if (isLegal(index)) { + s.append(sep).append(index).append(" * ").append(scale.value); + sep = " + "; + } + if (displacement < 0) { + s.append(" - ").append(-displacement); + } else if (displacement > 0) { + s.append(sep).append(displacement); + } + s.append("]"); + return s.toString(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof AMD64AddressValue) { + AMD64AddressValue addr = (AMD64AddressValue) obj; + return getKind() == addr.getKind() && displacement == addr.displacement && base.equals(addr.base) && scale == addr.scale && index.equals(addr.index); + } + return false; + } + + @Override + public int hashCode() { + return base.hashCode() ^ index.hashCode() ^ (displacement << 4) ^ (scale.value << 8) ^ (getKind().ordinal() << 12); + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java Thu Mar 21 14:11:13 2013 +0100 @@ -26,10 +26,9 @@ import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; import com.oracle.graal.amd64.*; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.asm.*; import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.asm.amd64.AMD64Assembler.*; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.asm.*; @@ -43,17 +42,25 @@ INEG, LNEG, I2L, L2I, I2B, I2C, I2S, F2D, D2F, - I2F, I2D, F2I, D2I, - L2F, L2D, F2L, D2L, - MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L; + I2F, I2D, + L2F, L2D, + MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L, + /* + * Converts a float/double to an int/long. The result of the conversion does not comply with Java semantics + * when the input is a NaN, infinity or the conversion result is greater than Integer.MAX_VALUE/Long.MAX_VALUE. + */ + F2I, D2I, F2L, D2L; - public static class Op1Reg extends AMD64LIRInstruction { + /** + * Unary operation with separate source and destination operand. + */ + public static class Unary2Op extends AMD64LIRInstruction { @Opcode private final AMD64Arithmetic opcode; - @Def({REG, HINT}) protected Value result; - @Use({REG}) protected Value x; + @Def({REG}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; - public Op1Reg(AMD64Arithmetic opcode, Value result, Value x) { + public Unary2Op(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x) { this.opcode = opcode; this.result = result; this.x = x; @@ -65,12 +72,15 @@ } } - public static class Op1Stack extends AMD64LIRInstruction { + /** + * Unary operation with single operand for source and destination. + */ + public static class Unary1Op extends AMD64LIRInstruction { @Opcode private final AMD64Arithmetic opcode; - @Def({REG, HINT}) protected Value result; - @Use({REG, STACK, CONST}) protected Value x; + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; - public Op1Stack(AMD64Arithmetic opcode, Value result, Value x) { + public Unary1Op(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x) { this.opcode = opcode; this.result = result; this.x = x; @@ -83,13 +93,17 @@ } } - public static class Op2Stack extends AMD64LIRInstruction { + /** + * Binary operation with two operands. The first source operand is combined with the destination. + * The second source operand may be a stack slot. + */ + public static class BinaryRegStack extends AMD64LIRInstruction { @Opcode private final AMD64Arithmetic opcode; - @Def({REG, HINT}) protected Value result; - @Use({REG, STACK, CONST}) protected Value x; - @Alive({REG, STACK, CONST}) protected Value y; + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + @Alive({REG, STACK}) protected AllocatableValue y; - public Op2Stack(AMD64Arithmetic opcode, Value result, Value x, Value y) { + public BinaryRegStack(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) { this.opcode = opcode; this.result = result; this.x = x; @@ -110,13 +124,17 @@ } } - public static class Op2Reg extends AMD64LIRInstruction { + /** + * Binary operation with two operands. The first source operand is combined with the destination. + * The second source operand must be a register. + */ + public static class BinaryRegReg extends AMD64LIRInstruction { @Opcode private final AMD64Arithmetic opcode; - @Def({REG, HINT}) protected Value result; - @Use({REG, STACK, CONST}) protected Value x; - @Alive({REG, CONST}) protected Value y; + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + @Alive({REG}) protected AllocatableValue y; - public Op2Reg(AMD64Arithmetic opcode, Value result, Value x, Value y) { + public BinaryRegReg(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) { this.opcode = opcode; this.result = result; this.x = x; @@ -137,13 +155,45 @@ } } - public static class Op2RegCommutative extends AMD64LIRInstruction { + /** + * Binary operation with single source/destination operand and one constant. + */ + public static class BinaryRegConst extends AMD64LIRInstruction { @Opcode private final AMD64Arithmetic opcode; - @Def({REG, HINT}) protected Value result; - @Use({REG, STACK, CONST}) protected Value x; - @Use({REG, CONST}) protected Value y; + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + protected Constant y; + + public BinaryRegConst(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, Constant y) { + this.opcode = opcode; + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + AMD64Move.move(tasm, masm, result, x); + emit(tasm, masm, opcode, result, y, null); + } - public Op2RegCommutative(AMD64Arithmetic opcode, Value result, Value x, Value y) { + @Override + public void verify() { + super.verify(); + verifyKind(opcode, result, x, y); + } + } + + /** + * Commutative binary operation with two operands. One of the operands is combined with the result. + */ + public static class BinaryCommutative extends AMD64LIRInstruction { + @Opcode private final AMD64Arithmetic opcode; + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + @Use({REG, STACK}) protected AllocatableValue y; + + public BinaryCommutative(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) { this.opcode = opcode; this.result = result; this.x = x; @@ -167,13 +217,16 @@ } } - public static class ShiftOp extends AMD64LIRInstruction { + /** + * Binary operation with separate source and destination and one constant operand. + */ + public static class BinaryRegStackConst extends AMD64LIRInstruction { @Opcode private final AMD64Arithmetic opcode; - @Def({REG, HINT}) protected Value result; - @Use({REG, STACK, CONST}) protected Value x; - @Alive({REG, CONST}) protected Value y; + @Def({REG}) protected AllocatableValue result; + @Use({REG, STACK}) protected AllocatableValue x; + protected Constant y; - public ShiftOp(AMD64Arithmetic opcode, Value result, Value x, Value y) { + public BinaryRegStackConst(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, Constant y) { this.opcode = opcode; this.result = result; this.x = x; @@ -189,22 +242,19 @@ @Override public void verify() { super.verify(); - assert isConstant(y) || asRegister(y) == AMD64.rcx; - assert differentRegisters(result, y) || sameRegister(x, y); - verifyKind(opcode, result, x, x); - assert y.getKind().getStackKind() == Kind.Int; + verifyKind(opcode, result, x, y); } } public static class DivRemOp extends AMD64LIRInstruction { @Opcode private final AMD64Arithmetic opcode; - @Def protected Value divResult; - @Def protected Value remResult; - @Use protected Value x; - @Alive protected Value y; + @Def protected AllocatableValue divResult; + @Def protected AllocatableValue remResult; + @Use protected AllocatableValue x; + @Alive protected AllocatableValue y; @State protected LIRFrameState state; - public DivRemOp(AMD64Arithmetic opcode, Value x, Value y, LIRFrameState state) { + public DivRemOp(AMD64Arithmetic opcode, AllocatableValue x, AllocatableValue y, LIRFrameState state) { this.opcode = opcode; this.divResult = AMD64.rax.asValue(x.getKind()); this.remResult = AMD64.rdx.asValue(x.getKind()); @@ -229,49 +279,14 @@ } } - public static class DivOp extends AMD64LIRInstruction { - @Opcode private final AMD64Arithmetic opcode; - @Def protected Value result; - @Use protected Value x; - @Alive protected Value y; - @Temp protected Value temp; - @State protected LIRFrameState state; - - public DivOp(AMD64Arithmetic opcode, Value result, Value x, Value y, LIRFrameState state) { - this.opcode = opcode; - this.result = result; - this.x = x; - this.y = y; - this.temp = asRegister(result) == AMD64.rax ? AMD64.rdx.asValue(result.getKind()) : AMD64.rax.asValue(result.getKind()); - this.state = state; - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - emit(tasm, masm, opcode, result, y, state); - } - - @Override - protected void verify() { - super.verify(); - // left input in rax, right input in any register but rax and rdx, result quotient in rax, result remainder in rdx - assert asRegister(x) == AMD64.rax; - assert differentRegisters(y, AMD64.rax.asValue(), AMD64.rdx.asValue()); - assert (name().endsWith("DIV") && asRegister(result) == AMD64.rax) || (name().endsWith("REM") && asRegister(result) == AMD64.rdx); - verifyKind(opcode, result, x, y); - } - } - @SuppressWarnings("unused") - protected static void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Arithmetic opcode, Value result) { + protected static void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Arithmetic opcode, AllocatableValue result) { switch (opcode) { case INEG: masm.negl(asIntReg(result)); break; case LNEG: masm.negq(asLongReg(result)); break; case L2I: masm.andl(asIntReg(result), 0xFFFFFFFF); break; - case I2B: masm.signExtendByte(asIntReg(result)); break; case I2C: masm.andl(asIntReg(result), 0xFFFF); break; - case I2S: masm.signExtendShort(asIntReg(result)); break; default: throw GraalInternalError.shouldNotReachHere(); } } @@ -286,9 +301,9 @@ case IMUL: masm.imull(asIntReg(dst), asIntReg(src)); break; case IOR: masm.orl(asIntReg(dst), asIntReg(src)); break; case IXOR: masm.xorl(asIntReg(dst), asIntReg(src)); break; - case ISHL: masm.shll(asIntReg(dst)); break; - case ISHR: masm.sarl(asIntReg(dst)); break; - case IUSHR:masm.shrl(asIntReg(dst)); break; + case ISHL: assert asIntReg(src) == AMD64.rcx; masm.shll(asIntReg(dst)); break; + case ISHR: assert asIntReg(src) == AMD64.rcx; masm.sarl(asIntReg(dst)); break; + case IUSHR: assert asIntReg(src) == AMD64.rcx; masm.shrl(asIntReg(dst)); break; case LADD: masm.addq(asLongReg(dst), asLongReg(src)); break; case LSUB: masm.subq(asLongReg(dst), asLongReg(src)); break; @@ -296,9 +311,9 @@ case LAND: masm.andq(asLongReg(dst), asLongReg(src)); break; case LOR: masm.orq(asLongReg(dst), asLongReg(src)); break; case LXOR: masm.xorq(asLongReg(dst), asLongReg(src)); break; - case LSHL: masm.shlq(asLongReg(dst)); break; - case LSHR: masm.sarq(asLongReg(dst)); break; - case LUSHR:masm.shrq(asLongReg(dst)); break; + case LSHL: assert asIntReg(src) == AMD64.rcx; masm.shlq(asLongReg(dst)); break; + case LSHR: assert asIntReg(src) == AMD64.rcx; masm.sarq(asLongReg(dst)); break; + case LUSHR: assert asIntReg(src) == AMD64.rcx; masm.shrq(asLongReg(dst)); break; case FADD: masm.addss(asFloatReg(dst), asFloatReg(src)); break; case FSUB: masm.subss(asFloatReg(dst), asFloatReg(src)); break; @@ -316,6 +331,8 @@ case DOR: masm.orpd(asDoubleReg(dst), asDoubleReg(src)); break; case DXOR: masm.xorpd(asDoubleReg(dst), asDoubleReg(src)); break; + case I2B: masm.movsxb(asIntReg(dst), asIntReg(src)); break; + case I2S: masm.movsxw(asIntReg(dst), asIntReg(src)); break; case I2L: masm.movslq(asLongReg(dst), asIntReg(src)); break; case F2D: masm.cvtss2sd(asDoubleReg(dst), asFloatReg(src)); break; case D2F: masm.cvtsd2ss(asFloatReg(dst), asDoubleReg(src)); break; @@ -325,19 +342,15 @@ case L2D: masm.cvtsi2sdq(asDoubleReg(dst), asLongReg(src)); break; case F2I: masm.cvttss2sil(asIntReg(dst), asFloatReg(src)); - emitConvertFixup(tasm, masm, dst, src); break; case D2I: masm.cvttsd2sil(asIntReg(dst), asDoubleReg(src)); - emitConvertFixup(tasm, masm, dst, src); break; case F2L: masm.cvttss2siq(asLongReg(dst), asFloatReg(src)); - emitConvertFixup(tasm, masm, dst, src); break; case D2L: masm.cvttsd2siq(asLongReg(dst), asDoubleReg(src)); - emitConvertFixup(tasm, masm, dst, src); break; case MOV_I2F: masm.movdl(asFloatReg(dst), asIntReg(src)); break; case MOV_L2D: masm.movdq(asDoubleReg(dst), asLongReg(src)); break; @@ -400,46 +413,75 @@ case LSHR: masm.sarq(asLongReg(dst), tasm.asIntConst(src) & 63); break; case LUSHR:masm.shrq(asLongReg(dst), tasm.asIntConst(src) & 63); break; - case FADD: masm.addss(asFloatReg(dst), tasm.asFloatConstRef(src)); break; - case FSUB: masm.subss(asFloatReg(dst), tasm.asFloatConstRef(src)); break; - case FMUL: masm.mulss(asFloatReg(dst), tasm.asFloatConstRef(src)); break; - case FAND: masm.andps(asFloatReg(dst), tasm.asFloatConstRef(src, 16)); break; - case FOR: masm.orps(asFloatReg(dst), tasm.asFloatConstRef(src, 16)); break; - case FXOR: masm.xorps(asFloatReg(dst), tasm.asFloatConstRef(src, 16)); break; - case FDIV: masm.divss(asFloatReg(dst), tasm.asFloatConstRef(src)); break; + case FADD: masm.addss(asFloatReg(dst), (AMD64Address) tasm.asFloatConstRef(src)); break; + case FSUB: masm.subss(asFloatReg(dst), (AMD64Address) tasm.asFloatConstRef(src)); break; + case FMUL: masm.mulss(asFloatReg(dst), (AMD64Address) tasm.asFloatConstRef(src)); break; + case FAND: masm.andps(asFloatReg(dst), (AMD64Address) tasm.asFloatConstRef(src, 16)); break; + case FOR: masm.orps(asFloatReg(dst), (AMD64Address) tasm.asFloatConstRef(src, 16)); break; + case FXOR: masm.xorps(asFloatReg(dst), (AMD64Address) tasm.asFloatConstRef(src, 16)); break; + case FDIV: masm.divss(asFloatReg(dst), (AMD64Address) tasm.asFloatConstRef(src)); break; - case DADD: masm.addsd(asDoubleReg(dst), tasm.asDoubleConstRef(src)); break; - case DSUB: masm.subsd(asDoubleReg(dst), tasm.asDoubleConstRef(src)); break; - case DMUL: masm.mulsd(asDoubleReg(dst), tasm.asDoubleConstRef(src)); break; - case DDIV: masm.divsd(asDoubleReg(dst), tasm.asDoubleConstRef(src)); break; - case DAND: masm.andpd(asDoubleReg(dst), tasm.asDoubleConstRef(src, 16)); break; - case DOR: masm.orpd(asDoubleReg(dst), tasm.asDoubleConstRef(src, 16)); break; - case DXOR: masm.xorpd(asDoubleReg(dst), tasm.asDoubleConstRef(src, 16)); break; + case DADD: masm.addsd(asDoubleReg(dst), (AMD64Address) tasm.asDoubleConstRef(src)); break; + case DSUB: masm.subsd(asDoubleReg(dst), (AMD64Address) tasm.asDoubleConstRef(src)); break; + case DMUL: masm.mulsd(asDoubleReg(dst), (AMD64Address) tasm.asDoubleConstRef(src)); break; + case DDIV: masm.divsd(asDoubleReg(dst), (AMD64Address) tasm.asDoubleConstRef(src)); break; + case DAND: masm.andpd(asDoubleReg(dst), (AMD64Address) tasm.asDoubleConstRef(src, 16)); break; + case DOR: masm.orpd(asDoubleReg(dst), (AMD64Address) tasm.asDoubleConstRef(src, 16)); break; + case DXOR: masm.xorpd(asDoubleReg(dst), (AMD64Address) tasm.asDoubleConstRef(src, 16)); break; default: throw GraalInternalError.shouldNotReachHere(); } } else { switch (opcode) { - case IADD: masm.addl(asIntReg(dst), tasm.asIntAddr(src)); break; - case ISUB: masm.subl(asIntReg(dst), tasm.asIntAddr(src)); break; - case IAND: masm.andl(asIntReg(dst), tasm.asIntAddr(src)); break; - case IOR: masm.orl(asIntReg(dst), tasm.asIntAddr(src)); break; - case IXOR: masm.xorl(asIntReg(dst), tasm.asIntAddr(src)); break; + case IADD: masm.addl(asIntReg(dst), (AMD64Address) tasm.asIntAddr(src)); break; + case ISUB: masm.subl(asIntReg(dst), (AMD64Address) tasm.asIntAddr(src)); break; + case IAND: masm.andl(asIntReg(dst), (AMD64Address) tasm.asIntAddr(src)); break; + case IMUL: masm.imull(asIntReg(dst), (AMD64Address) tasm.asIntAddr(src)); break; + case IOR: masm.orl(asIntReg(dst), (AMD64Address) tasm.asIntAddr(src)); break; + case IXOR: masm.xorl(asIntReg(dst), (AMD64Address) tasm.asIntAddr(src)); break; + + case LADD: masm.addq(asLongReg(dst), (AMD64Address) tasm.asLongAddr(src)); break; + case LSUB: masm.subq(asLongReg(dst), (AMD64Address) tasm.asLongAddr(src)); break; + case LMUL: masm.imulq(asLongReg(dst), (AMD64Address) tasm.asLongAddr(src)); break; + case LAND: masm.andq(asLongReg(dst), (AMD64Address) tasm.asLongAddr(src)); break; + case LOR: masm.orq(asLongReg(dst), (AMD64Address) tasm.asLongAddr(src)); break; + case LXOR: masm.xorq(asLongReg(dst), (AMD64Address) tasm.asLongAddr(src)); break; + + case FADD: masm.addss(asFloatReg(dst), (AMD64Address) tasm.asFloatAddr(src)); break; + case FSUB: masm.subss(asFloatReg(dst), (AMD64Address) tasm.asFloatAddr(src)); break; + case FMUL: masm.mulss(asFloatReg(dst), (AMD64Address) tasm.asFloatAddr(src)); break; + case FDIV: masm.divss(asFloatReg(dst), (AMD64Address) tasm.asFloatAddr(src)); break; + + case DADD: masm.addsd(asDoubleReg(dst), (AMD64Address) tasm.asDoubleAddr(src)); break; + case DSUB: masm.subsd(asDoubleReg(dst), (AMD64Address) tasm.asDoubleAddr(src)); break; + case DMUL: masm.mulsd(asDoubleReg(dst), (AMD64Address) tasm.asDoubleAddr(src)); break; + case DDIV: masm.divsd(asDoubleReg(dst), (AMD64Address) tasm.asDoubleAddr(src)); break; - case LADD: masm.addq(asLongReg(dst), tasm.asLongAddr(src)); break; - case LSUB: masm.subq(asLongReg(dst), tasm.asLongAddr(src)); break; - case LAND: masm.andq(asLongReg(dst), tasm.asLongAddr(src)); break; - case LOR: masm.orq(asLongReg(dst), tasm.asLongAddr(src)); break; - case LXOR: masm.xorq(asLongReg(dst), tasm.asLongAddr(src)); break; + case I2B: masm.movsxb(asIntReg(dst), (AMD64Address) tasm.asIntAddr(src)); break; + case I2S: masm.movsxw(asIntReg(dst), (AMD64Address) tasm.asIntAddr(src)); break; + case I2L: masm.movslq(asLongReg(dst), (AMD64Address) tasm.asIntAddr(src)); break; + case F2D: masm.cvtss2sd(asDoubleReg(dst), (AMD64Address) tasm.asFloatAddr(src)); break; + case D2F: masm.cvtsd2ss(asFloatReg(dst), (AMD64Address) tasm.asDoubleAddr(src)); break; + case I2F: masm.cvtsi2ssl(asFloatReg(dst), (AMD64Address) tasm.asIntAddr(src)); break; + case I2D: masm.cvtsi2sdl(asDoubleReg(dst), (AMD64Address) tasm.asIntAddr(src)); break; + case L2F: masm.cvtsi2ssq(asFloatReg(dst), (AMD64Address) tasm.asLongAddr(src)); break; + case L2D: masm.cvtsi2sdq(asDoubleReg(dst), (AMD64Address) tasm.asLongAddr(src)); break; + case F2I: + masm.cvttss2sil(asIntReg(dst), (AMD64Address) tasm.asFloatAddr(src)); + break; + case D2I: + masm.cvttsd2sil(asIntReg(dst), (AMD64Address) tasm.asDoubleAddr(src)); + break; + case F2L: + masm.cvttss2siq(asLongReg(dst), (AMD64Address) tasm.asFloatAddr(src)); + break; + case D2L: + masm.cvttsd2siq(asLongReg(dst), (AMD64Address) tasm.asDoubleAddr(src)); + break; + case MOV_I2F: masm.movss(asFloatReg(dst), (AMD64Address) tasm.asIntAddr(src)); break; + case MOV_L2D: masm.movsd(asDoubleReg(dst), (AMD64Address) tasm.asLongAddr(src)); break; + case MOV_F2I: masm.movl(asIntReg(dst), (AMD64Address) tasm.asFloatAddr(src)); break; + case MOV_D2L: masm.movq(asLongReg(dst), (AMD64Address) tasm.asDoubleAddr(src)); break; - case FADD: masm.addss(asFloatReg(dst), tasm.asFloatAddr(src)); break; - case FSUB: masm.subss(asFloatReg(dst), tasm.asFloatAddr(src)); break; - case FMUL: masm.mulss(asFloatReg(dst), tasm.asFloatAddr(src)); break; - case FDIV: masm.divss(asFloatReg(dst), tasm.asFloatAddr(src)); break; - - case DADD: masm.addsd(asDoubleReg(dst), tasm.asDoubleAddr(src)); break; - case DSUB: masm.subsd(asDoubleReg(dst), tasm.asDoubleAddr(src)); break; - case DMUL: masm.mulsd(asDoubleReg(dst), tasm.asDoubleAddr(src)); break; - case DDIV: masm.divsd(asDoubleReg(dst), tasm.asDoubleAddr(src)); break; default: throw GraalInternalError.shouldNotReachHere(); } } @@ -450,67 +492,11 @@ } } - private static void emitConvertFixup(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Value x) { - ConvertSlowPath slowPath = new ConvertSlowPath(result, x); - tasm.stubs.add(slowPath); - switch (result.getKind()) { - case Int: masm.cmpl(asIntReg(result), Integer.MIN_VALUE); break; - case Long: masm.cmpq(asLongReg(result), tasm.asLongConstRef(Constant.forLong(java.lang.Long.MIN_VALUE))); break; - default: throw GraalInternalError.shouldNotReachHere(); - } - masm.jcc(ConditionFlag.equal, slowPath.start); - masm.bind(slowPath.continuation); - } - - private static class ConvertSlowPath extends AMD64Code { - public final Label start = new Label(); - public final Label continuation = new Label(); - private final Value result; - private final Value x; - - public ConvertSlowPath(Value result, Value x) { - this.result = result; - this.x = x; - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - masm.bind(start); - switch (x.getKind()) { - case Float: masm.ucomiss(asFloatReg(x), tasm.asFloatConstRef(Constant.FLOAT_0)); break; - case Double: masm.ucomisd(asDoubleReg(x), tasm.asDoubleConstRef(Constant.DOUBLE_0)); break; - default: throw GraalInternalError.shouldNotReachHere(); - } - Label nan = new Label(); - masm.jcc(ConditionFlag.parity, nan); - masm.jcc(ConditionFlag.below, continuation); - - // input is > 0 -> return maxInt - // result register already contains 0x80000000, so subtracting 1 gives 0x7fffffff - switch (result.getKind()) { - case Int: masm.decrementl(asIntReg(result), 1); break; - case Long: masm.decrementq(asLongReg(result), 1); break; - default: throw GraalInternalError.shouldNotReachHere(); - } - masm.jmp(continuation); - - // input is NaN -> return 0 - masm.bind(nan); - masm.xorptr(asRegister(result), asRegister(result)); - masm.jmp(continuation); - } - - @Override - public String description() { - return "convert " + x + " to " + result; - } - } - - private static void verifyKind(AMD64Arithmetic 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) || (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) + || (opcode.name().matches(".U?SH.") && result.getKind() == x.getKind() && y.getKind() == Kind.Int && (isConstant(y) || asRegister(y) == AMD64.rcx)); } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java Thu Mar 21 14:11:13 2013 +0100 @@ -23,7 +23,6 @@ package com.oracle.graal.lir.amd64; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.lir.asm.*; @@ -34,10 +33,10 @@ } @Opcode private final IntrinsicOpcode opcode; - @Def protected Value result; - @Use({OperandFlag.REG, OperandFlag.ADDR}) protected Value input; + @Def protected AllocatableValue result; + @Use({OperandFlag.REG, OperandFlag.STACK}) protected AllocatableValue input; - public AMD64BitManipulationOp(IntrinsicOpcode opcode, Value result, Value input) { + public AMD64BitManipulationOp(IntrinsicOpcode opcode, AllocatableValue result, AllocatableValue input) { this.opcode = opcode; this.result = result; this.input = input; @@ -46,8 +45,8 @@ @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { Register dst = ValueUtil.asIntReg(result); - if (ValueUtil.isAddress(input)) { - Address src = ValueUtil.asAddress(input); + if (ValueUtil.isRegister(input)) { + Register src = ValueUtil.asRegister(input); switch (opcode) { case IPOPCNT: masm.popcntl(dst, src); @@ -66,7 +65,7 @@ break; } } else { - Register src = ValueUtil.asRegister(input); + AMD64Address src = (AMD64Address) tasm.asAddress(input); switch (opcode) { case IPOPCNT: masm.popcntl(dst, src); diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java Thu Mar 21 14:11:13 2013 +0100 @@ -26,17 +26,15 @@ import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.amd64.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.LIRInstruction.Opcode; import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.spi.*; public class AMD64Call { - public static final Descriptor DEBUG = new Descriptor("debug", false, void.class); - @Opcode("CALL_DIRECT") public static class DirectCallOp extends AMD64LIRInstruction implements StandardOp.CallOp { @@ -45,9 +43,9 @@ @Temp protected Value[] temps; @State protected LIRFrameState state; - protected final Object callTarget; + protected final ResolvedJavaMethod callTarget; - public DirectCallOp(Object callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { + public DirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { this.callTarget = callTarget; this.result = result; this.parameters = parameters; @@ -58,15 +56,59 @@ @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - emitAlignmentForDirectCall(tasm, masm); - directCall(tasm, masm, callTarget, state); + 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; + this.result = result; + this.parameters = parameters; + this.state = state; + this.temps = temps; + assert temps != null; } - protected void emitAlignmentForDirectCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - // make sure that the displacement word of the call ends up word aligned - int offset = masm.codeBuffer.position(); - offset += tasm.target.arch.getMachineCodeCallDisplacementOffset(); - masm.nop(tasm.target.wordSize - offset % tasm.target.wordSize); + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + directCall(tasm, masm, callTarget, null, false, state); + } + } + + @Opcode("CALL_FAR_RUNTIME") + public static class DirectFarRuntimeCallOp 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; + @Temp({REG}) protected AllocatableValue callTemp; + + protected final RuntimeCallTarget callTarget; + + public DirectFarRuntimeCallOp(LIRGeneratorTool gen, RuntimeCallTarget 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; + callTemp = gen.newVariable(Kind.Long); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + directCall(tasm, masm, callTarget, ((RegisterValue) callTemp).getRegister(), false, state); } } @@ -79,9 +121,9 @@ @Temp protected Value[] temps; @State protected LIRFrameState state; - protected final Object callTarget; + protected final InvokeTarget callTarget; - public IndirectCallOp(Object callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, LIRFrameState state) { + public IndirectCallOp(InvokeTarget callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, LIRFrameState state) { this.callTarget = callTarget; this.result = result; this.parameters = parameters; @@ -103,53 +145,49 @@ } } - public static void directCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Object callTarget, LIRFrameState info) { + public static void directCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, InvokeTarget callTarget, Register scratch, boolean align, LIRFrameState info) { + if (align) { + emitAlignmentForDirectCall(tasm, masm); + } int before = masm.codeBuffer.position(); - if (callTarget instanceof RuntimeCallTarget) { - long maxOffset = ((RuntimeCallTarget) callTarget).getMaxCallTargetOffset(); - if (maxOffset != (int) maxOffset) { - // offset might not fit a 32-bit immediate, generate an - // indirect call with a 64-bit immediate - Register scratch = tasm.frameMap.registerConfig.getScratchRegister(); - masm.movq(scratch, 0L); - masm.call(scratch); - } else { - masm.call(); - } - + if (scratch != null) { + // offset might not fit a 32-bit immediate, generate an + // indirect call with a 64-bit immediate + masm.movq(scratch, 0L); + masm.call(scratch); } else { masm.call(); } int after = masm.codeBuffer.position(); - tasm.recordDirectCall(before, after, tasm.runtime.lookupCallTarget(callTarget), info); + tasm.recordDirectCall(before, after, callTarget, info); tasm.recordExceptionHandlers(after, info); masm.ensureUniquePC(); } - public static void directJmp(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Object target) { + protected static void emitAlignmentForDirectCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + // make sure that the displacement word of the call ends up word aligned + int offset = masm.codeBuffer.position(); + offset += tasm.target.arch.getMachineCodeCallDisplacementOffset(); + int modulus = tasm.target.wordSize; + if (offset % modulus != 0) { + masm.nop(modulus - offset % modulus); + } + } + + public static void directJmp(TargetMethodAssembler tasm, AMD64MacroAssembler masm, InvokeTarget target) { int before = masm.codeBuffer.position(); masm.jmp(0, true); int after = masm.codeBuffer.position(); - tasm.recordDirectCall(before, after, tasm.runtime.lookupCallTarget(target), null); + tasm.recordDirectCall(before, after, target, null); masm.ensureUniquePC(); } - public static void indirectCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Register dst, Object callTarget, LIRFrameState info) { + public static void indirectCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) { int before = masm.codeBuffer.position(); masm.call(dst); int after = masm.codeBuffer.position(); - tasm.recordIndirectCall(before, after, tasm.runtime.lookupCallTarget(callTarget), info); + tasm.recordIndirectCall(before, after, callTarget, info); tasm.recordExceptionHandlers(after, info); masm.ensureUniquePC(); } - - public static void shouldNotReachHere(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - boolean assertions = false; - assert (assertions = true) == true; - - if (assertions) { - directCall(tasm, masm, tasm.runtime.lookupRuntimeCall(DEBUG), null); - masm.hlt(); - } - } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Code.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Code.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +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.lir.amd64; - -import com.oracle.graal.asm.amd64.*; -import com.oracle.graal.lir.*; -import com.oracle.graal.lir.asm.*; - -/** - * Convenience class to provide AMD64MacroAssembler for the {@link #emitCode} method. - */ -public abstract class AMD64Code implements LIR.Code { - - @Override - public final void emitCode(TargetMethodAssembler tasm) { - emitCode(tasm, (AMD64MacroAssembler) tasm.asm); - } - - public abstract void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm); -} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java Thu Mar 21 14:11:13 2013 +0100 @@ -54,7 +54,6 @@ protected void verify() { super.verify(); assert (name().startsWith("I") && x.getKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) - || (name().startsWith("I") && x.getKind() == Kind.Jsr && y.getKind() == Kind.Jsr) || (name().startsWith("L") && x.getKind() == Kind.Long && y.getKind() == Kind.Long) || (name().startsWith("A") && x.getKind() == Kind.Object && y.getKind() == Kind.Object) || (name().startsWith("F") && x.getKind() == Kind.Float && y.getKind() == Kind.Float) @@ -82,17 +81,17 @@ } else { throw GraalInternalError.shouldNotReachHere("Only null object constants are allowed in comparisons"); } - case FCMP: masm.ucomiss(asFloatReg(x), tasm.asFloatConstRef(y)); break; - case DCMP: masm.ucomisd(asDoubleReg(x), tasm.asDoubleConstRef(y)); break; + case FCMP: masm.ucomiss(asFloatReg(x), (AMD64Address) tasm.asFloatConstRef(y)); break; + case DCMP: masm.ucomisd(asDoubleReg(x), (AMD64Address) tasm.asDoubleConstRef(y)); break; default: throw GraalInternalError.shouldNotReachHere(); } } else { switch (opcode) { - case ICMP: masm.cmpl(asIntReg(x), tasm.asIntAddr(y)); break; - case LCMP: masm.cmpq(asLongReg(x), tasm.asLongAddr(y)); break; - case ACMP: masm.cmpptr(asObjectReg(x), tasm.asObjectAddr(y)); break; - case FCMP: masm.ucomiss(asFloatReg(x), tasm.asFloatAddr(y)); break; - case DCMP: masm.ucomisd(asDoubleReg(x), tasm.asDoubleAddr(y)); break; + case ICMP: masm.cmpl(asIntReg(x), (AMD64Address) tasm.asIntAddr(y)); break; + case LCMP: masm.cmpq(asLongReg(x), (AMD64Address) tasm.asLongAddr(y)); break; + case ACMP: masm.cmpptr(asObjectReg(x), (AMD64Address) tasm.asObjectAddr(y)); break; + case FCMP: masm.ucomiss(asFloatReg(x), (AMD64Address) tasm.asFloatAddr(y)); break; + case DCMP: masm.ucomisd(asDoubleReg(x), (AMD64Address) tasm.asDoubleAddr(y)); break; default: throw GraalInternalError.shouldNotReachHere(); } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java Thu Mar 21 14:11:13 2013 +0100 @@ -26,13 +26,13 @@ import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; import com.oracle.graal.amd64.*; +import com.oracle.graal.api.code.CompilationResult.JumpTable; import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.Address.Scale; -import com.oracle.graal.api.code.CompilationResult.JumpTable; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.asm.amd64.AMD64Address.Scale; import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag; -import com.oracle.graal.asm.amd64.*; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.LIRInstruction.Opcode; @@ -63,16 +63,14 @@ public static class BranchOp extends AMD64LIRInstruction implements StandardOp.BranchOp { protected ConditionFlag condition; protected LabelRef destination; - @State protected LIRFrameState state; - public BranchOp(Condition condition, LabelRef destination, LIRFrameState info) { - this(intCond(condition), destination, info); + public BranchOp(Condition condition, LabelRef destination) { + this(intCond(condition), destination); } - public BranchOp(ConditionFlag condition, LabelRef destination, LIRFrameState state) { + public BranchOp(ConditionFlag condition, LabelRef destination) { this.condition = condition; this.destination = destination; - this.state = state; } @Override @@ -96,8 +94,8 @@ public static class FloatBranchOp extends BranchOp { protected boolean unorderedIsTrue; - public FloatBranchOp(Condition condition, boolean unorderedIsTrue, LabelRef destination, LIRFrameState info) { - super(floatCond(condition), destination, info); + public FloatBranchOp(Condition condition, boolean unorderedIsTrue, LabelRef destination) { + super(floatCond(condition), destination); this.unorderedIsTrue = unorderedIsTrue; } @@ -162,13 +160,13 @@ long lc = keyConstants[i].asLong(); assert NumUtil.isInt(lc); masm.cmpl(intKey, (int) lc); - masm.jcc(ConditionFlag.equal, keyTargets[i].label()); + masm.jcc(ConditionFlag.Equal, keyTargets[i].label()); } } else if (key.getKind() == Kind.Long) { Register longKey = asLongReg(key); for (int i = 0; i < keyConstants.length; i++) { - masm.cmpq(longKey, tasm.asLongConstRef(keyConstants[i])); - masm.jcc(ConditionFlag.equal, keyTargets[i].label()); + masm.cmpq(longKey, (AMD64Address) tasm.asLongConstRef(keyConstants[i])); + masm.jcc(ConditionFlag.Equal, keyTargets[i].label()); } } else if (key.getKind() == Kind.Object) { Register intKey = asObjectReg(key); @@ -176,7 +174,7 @@ for (int i = 0; i < keyConstants.length; i++) { AMD64Move.move(tasm, masm, temp.asValue(Kind.Object), keyConstants[i]); masm.cmpptr(intKey, temp); - masm.jcc(ConditionFlag.equal, keyTargets[i].label()); + masm.jcc(ConditionFlag.Equal, keyTargets[i].label()); } } else { throw new GraalInternalError("sequential switch only supported for int, long and object"); @@ -226,15 +224,15 @@ int highKey = highKeys[i]; if (lowKey == highKey) { masm.cmpl(asIntReg(key), lowKey); - masm.jcc(ConditionFlag.equal, keyTargets[i].label()); + masm.jcc(ConditionFlag.Equal, keyTargets[i].label()); skipLowCheck = false; } else { if (!skipLowCheck || (prevHighKey + 1) != lowKey) { masm.cmpl(asIntReg(key), lowKey); - masm.jcc(ConditionFlag.less, actualDefaultTarget); + masm.jcc(ConditionFlag.Less, actualDefaultTarget); } masm.cmpl(asIntReg(key), highKey); - masm.jcc(ConditionFlag.lessEqual, keyTargets[i].label()); + masm.jcc(ConditionFlag.LessEqual, keyTargets[i].label()); skipLowCheck = true; } prevHighKey = highKey; @@ -333,16 +331,16 @@ // Jump to default target if index is not within the jump table if (defaultTarget != null) { - masm.jcc(ConditionFlag.above, defaultTarget.label()); + masm.jcc(ConditionFlag.Above, defaultTarget.label()); } // Set scratch to address of jump table int leaPos = buf.position(); - masm.leaq(scratch, new Address(tasm.target.wordKind, AMD64.rip.asValue(), 0)); + masm.leaq(scratch, new AMD64Address(AMD64.rip, 0)); int afterLea = buf.position(); // Load jump table entry into scratch and jump to it - masm.movslq(value, new Address(Kind.Int, scratch.asValue(), value.asValue(), Scale.Times4, 0)); + masm.movslq(value, new AMD64Address(scratch, value, Scale.Times4, 0)); masm.addq(scratch, value); masm.jmp(scratch); @@ -354,7 +352,7 @@ // Patch LEA instruction above now that we know the position of the jump table int jumpTablePos = buf.position(); buf.setPosition(leaPos); - masm.leaq(scratch, new Address(tasm.target.wordKind, AMD64.rip.asValue(), jumpTablePos - afterLea)); + masm.leaq(scratch, new AMD64Address(AMD64.rip, jumpTablePos - afterLea)); buf.setPosition(jumpTablePos); // Emit jump table entries @@ -374,15 +372,15 @@ } JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, 4); - tasm.targetMethod.addAnnotation(jt); + tasm.compilationResult.addAnnotation(jt); } private static void floatJcc(AMD64MacroAssembler masm, ConditionFlag condition, boolean unorderedIsTrue, Label label) { Label endLabel = new Label(); if (unorderedIsTrue && !trueOnUnordered(condition)) { - masm.jcc(ConditionFlag.parity, label); + masm.jcc(ConditionFlag.Parity, label); } else if (!unorderedIsTrue && trueOnUnordered(condition)) { - masm.jcc(ConditionFlag.parity, endLabel); + masm.jccb(ConditionFlag.Parity, endLabel); } masm.jcc(condition, label); masm.bind(endLabel); @@ -397,9 +395,9 @@ if (isFloat) { if (unorderedIsTrue && !trueOnUnordered(condition)) { - cmove(tasm, masm, result, ConditionFlag.parity, trueValue); + cmove(tasm, masm, result, ConditionFlag.Parity, trueValue); } else if (!unorderedIsTrue && trueOnUnordered(condition)) { - cmove(tasm, masm, result, ConditionFlag.parity, falseValue); + cmove(tasm, masm, result, ConditionFlag.Parity, falseValue); } } } @@ -413,9 +411,10 @@ default: throw GraalInternalError.shouldNotReachHere(); } } else { + AMD64Address addr = (AMD64Address) tasm.asAddress(other); switch (other.getKind()) { - case Int: masm.cmovl(cond, asRegister(result), tasm.asAddress(other)); break; - case Long: masm.cmovq(cond, asRegister(result), tasm.asAddress(other)); break; + case Int: masm.cmovl(cond, asRegister(result), addr); break; + case Long: masm.cmovq(cond, asRegister(result), addr); break; default: throw GraalInternalError.shouldNotReachHere(); } } @@ -423,45 +422,45 @@ private static ConditionFlag intCond(Condition cond) { switch (cond) { - case EQ: return ConditionFlag.equal; - case NE: return ConditionFlag.notEqual; - case LT: return ConditionFlag.less; - case LE: return ConditionFlag.lessEqual; - case GE: return ConditionFlag.greaterEqual; - case GT: return ConditionFlag.greater; - case BE: return ConditionFlag.belowEqual; - case AE: return ConditionFlag.aboveEqual; - case AT: return ConditionFlag.above; - case BT: return ConditionFlag.below; + case EQ: return ConditionFlag.Equal; + case NE: return ConditionFlag.NotEqual; + case LT: return ConditionFlag.Less; + case LE: return ConditionFlag.LessEqual; + case GE: return ConditionFlag.GreaterEqual; + case GT: return ConditionFlag.Greater; + case BE: return ConditionFlag.BelowEqual; + case AE: return ConditionFlag.AboveEqual; + case AT: return ConditionFlag.Above; + case BT: return ConditionFlag.Below; default: throw GraalInternalError.shouldNotReachHere(); } } private static ConditionFlag floatCond(Condition cond) { switch (cond) { - case EQ: return ConditionFlag.equal; - case NE: return ConditionFlag.notEqual; - case LT: return ConditionFlag.below; - case LE: return ConditionFlag.belowEqual; - case GE: return ConditionFlag.aboveEqual; - case GT: return ConditionFlag.above; + case EQ: return ConditionFlag.Equal; + case NE: return ConditionFlag.NotEqual; + case LT: return ConditionFlag.Below; + case LE: return ConditionFlag.BelowEqual; + case GE: return ConditionFlag.AboveEqual; + case GT: return ConditionFlag.Above; default: throw GraalInternalError.shouldNotReachHere(); } } private static boolean trueOnUnordered(ConditionFlag condition) { switch(condition) { - case aboveEqual: - case notEqual: - case above: - case less: - case overflow: + case AboveEqual: + case NotEqual: + case Above: + case Less: + case Overflow: return false; - case equal: - case belowEqual: - case below: - case greaterEqual: - case noOverflow: + case Equal: + case BelowEqual: + case Below: + case GreaterEqual: + case NoOverflow: return true; default: throw GraalInternalError.shouldNotReachHere(); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -24,6 +24,7 @@ import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + import static java.lang.Double.*; import static java.lang.Float.*; @@ -38,37 +39,11 @@ import com.oracle.graal.lir.StandardOp.MoveOp; import com.oracle.graal.lir.asm.*; -// @formatter:off public class AMD64Move { @Opcode("MOVE") - public static class SpillMoveOp extends AMD64LIRInstruction implements MoveOp { - @Def({REG, STACK}) protected Value result; - @Use({REG, STACK, CONST}) protected Value input; - - public SpillMoveOp(Value result, Value input) { - this.result = result; - this.input = input; - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - move(tasm, masm, getResult(), getInput()); - } + public static class MoveToRegOp extends AMD64LIRInstruction implements MoveOp { - @Override - public Value getInput() { - return input; - } - @Override - public Value getResult() { - return result; - } - } - - - @Opcode("MOVE") - public static class MoveToRegOp extends AMD64LIRInstruction implements MoveOp { @Def({REG, HINT}) protected Value result; @Use({REG, STACK, CONST}) protected Value input; @@ -86,15 +61,16 @@ public Value getInput() { return input; } + @Override public Value getResult() { return result; } } - @Opcode("MOVE") public static class MoveFromRegOp extends AMD64LIRInstruction implements MoveOp { + @Def({REG, STACK}) protected Value result; @Use({REG, CONST, HINT}) protected Value input; @@ -112,66 +88,201 @@ public Value getInput() { return input; } + @Override public Value getResult() { return result; } } + public abstract static class MemOp extends AMD64LIRInstruction { - public static class LoadOp extends AMD64LIRInstruction { - @Def({REG}) protected Value result; - @Use({ADDR}) protected Value address; + @Use({COMPOSITE}) protected AMD64AddressValue address; @State protected LIRFrameState state; - public LoadOp(Value result, Value address, LIRFrameState state) { - this.result = result; + public MemOp(AMD64AddressValue address, LIRFrameState state) { this.address = address; this.state = state; } + protected abstract void emitMemAccess(AMD64MacroAssembler masm); + @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - load(tasm, masm, result, (Address) address, state); + if (state != null) { + tasm.recordImplicitException(masm.codeBuffer.position(), state); + } + emitMemAccess(masm); + } + } + + public static class LoadOp extends MemOp { + + @Def({REG}) protected AllocatableValue result; + + public LoadOp(AllocatableValue result, AMD64AddressValue address, LIRFrameState state) { + super(address, state); + this.result = result; + } + + @Override + public void emitMemAccess(AMD64MacroAssembler masm) { + switch (address.getKind()) { + case Boolean: + case Byte: + masm.movsxb(asRegister(result), address.toAddress()); + break; + case Char: + masm.movzxl(asRegister(result), address.toAddress()); + break; + case Short: + masm.movswl(asRegister(result), address.toAddress()); + break; + case Int: + masm.movslq(asRegister(result), address.toAddress()); + break; + case Long: + masm.movq(asRegister(result), address.toAddress()); + break; + case Float: + masm.movflt(asFloatReg(result), address.toAddress()); + break; + case Double: + masm.movdbl(asDoubleReg(result), address.toAddress()); + break; + case Object: + masm.movq(asRegister(result), address.toAddress()); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } } } + public static class StoreOp extends MemOp { - public static class StoreOp extends AMD64LIRInstruction { - @Use({ADDR}) protected Value address; - @Use({REG, CONST}) protected Value input; - @State protected LIRFrameState state; + @Use({REG}) protected AllocatableValue input; - public StoreOp(Value address, Value input, LIRFrameState state) { - this.address = address; + public StoreOp(AMD64AddressValue address, AllocatableValue input, LIRFrameState state) { + super(address, state); this.input = input; - this.state = state; } @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - store(tasm, masm, (Address) address, input, state); + public void emitMemAccess(AMD64MacroAssembler masm) { + assert isRegister(input); + switch (address.getKind()) { + case Boolean: + case Byte: + masm.movb(address.toAddress(), asRegister(input)); + break; + case Char: + case Short: + masm.movw(address.toAddress(), asRegister(input)); + break; + case Int: + masm.movl(address.toAddress(), asRegister(input)); + break; + case Long: + masm.movq(address.toAddress(), asRegister(input)); + break; + case Float: + masm.movflt(address.toAddress(), asFloatReg(input)); + break; + case Double: + masm.movsd(address.toAddress(), asDoubleReg(input)); + break; + case Object: + masm.movq(address.toAddress(), asRegister(input)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } } } + public static class StoreConstantOp extends MemOp { + + protected final Constant input; + + public StoreConstantOp(AMD64AddressValue address, Constant input, LIRFrameState state) { + super(address, state); + this.input = input; + } + + @Override + public void emitMemAccess(AMD64MacroAssembler masm) { + switch (address.getKind()) { + case Boolean: + case Byte: + masm.movb(address.toAddress(), input.asInt() & 0xFF); + break; + case Char: + case Short: + masm.movw(address.toAddress(), input.asInt() & 0xFFFF); + break; + case Int: + masm.movl(address.toAddress(), input.asInt()); + break; + case Long: + if (NumUtil.isInt(input.asLong())) { + masm.movslq(address.toAddress(), (int) input.asLong()); + } else { + throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); + } + break; + case Float: + masm.movl(address.toAddress(), floatToRawIntBits(input.asFloat())); + break; + case Double: + throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); + case Object: + if (input.isNull()) { + masm.movptr(address.toAddress(), 0); + } else { + throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); + } + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + } public static class LeaOp extends AMD64LIRInstruction { - @Def({REG}) protected Value result; - @Use({ADDR, STACK, UNINITIALIZED}) protected Value address; - public LeaOp(Value result, Value address) { + @Def({REG}) protected AllocatableValue result; + @Use({COMPOSITE, UNINITIALIZED}) protected AMD64AddressValue address; + + public LeaOp(AllocatableValue result, AMD64AddressValue address) { this.result = result; this.address = address; } @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - masm.leaq(asLongReg(result), tasm.asAddress(address)); + masm.leaq(asLongReg(result), address.toAddress()); } } + public static class StackLeaOp extends AMD64LIRInstruction { + + @Def({REG}) protected AllocatableValue result; + @Use({STACK, UNINITIALIZED}) protected StackSlot slot; + + public StackLeaOp(AllocatableValue result, StackSlot slot) { + this.result = result; + this.slot = slot; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + masm.leaq(asLongReg(result), (AMD64Address) tasm.asAddress(slot)); + } + } public static class MembarOp extends AMD64LIRInstruction { + private final int barriers; public MembarOp(final int barriers) { @@ -184,9 +295,9 @@ } } + public static class NullCheckOp extends AMD64LIRInstruction { - public static class NullCheckOp extends AMD64LIRInstruction { - @Use protected Value input; + @Use({REG}) protected AllocatableValue input; @State protected LIRFrameState state; public NullCheckOp(Variable input, LIRFrameState state) { @@ -201,15 +312,15 @@ } } - @Opcode("CAS") public static class CompareAndSwapOp extends AMD64LIRInstruction { - @Def protected Value result; - @Use({ADDR}) protected Value address; - @Use protected Value cmpValue; - @Use protected Value newValue; - public CompareAndSwapOp(Value result, Address address, Value cmpValue, Value newValue) { + @Def protected AllocatableValue result; + @Use({COMPOSITE}) protected AMD64AddressValue address; + @Use protected AllocatableValue cmpValue; + @Use protected AllocatableValue newValue; + + public CompareAndSwapOp(AllocatableValue result, AMD64AddressValue address, AllocatableValue cmpValue, AllocatableValue newValue) { this.result = result; this.address = address; this.cmpValue = cmpValue; @@ -218,11 +329,10 @@ @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - compareAndSwap(tasm, masm, result, (Address) address, cmpValue, newValue); + compareAndSwap(tasm, masm, result, address, cmpValue, newValue); } } - public static void move(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Value input) { if (isRegister(input)) { if (isRegister(result)) { @@ -256,46 +366,80 @@ return; } switch (input.getKind()) { - case Jsr: - case Int: masm.movl(asRegister(result), asRegister(input)); break; - case Long: masm.movq(asRegister(result), asRegister(input)); break; - case Float: masm.movflt(asFloatReg(result), asFloatReg(input)); break; - case Double: masm.movdbl(asDoubleReg(result), asDoubleReg(input)); break; - case Object: masm.movq(asRegister(result), asRegister(input)); break; - default: throw GraalInternalError.shouldNotReachHere("kind=" + result.getKind()); + case Int: + masm.movl(asRegister(result), asRegister(input)); + break; + case Long: + masm.movq(asRegister(result), asRegister(input)); + break; + case Float: + masm.movflt(asFloatReg(result), asFloatReg(input)); + break; + case Double: + masm.movdbl(asDoubleReg(result), asDoubleReg(input)); + break; + case Object: + masm.movq(asRegister(result), asRegister(input)); + break; + default: + throw GraalInternalError.shouldNotReachHere("kind=" + result.getKind()); } } private static void reg2stack(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Value input) { + AMD64Address dest = (AMD64Address) tasm.asAddress(result); switch (input.getKind()) { - case Jsr: - case Int: masm.movl(tasm.asAddress(result), asRegister(input)); break; - case Long: masm.movq(tasm.asAddress(result), asRegister(input)); break; - case Float: masm.movflt(tasm.asAddress(result), asFloatReg(input)); break; - case Double: masm.movsd(tasm.asAddress(result), asDoubleReg(input)); break; - case Object: masm.movq(tasm.asAddress(result), asRegister(input)); break; - default: throw GraalInternalError.shouldNotReachHere(); + case Int: + masm.movl(dest, asRegister(input)); + break; + case Long: + masm.movq(dest, asRegister(input)); + break; + case Float: + masm.movflt(dest, asFloatReg(input)); + break; + case Double: + masm.movsd(dest, asDoubleReg(input)); + break; + case Object: + masm.movq(dest, asRegister(input)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); } } private static void stack2reg(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Value input) { + AMD64Address src = (AMD64Address) tasm.asAddress(input); switch (input.getKind()) { - case Jsr: - case Int: masm.movl(asRegister(result), tasm.asAddress(input)); break; - case Long: masm.movq(asRegister(result), tasm.asAddress(input)); break; - case Float: masm.movflt(asFloatReg(result), tasm.asAddress(input)); break; - case Double: masm.movdbl(asDoubleReg(result), tasm.asAddress(input)); break; - case Object: masm.movq(asRegister(result), tasm.asAddress(input)); break; - default: throw GraalInternalError.shouldNotReachHere(); + case Int: + masm.movl(asRegister(result), src); + break; + case Long: + masm.movq(asRegister(result), src); + break; + case Float: + masm.movflt(asFloatReg(result), src); + break; + case Double: + masm.movdbl(asDoubleReg(result), src); + break; + case Object: + masm.movq(asRegister(result), src); + break; + default: + throw GraalInternalError.shouldNotReachHere(); } } private static void const2reg(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Constant input) { - // Note: we use the kind of the input operand (and not the kind of the result operand) because they don't match - // in all cases. For example, an object constant can be loaded to a long register when unsafe casts occurred (e.g., - // for a write barrier where arithmetic operations are then performed on the pointer). + /* + * Note: we use the kind of the input operand (and not the kind of the result operand) + * because they don't match in all cases. For example, an object constant can be loaded to a + * long register when unsafe casts occurred (e.g., for a write barrier where arithmetic + * operations are then performed on the pointer). + */ switch (input.getKind().getStackKind()) { - case Jsr: case Int: if (tasm.runtime.needsDataPatch(input)) { tasm.recordDataReferenceInCode(input, 0, true); @@ -321,7 +465,7 @@ assert !tasm.runtime.needsDataPatch(input); masm.xorps(asFloatReg(result), asFloatReg(result)); } else { - masm.movflt(asFloatReg(result), tasm.asFloatConstRef(input)); + masm.movflt(asFloatReg(result), (AMD64Address) tasm.asFloatConstRef(input)); } break; case Double: @@ -330,7 +474,7 @@ assert !tasm.runtime.needsDataPatch(input); masm.xorpd(asDoubleReg(result), asDoubleReg(result)); } else { - masm.movdbl(asDoubleReg(result), tasm.asDoubleConstRef(input)); + masm.movdbl(asDoubleReg(result), (AMD64Address) tasm.asDoubleConstRef(input)); } break; case Object: @@ -343,7 +487,7 @@ tasm.recordDataReferenceInCode(input, 0, true); masm.movq(asRegister(result), 0xDEADDEADDEADDEADL); } else { - masm.movq(asRegister(result), tasm.recordDataReferenceInCode(input, 0, false)); + masm.movq(asRegister(result), (AMD64Address) tasm.recordDataReferenceInCode(input, 0, false)); } break; default: @@ -353,15 +497,23 @@ private static void const2stack(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Constant input) { assert !tasm.runtime.needsDataPatch(input); + AMD64Address dest = (AMD64Address) tasm.asAddress(result); switch (input.getKind().getStackKind()) { - case Jsr: - case Int: masm.movl(tasm.asAddress(result), input.asInt()); break; - case Long: masm.movlong(tasm.asAddress(result), input.asLong()); break; - case Float: masm.movl(tasm.asAddress(result), floatToRawIntBits(input.asFloat())); break; - case Double: masm.movlong(tasm.asAddress(result), doubleToRawLongBits(input.asDouble())); break; + case Int: + masm.movl(dest, input.asInt()); + break; + case Long: + masm.movlong(dest, input.asLong()); + break; + case Float: + masm.movl(dest, floatToRawIntBits(input.asFloat())); + break; + case Double: + masm.movlong(dest, doubleToRawLongBits(input.asDouble())); + break; case Object: if (input.isNull()) { - masm.movlong(tasm.asAddress(result), 0L); + masm.movlong(dest, 0L); } else { throw GraalInternalError.shouldNotReachHere("Non-null object constants must be in register"); } @@ -371,88 +523,22 @@ } } - - public static void load(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Address loadAddr, LIRFrameState info) { - if (info != null) { - tasm.recordImplicitException(masm.codeBuffer.position(), info); - } - switch (loadAddr.getKind()) { - case Boolean: - case Byte: masm.movsxb(asRegister(result), loadAddr); break; - case Char: masm.movzxl(asRegister(result), loadAddr); break; - case Short: masm.movswl(asRegister(result), loadAddr); break; - case Int: masm.movslq(asRegister(result), loadAddr); break; - case Long: masm.movq(asRegister(result), loadAddr); break; - case Float: masm.movflt(asFloatReg(result), loadAddr); break; - case Double: masm.movdbl(asDoubleReg(result), loadAddr); break; - case Object: masm.movq(asRegister(result), loadAddr); break; - default: throw GraalInternalError.shouldNotReachHere(); - } - } - - public static void store(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Address storeAddr, Value input, LIRFrameState info) { - if (info != null) { - tasm.recordImplicitException(masm.codeBuffer.position(), info); - } - - if (isRegister(input)) { - switch (storeAddr.getKind()) { - case Boolean: - case Byte: masm.movb(storeAddr, asRegister(input)); break; - case Char: - case Short: masm.movw(storeAddr, asRegister(input)); break; - case Int: masm.movl(storeAddr, asRegister(input)); break; - case Long: masm.movq(storeAddr, asRegister(input)); break; - case Float: masm.movflt(storeAddr, asFloatReg(input)); break; - case Double: masm.movsd(storeAddr, asDoubleReg(input)); break; - case Object: masm.movq(storeAddr, asRegister(input)); break; - default: throw GraalInternalError.shouldNotReachHere(); - } - } else if (isConstant(input)) { - Constant c = (Constant) input; - switch (storeAddr.getKind()) { - case Boolean: - case Byte: masm.movb(storeAddr, c.asInt() & 0xFF); break; - case Char: - case Short: masm.movw(storeAddr, c.asInt() & 0xFFFF); break; - case Jsr: - case Int: masm.movl(storeAddr, c.asInt()); break; - case Long: - if (NumUtil.isInt(c.asLong())) { - masm.movslq(storeAddr, (int) c.asLong()); - } else { - throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); - } - break; - case Float: masm.movl(storeAddr, floatToRawIntBits(c.asFloat())); break; - case Double: throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); - case Object: - if (c.isNull()) { - masm.movptr(storeAddr, 0); - } else { - throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); - } - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - - } else { - throw GraalInternalError.shouldNotReachHere(); - } - } - - protected static void compareAndSwap(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Address address, Value cmpValue, Value newValue) { + protected static void compareAndSwap(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AllocatableValue result, AMD64AddressValue address, AllocatableValue cmpValue, AllocatableValue newValue) { assert asRegister(cmpValue) == AMD64.rax && asRegister(result) == AMD64.rax; if (tasm.target.isMP) { masm.lock(); } switch (cmpValue.getKind()) { - case Int: masm.cmpxchgl(asRegister(newValue), address); break; + case Int: + masm.cmpxchgl(asRegister(newValue), address.toAddress()); + break; case Long: - case Object: masm.cmpxchgq(asRegister(newValue), address); break; - default: throw GraalInternalError.shouldNotReachHere(); + case Object: + masm.cmpxchgq(asRegister(newValue), address.toAddress()); + break; + default: + throw GraalInternalError.shouldNotReachHere(); } } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestOp.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestOp.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestOp.java Thu Mar 21 14:11:13 2013 +0100 @@ -77,10 +77,10 @@ } else { switch (x.getKind()) { case Int: - masm.testl(asIntReg(x), tasm.asIntAddr(y)); + masm.testl(asIntReg(x), (AMD64Address) tasm.asIntAddr(y)); break; case Long: - masm.testq(asLongReg(x), tasm.asLongAddr(y)); + masm.testq(asLongReg(x), (AMD64Address) tasm.asLongAddr(y)); break; default: throw GraalInternalError.shouldNotReachHere(); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,106 @@ +/* + * 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.ptx; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.ptx.*; +import com.oracle.graal.lir.*; + +/** + * Represents an address in target machine memory, specified via some combination of a base register + * and a displacement. + */ +public final class PTXAddressValue extends CompositeValue { + + private static final long serialVersionUID = 1802222435353022623L; + + @Component({REG, UNUSED}) private AllocatableValue base; + private final long displacement; + + /** + * Creates an {@link PTXAddressValue} with given base register and no displacement. + * + * @param kind the kind of the value being addressed + * @param base the base register + */ + public PTXAddressValue(Kind kind, AllocatableValue base) { + this(kind, base, 0); + } + + /** + * Creates an {@link PTXAddressValue} with given base register and a displacement. This is the + * most general constructor. + * + * @param kind the kind of the value being addressed + * @param base the base register + * @param displacement the displacement + */ + public PTXAddressValue(Kind kind, AllocatableValue base, long displacement) { + super(kind); + this.base = base; + this.displacement = displacement; + + assert !isStackSlot(base); + } + + public PTXAddress toAddress() { + Register baseReg = base == AllocatableValue.UNUSED ? Register.None : asRegister(base); + return new PTXAddress(baseReg, displacement); + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder(); + s.append(getKind().getJavaName()).append("["); + String sep = ""; + if (isLegal(base)) { + s.append(base); + sep = " + "; + } + if (displacement < 0) { + s.append(" - ").append(-displacement); + } else if (displacement > 0) { + s.append(sep).append(displacement); + } + s.append("]"); + return s.toString(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof PTXAddressValue) { + PTXAddressValue addr = (PTXAddressValue) obj; + return getKind() == addr.getKind() && displacement == addr.displacement && base.equals(addr.base); + } + return false; + } + + @Override + public int hashCode() { + return base.hashCode() ^ ((int) displacement << 4) ^ (getKind().ordinal() << 12); + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXArithmetic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXArithmetic.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,297 @@ +/* + * 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.ptx; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.ptx.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +// @formatter:off +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, + I2L, L2I, I2B, I2C, I2S, + F2D, D2F, + I2F, I2D, F2I, D2I, + L2F, L2D, F2L, D2L, + MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L; + + + public static class Op1Reg extends PTXLIRInstruction { + @Opcode private final PTXArithmetic opcode; + @Def({REG, HINT}) protected Value result; + @Use({REG}) protected Value x; + + public Op1Reg(PTXArithmetic opcode, Value result, Value x) { + this.opcode = opcode; + this.result = result; + this.x = x; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + emit(tasm, masm, opcode, result, x, null); + } + } + + public static class Op1Stack extends PTXLIRInstruction { + @Opcode private final PTXArithmetic opcode; + @Def({REG, HINT}) protected Value result; + @Use({REG, STACK, CONST}) protected Value x; + + public Op1Stack(PTXArithmetic opcode, Value result, Value x) { + this.opcode = opcode; + this.result = result; + this.x = x; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + emit(tasm, masm, opcode, result, x, null); + } + } + + public static class Op2Stack extends PTXLIRInstruction { + @Opcode private final PTXArithmetic opcode; + @Def({REG, HINT}) protected Value result; + @Use({REG, STACK, CONST}) protected Value x; + @Alive({REG, STACK, CONST}) protected Value y; + + public Op2Stack(PTXArithmetic opcode, Value result, Value x, Value y) { + this.opcode = opcode; + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + emit(tasm, masm, opcode, result, x, y, null); + } + + @Override + public void verify() { + super.verify(); + verifyKind(opcode, result, x, y); + } + } + + public static class Op2Reg extends PTXLIRInstruction { + @Opcode private final PTXArithmetic opcode; + @Def({REG, HINT}) protected Value result; + @Use({REG, STACK, CONST}) protected Value x; + @Alive({REG, CONST}) protected Value y; + + public Op2Reg(PTXArithmetic opcode, Value result, Value x, Value y) { + this.opcode = opcode; + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + emit(tasm, masm, opcode, result, x, y, null); + } + + @Override + public void verify() { + super.verify(); + verifyKind(opcode, result, x, y); + } + } + + public static class Op2RegCommutative extends PTXLIRInstruction { + @Opcode private final PTXArithmetic opcode; + @Def({REG, HINT}) protected Value result; + @Use({REG, STACK, CONST}) protected Value x; + @Use({REG, CONST}) protected Value y; + + public Op2RegCommutative(PTXArithmetic opcode, Value result, Value x, Value y) { + this.opcode = opcode; + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + if (sameRegister(result, y)) { + emit(tasm, masm, opcode, result, x, null); + } else { + PTXMove.move(tasm, masm, result, x); + emit(tasm, masm, opcode, result, y, null); + } + } + + @Override + protected void verify() { + super.verify(); + verifyKind(opcode, result, x, y); + } + } + + public static class ShiftOp extends PTXLIRInstruction { + @Opcode private final PTXArithmetic opcode; + @Def({REG, HINT}) protected Value result; + @Use({REG, STACK, CONST}) protected Value x; + @Alive({REG, CONST}) protected Value y; + + public ShiftOp(PTXArithmetic opcode, Value result, Value x, Value y) { + this.opcode = opcode; + this.result = result; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + emit(tasm, masm, opcode, result, x, y, null); + } + + @Override + public void verify() { + super.verify(); + verifyKind(opcode, result, x, x); + assert y.getKind().getStackKind() == Kind.Int; + } + } + + public static class DivOp extends PTXLIRInstruction { + @Opcode private final PTXArithmetic opcode; + @Def protected Value result; + @Use protected Value x; + @Alive protected Value y; + @State protected LIRFrameState state; + + public DivOp(PTXArithmetic opcode, Value result, Value x, Value y, LIRFrameState state) { + this.opcode = opcode; + this.result = result; + this.x = x; + this.y = y; + this.state = state; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + emit(tasm, masm, opcode, result, y, state); + } + + @Override + protected void verify() { + super.verify(); + verifyKind(opcode, result, x, y); + } + } + + + @SuppressWarnings("unused") + protected static void emit(TargetMethodAssembler tasm, PTXAssembler masm, PTXArithmetic opcode, Value result) { + switch (opcode) { + default: throw GraalInternalError.shouldNotReachHere(); + } + } + + 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; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } else if (isConstant(src)) { + switch (opcode) { + case ISUB: masm.sub_s32(asIntReg(dst), asIntReg(dst), tasm.asIntConst(src)); break; + case IAND: masm.and_b32(asIntReg(dst), asIntReg(dst), tasm.asIntConst(src)); break; + default: throw GraalInternalError.shouldNotReachHere(); + } + } else { + switch (opcode) { + default: throw GraalInternalError.shouldNotReachHere(); + } + } + + if (info != null) { + assert exceptionOffset != -1; + tasm.recordImplicitException(exceptionOffset, info); + } + } + + 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(); + } + } 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(); + } + } 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(); + } + } + + if (info != null) { + assert exceptionOffset != -1; + tasm.recordImplicitException(exceptionOffset, info); + } + } + + 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) + || (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); + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXBitManipulationOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXBitManipulationOp.java Thu Mar 21 14:11:13 2013 +0100 @@ -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.lir.ptx; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.ptx.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.asm.*; + +public class PTXBitManipulationOp extends PTXLIRInstruction { + + public enum IntrinsicOpcode { + IPOPCNT, LPOPCNT, IBSR, LBSR, BSF; + } + + @Opcode private final IntrinsicOpcode opcode; + @Def protected Value result; + @Use({OperandFlag.REG}) protected Value input; + + public PTXBitManipulationOp(IntrinsicOpcode opcode, Value result, Value input) { + this.opcode = opcode; + this.result = result; + this.input = input; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + Register dst = ValueUtil.asIntReg(result); + Register src = ValueUtil.asRegister(input); + switch (opcode) { + case IPOPCNT: + masm.popc_b32(dst, src); + break; + case LPOPCNT: + masm.popc_b64(dst, src); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXCompare.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXCompare.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,226 @@ +/* + * 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.lir.ptx; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.ptx.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.calc.*; + +public enum PTXCompare { + ICMP, LCMP, ACMP, FCMP, DCMP; + + public static class CompareOp extends PTXLIRInstruction { + + @Opcode private final PTXCompare opcode; + @Use({REG, STACK, CONST}) protected Value x; + @Use({REG, STACK, CONST}) protected Value y; + private final Condition condition; + + public CompareOp(PTXCompare opcode, Condition condition, Value x, Value y) { + this.opcode = opcode; + this.condition = condition; + this.x = x; + this.y = y; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + emit(tasm, masm, opcode, condition, x, y); + } + + @Override + protected void verify() { + super.verify(); + assert (name().startsWith("I") && x.getKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) || (name().startsWith("L") && x.getKind() == Kind.Long && y.getKind() == Kind.Long) || + (name().startsWith("A") && x.getKind() == Kind.Object && y.getKind() == Kind.Object) || + (name().startsWith("F") && x.getKind() == Kind.Float && y.getKind() == Kind.Float) || (name().startsWith("D") && x.getKind() == Kind.Double && y.getKind() == Kind.Double); + } + } + + 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); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } else if (isConstant(y)) { + Register a = asIntReg(x); + int b = tasm.asIntConst(y); + switch (opcode) { + case ICMP: + emitCompareRegConst(masm, condition, a, b); + break; + case ACMP: + if (((Constant) y).isNull()) { + switch (condition) { + case EQ: + masm.setp_eq_s32(a, b); + break; + case NE: + masm.setp_ne_s32(a, b); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } else { + throw GraalInternalError.shouldNotReachHere("Only null object constants are allowed in comparisons"); + } + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } else { + Register a = asIntReg(x); + Register b = asIntReg(y); + switch (opcode) { + case ICMP: + emitCompareRegReg(masm, condition, a, b); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + } + + private static void emitCompareConstReg(PTXAssembler masm, Condition condition, int a, Register b) { + switch (condition) { + case EQ: + masm.setp_eq_s32(a, b); + break; + case NE: + masm.setp_ne_s32(a, b); + break; + case LT: + masm.setp_lt_s32(a, b); + break; + case LE: + masm.setp_le_s32(a, b); + break; + case GT: + masm.setp_gt_s32(a, b); + break; + case GE: + masm.setp_ge_s32(a, b); + break; + case AT: + masm.setp_gt_u32(a, b); + break; + case AE: + masm.setp_ge_u32(a, b); + break; + case BT: + masm.setp_lt_u32(a, b); + break; + case BE: + masm.setp_le_u32(a, b); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + private static void emitCompareRegConst(PTXAssembler masm, Condition condition, Register a, int b) { + switch (condition) { + case EQ: + masm.setp_eq_s32(a, b); + break; + case NE: + masm.setp_ne_s32(a, b); + break; + case LT: + masm.setp_lt_s32(a, b); + break; + case LE: + masm.setp_le_s32(a, b); + break; + case GT: + masm.setp_gt_s32(a, b); + break; + case GE: + masm.setp_ge_s32(a, b); + break; + case AT: + masm.setp_gt_u32(a, b); + break; + case AE: + masm.setp_ge_u32(a, b); + break; + case BT: + masm.setp_lt_u32(a, b); + break; + case BE: + masm.setp_le_u32(a, b); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + private static void emitCompareRegReg(PTXAssembler masm, Condition condition, Register a, Register b) { + switch (condition) { + case EQ: + masm.setp_eq_s32(a, b); + break; + case NE: + masm.setp_ne_s32(a, b); + break; + case LT: + masm.setp_lt_s32(a, b); + break; + case LE: + masm.setp_le_s32(a, b); + break; + case GT: + masm.setp_gt_s32(a, b); + break; + case GE: + masm.setp_ge_s32(a, b); + break; + case AT: + masm.setp_gt_u32(a, b); + break; + case AE: + masm.setp_ge_u32(a, b); + break; + case BT: + masm.setp_lt_u32(a, b); + break; + case BE: + masm.setp_le_u32(a, b); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,83 @@ +/* + * 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.ptx; + +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.*; + +public class PTXControlFlow { + + public static class ReturnOp extends PTXLIRInstruction { + + @Use({REG, ILLEGAL}) protected Value x; + + public ReturnOp(Value x) { + this.x = x; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + if (tasm.frameContext != null) { + tasm.frameContext.leave(tasm); + } + masm.exit(); + } + } + + public static class BranchOp extends PTXLIRInstruction implements StandardOp.BranchOp { + + protected Condition condition; + protected LabelRef destination; + + public BranchOp(Condition condition, LabelRef destination) { + this.condition = condition; + this.destination = destination; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + masm.at(); + Label l = destination.label(); + l.addPatchAt(tasm.asm.codeBuffer.position()); + String target = l.isBound() ? "L" + l.toString() : AbstractPTXAssembler.UNBOUND_TARGET; + masm.bra(target); + } + + @Override + public LabelRef destination() { + return destination; + } + + @Override + public void negate(LabelRef newDestination) { + destination = newDestination; + condition = condition.negate(); + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXLIRInstruction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXLIRInstruction.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,40 @@ +/* + * 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.ptx; + +import com.oracle.graal.asm.ptx.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.asm.*; + +/** + * Convenience class to provide PTXAssembler for the {@link #emitCode} method. + */ +public abstract class PTXLIRInstruction extends LIRInstruction { + + @Override + public final void emitCode(TargetMethodAssembler tasm) { + emitCode(tasm, (PTXAssembler) tasm.asm); + } + + public abstract void emitCode(TargetMethodAssembler tasm, PTXAssembler masm); +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,278 @@ +/* + * 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.ptx; + +import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.ptx.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.Opcode; +import com.oracle.graal.lir.StandardOp.MoveOp; +import com.oracle.graal.lir.asm.*; + +public class PTXMove { + + @Opcode("MOVE") + public static class SpillMoveOp extends PTXLIRInstruction implements MoveOp { + + @Def({REG, STACK}) protected Value result; + @Use({REG, STACK, CONST}) protected Value input; + + public SpillMoveOp(Value result, Value input) { + this.result = result; + this.input = input; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + move(tasm, masm, getResult(), getInput()); + } + + @Override + public Value getInput() { + return input; + } + + @Override + public Value getResult() { + return result; + } + } + + @Opcode("MOVE") + public static class MoveToRegOp extends PTXLIRInstruction implements MoveOp { + + @Def({REG, HINT}) protected Value result; + @Use({REG, STACK, CONST}) protected Value input; + + public MoveToRegOp(Value result, Value input) { + this.result = result; + this.input = input; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + move(tasm, masm, getResult(), getInput()); + } + + @Override + public Value getInput() { + return input; + } + + @Override + public Value getResult() { + return result; + } + } + + @Opcode("MOVE") + public static class MoveFromRegOp extends PTXLIRInstruction implements MoveOp { + + @Def({REG, STACK}) protected Value result; + @Use({REG, CONST, HINT}) protected Value input; + + public MoveFromRegOp(Value result, Value input) { + this.result = result; + this.input = input; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + move(tasm, masm, getResult(), getInput()); + } + + @Override + public Value getInput() { + return input; + } + + @Override + public Value getResult() { + return result; + } + } + + public static class LoadOp extends PTXLIRInstruction { + + @Def({REG}) protected AllocatableValue result; + @Use({COMPOSITE}) protected PTXAddressValue address; + @State protected LIRFrameState state; + + public LoadOp(AllocatableValue result, PTXAddressValue address, LIRFrameState state) { + this.result = result; + this.address = address; + this.state = state; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + PTXAddress addr = address.toAddress(); + switch (address.getKind()) { + case Int: + masm.ld_global_s32(asRegister(result), addr.getBase(), addr.getDisplacement()); + break; + case Object: + masm.ld_global_u32(asRegister(result), addr.getBase(), addr.getDisplacement()); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + } + + public static class StoreOp extends PTXLIRInstruction { + + @Use({COMPOSITE}) protected PTXAddressValue address; + @Use({REG}) protected AllocatableValue input; + @State protected LIRFrameState state; + + public StoreOp(PTXAddressValue address, AllocatableValue input, LIRFrameState state) { + this.address = address; + this.input = input; + this.state = state; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + assert isRegister(input); + PTXAddress addr = address.toAddress(); + switch (address.getKind()) { + case Int: + masm.st_global_s32(addr.getBase(), addr.getDisplacement(), asRegister(input)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + } + + public static class LeaOp extends PTXLIRInstruction { + + @Def({REG}) protected AllocatableValue result; + @Use({COMPOSITE, UNINITIALIZED}) protected PTXAddressValue address; + + public LeaOp(AllocatableValue result, PTXAddressValue address) { + this.result = result; + this.address = address; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + throw new InternalError("NYI"); + } + } + + public static class StackLeaOp extends PTXLIRInstruction { + + @Def({REG}) protected AllocatableValue result; + @Use({STACK, UNINITIALIZED}) protected StackSlot slot; + + public StackLeaOp(AllocatableValue result, StackSlot slot) { + this.result = result; + this.slot = slot; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + throw new InternalError("NYI"); + } + } + + @Opcode("CAS") + public static class CompareAndSwapOp extends PTXLIRInstruction { + + @Def protected AllocatableValue result; + @Use({COMPOSITE}) protected PTXAddressValue address; + @Use protected AllocatableValue cmpValue; + @Use protected AllocatableValue newValue; + + public CompareAndSwapOp(AllocatableValue result, PTXAddressValue address, AllocatableValue cmpValue, AllocatableValue newValue) { + this.result = result; + this.address = address; + this.cmpValue = cmpValue; + this.newValue = newValue; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { + compareAndSwap(tasm, masm, result, address, cmpValue, newValue); + } + } + + public static void move(TargetMethodAssembler tasm, PTXAssembler masm, Value result, Value input) { + if (isRegister(input)) { + if (isRegister(result)) { + reg2reg(masm, result, input); + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } else if (isConstant(input)) { + if (isRegister(result)) { + const2reg(tasm, masm, result, (Constant) input); + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } + + private static void reg2reg(PTXAssembler masm, Value result, Value input) { + if (asRegister(input).equals(asRegister(result))) { + return; + } + switch (input.getKind()) { + case Int: + masm.mov_s32(asRegister(result), asRegister(input)); + break; + case Object: + masm.mov_u64(asRegister(result), asRegister(input)); + break; + default: + throw GraalInternalError.shouldNotReachHere("kind=" + result.getKind()); + } + } + + private static void const2reg(TargetMethodAssembler tasm, PTXAssembler masm, Value result, Constant input) { + switch (input.getKind().getStackKind()) { + case Int: + if (tasm.runtime.needsDataPatch(input)) { + tasm.recordDataReferenceInCode(input, 0, true); + } + masm.mov_s32(asRegister(result), input.asInt()); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + @SuppressWarnings("unused") + protected static void compareAndSwap(TargetMethodAssembler tasm, PTXAssembler masm, AllocatableValue result, PTXAddressValue address, AllocatableValue cmpValue, AllocatableValue newValue) { + throw new InternalError("NYI"); + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,61 @@ +/* + * 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 java.lang.annotation.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.lir.LIRInstruction.OperandFlag; +import com.oracle.graal.lir.LIRInstruction.OperandMode; +import com.oracle.graal.lir.LIRInstruction.ValueProcedure; + +/** + * Base class to represent values that need to be stored in more than one register. + */ +public abstract class CompositeValue extends Value { + + private static final long serialVersionUID = -169180052684126180L; + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public static @interface Component { + + OperandFlag[] value() default OperandFlag.REG; + } + + private final CompositeValueClass valueClass; + + public CompositeValue(Kind kind) { + super(kind); + valueClass = CompositeValueClass.get(getClass()); + } + + public final void forEachComponent(OperandMode mode, ValueProcedure proc) { + valueClass.forEachComponent(this, mode, proc); + } + + @Override + public String toString() { + return valueClass.toString(this); + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,145 @@ +/* + * 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 java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.LIRInstruction.OperandFlag; +import com.oracle.graal.lir.LIRInstruction.OperandMode; +import com.oracle.graal.lir.LIRInstruction.ValueProcedure; + +public class CompositeValueClass extends LIRIntrospection { + + public static final CompositeValueClass get(Class c) { + CompositeValueClass clazz = (CompositeValueClass) allClasses.get(c); + if (clazz != null) { + return clazz; + } + + // We can have a race of multiple threads creating the LIRInstructionClass at the same time. + // However, only one will be put into the map, and this is the one returned by all threads. + clazz = new CompositeValueClass(c); + CompositeValueClass oldClazz = (CompositeValueClass) allClasses.putIfAbsent(c, clazz); + if (oldClazz != null) { + return oldClazz; + } else { + return clazz; + } + } + + private final int directComponentCount; + private final long[] componentOffsets; + private final EnumSet[] componentFlags; + + @SuppressWarnings("unchecked") + public CompositeValueClass(Class clazz) { + super(clazz); + + ValueFieldScanner scanner = new ValueFieldScanner(new DefaultCalcOffset()); + scanner.scan(clazz); + + OperandModeAnnotation mode = scanner.valueAnnotations.get(CompositeValue.Component.class); + directComponentCount = mode.scalarOffsets.size(); + componentOffsets = sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets); + componentFlags = arrayUsingSortedOffsets(mode.flags, componentOffsets, new EnumSet[componentOffsets.length]); + + dataOffsets = sortedLongCopy(scanner.dataOffsets); + + fieldNames = scanner.fieldNames; + fieldTypes = scanner.fieldTypes; + } + + @Override + protected void rescanFieldOffsets(CalcOffset calc) { + ValueFieldScanner scanner = new ValueFieldScanner(calc); + scanner.scan(clazz); + + OperandModeAnnotation mode = scanner.valueAnnotations.get(CompositeValue.Component.class); + copyInto(componentOffsets, sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets)); + + copyInto(dataOffsets, sortedLongCopy(scanner.dataOffsets)); + + fieldNames.clear(); + fieldNames.putAll(scanner.fieldNames); + fieldTypes.clear(); + fieldTypes.putAll(scanner.fieldTypes); + } + + private static class ValueFieldScanner extends FieldScanner { + + public ValueFieldScanner(CalcOffset calc) { + super(calc); + + valueAnnotations.put(CompositeValue.Component.class, new OperandModeAnnotation()); + } + + @Override + protected void scan(Class clazz) { + super.scan(clazz); + } + + @Override + protected EnumSet getFlags(Field field) { + EnumSet result = EnumSet.noneOf(OperandFlag.class); + if (field.isAnnotationPresent(CompositeValue.Component.class)) { + result.addAll(Arrays.asList(field.getAnnotation(CompositeValue.Component.class).value())); + } else { + GraalInternalError.shouldNotReachHere(); + } + return result; + } + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder(); + str.append(getClass().getSimpleName()).append(" ").append(clazz.getSimpleName()).append(" component["); + for (int i = 0; i < componentOffsets.length; i++) { + str.append(i == 0 ? "" : ", ").append(componentOffsets[i]); + } + str.append("] data["); + for (int i = 0; i < dataOffsets.length; i++) { + str.append(i == 0 ? "" : ", ").append(dataOffsets[i]); + } + str.append("]"); + return str.toString(); + } + + public final void forEachComponent(CompositeValue obj, OperandMode mode, ValueProcedure proc) { + forEach(obj, directComponentCount, componentOffsets, mode, componentFlags, proc); + } + + public String toString(CompositeValue obj) { + StringBuilder result = new StringBuilder(); + + appendValues(result, obj, "", "", "{", "}", new String[]{""}, componentOffsets); + + for (int i = 0; i < dataOffsets.length; i++) { + result.append(" ").append(fieldNames.get(dataOffsets[i])).append(": ").append(getFieldString(obj, dataOffsets[i])); + } + + return result.toString(); + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Thu Mar 21 14:11:13 2013 +0100 @@ -70,17 +70,11 @@ * The spill slot area also includes stack allocated memory blocks (ALLOCA blocks). The size of such * a block may be greater than the size of a normal spill slot or the word size. *

- * A runtime has two ways to reserve space in the stack frame for its own use: - *

    - *
  • A memory block somewhere in the frame of size - * {@link CodeCacheProvider#getCustomStackAreaSize()}. The offset to this block is returned in - * {@link CompilationResult#getCustomStackAreaOffset()}. - *
  • At the beginning of the overflow argument area: The calling convention can specify that the - * first overflow stack argument is not at offset 0, but at a specified offset o. Use - * {@link CodeCacheProvider#getMinimumOutgoingSize()} to make sure that call-free methods also have - * this space reserved. Then the VM can use memory the memory at offset 0 relative to the stack - * pointer. - *
+ * A runtime can reserve space at the beginning of the overflow argument area. The calling + * convention can specify that the first overflow stack argument is not at offset 0, but at a + * specified offset. Use {@link CodeCacheProvider#getMinimumOutgoingSize()} to make sure that + * call-free methods also have this space reserved. Then the VM can use the memory at offset 0 + * relative to the stack pointer. */ public final class FrameMap { @@ -89,14 +83,9 @@ public final RegisterConfig registerConfig; /** - * The initial frame size, not including the size of the return address. This is the constant - * space reserved by the runtime for all compiled methods. - */ - public final int initialFrameSize; - - /** - * The final frame size, not including the size of the return address. The value is only set - * after register allocation is complete, i.e., after all spill slots have been allocated. + * The final frame size, not including the size of the + * {@link Architecture#getReturnAddressSize() return address slot}. The value is only set after + * register allocation is complete, i.e., after all spill slots have been allocated. */ private int frameSize; @@ -117,12 +106,6 @@ private final List objectStackBlocks; /** - * The stack area reserved for use by the VM, or {@code null} if the VM does not request stack - * space. - */ - private final StackSlot customArea; - - /** * Records whether an offset to an incoming stack argument was ever returned by * {@link #offsetForStackSlot(StackSlot)}. */ @@ -139,8 +122,6 @@ this.spillSize = returnAddressSize() + calleeSaveAreaSize(); this.outgoingSize = runtime.getMinimumOutgoingSize(); this.objectStackBlocks = new ArrayList<>(); - this.customArea = allocateStackBlock(runtime.getCustomStackAreaSize(), false); - this.initialFrameSize = currentFrameSize(); } private int returnAddressSize() { @@ -161,7 +142,8 @@ } /** - * Gets the frame size of the compiled frame, not including the size of the return address. + * Gets the frame size of the compiled frame, not including the size of the + * {@link Architecture#getReturnAddressSize() return address slot}. * * @return The size of the frame (in bytes). */ @@ -171,7 +153,17 @@ } /** - * Gets the total frame size of the compiled frame, including the size of the return address. + * Determines if any space is used in the frame apart from the + * {@link Architecture#getReturnAddressSize() return address slot}. + */ + public boolean frameNeedsAllocating() { + int unalignedFrameSize = outgoingSize + spillSize - returnAddressSize(); + return unalignedFrameSize != 0; + } + + /** + * Gets the total frame size of the compiled frame, including the size of the + * {@link Architecture#getReturnAddressSize() return address slot}. * * @return The total size of the frame (in bytes). */ @@ -194,6 +186,21 @@ */ public void finish() { assert this.frameSize == -1 : "must only be set once"; + if (freedSlots != null) { + // If the freed slots cover the complete spill area (except for the return + // address slot), then the spill size is reset to its initial value. + // Without this, frameNeedsAllocating() would never return true. + int total = 0; + for (StackSlot s : freedSlots) { + total += target.sizeInBytes(s.getKind()); + } + int initialSpillSize = returnAddressSize() + calleeSaveAreaSize(); + if (total == spillSize - initialSpillSize) { + // reset spill area size + spillSize = initialSpillSize; + } + freedSlots = null; + } frameSize = currentFrameSize(); } @@ -223,16 +230,6 @@ } /** - * Gets the offset of the stack area stack block reserved for use by the VM, or -1 if the VM - * does not request stack space. - * - * @return The offset to the custom area (in bytes). - */ - public int offsetToCustomArea() { - return customArea == null ? -1 : offsetForStackSlot(customArea); - } - - /** * Informs the frame map that the compiled code calls a particular method, which may need stack * space for outgoing arguments. * @@ -265,11 +262,36 @@ */ public StackSlot allocateSpillSlot(Kind kind) { assert frameSize == -1 : "frame size must not yet be fixed"; + if (freedSlots != null) { + for (Iterator iter = freedSlots.iterator(); iter.hasNext();) { + StackSlot s = iter.next(); + if (s.getKind() == kind) { + iter.remove(); + if (freedSlots.isEmpty()) { + freedSlots = null; + } + return s; + } + } + } int size = target.sizeInBytes(kind); spillSize = NumUtil.roundUp(spillSize + size, size); return getSlot(kind, 0); } + private List freedSlots; + + /** + * Frees a spill slot that was obtained via {@link #allocateSpillSlot(Kind)} such that it can be + * reused for the next allocation request for the same kind of slot. + */ + public void freeSpillSlot(StackSlot slot) { + if (freedSlots == null) { + freedSlots = new ArrayList<>(); + } + freedSlots.add(slot); + } + /** * Reserves a block of memory in the frame of the method being compiled. The returned block is * aligned on a word boundary. If the requested size is 0, the method returns {@code null}. @@ -347,28 +369,4 @@ } } } - - /** - * Clears the specified location as a reference in the reference map of the debug information. - * The tracked location can be a {@link RegisterValue} or a {@link StackSlot}. Note that a - * {@link Constant} is automatically tracked. - * - * @param location The location to be removed from the reference map. - * @param registerRefMap A register reference map, as created by {@link #initRegisterRefMap()}. - * @param frameRefMap A frame reference map, as created by {@link #initFrameRefMap()}. - */ - public void clearReference(Value location, BitSet registerRefMap, BitSet frameRefMap) { - if (location.getKind() == Kind.Object) { - if (location instanceof RegisterValue) { - registerRefMap.clear(asRegister(location).number); - } else if (isStackSlot(location)) { - int index = frameRefMapIndex(asStackSlot(location)); - if (index < frameRefMap.size()) { - frameRefMap.clear(index); - } - } else { - assert isConstant(location); - } - } - } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,6 +24,7 @@ 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.*; @@ -55,12 +56,6 @@ */ private final List codeEmittingOrder; - /** - * Various out-of-line stubs to be emitted near the end of the method after all other LIR code - * has been emitted. - */ - public final List stubs; - private int numVariables; public SpillMoveFactory spillMoveFactory; @@ -74,30 +69,22 @@ private boolean hasArgInCallerFrame; - /** - * An opaque chunk of machine code. - */ - public interface Code { - - void emitCode(TargetMethodAssembler tasm); - - /** - * A description of this code stub useful for commenting the code in a disassembly. - */ - String description(); - } + private final SpeculationLog speculationLog; /** * Creates a new LIR instance for the specified compilation. */ - public LIR(ControlFlowGraph cfg, BlockMap> blockToNodesMap, List linearScanOrder, List codeEmittingOrder) { + public LIR(ControlFlowGraph cfg, BlockMap> blockToNodesMap, List linearScanOrder, List codeEmittingOrder, SpeculationLog speculationLog) { this.cfg = cfg; this.blockToNodesMap = blockToNodesMap; this.codeEmittingOrder = codeEmittingOrder; this.linearScanOrder = linearScanOrder; this.lirInstructions = new BlockMap<>(cfg); + this.speculationLog = speculationLog; + } - stubs = new ArrayList<>(); + public SpeculationLog getDeoptimizationReasons() { + return speculationLog; } /** @@ -108,7 +95,7 @@ } /** - * Determines if any instruction in the LIR has any debug info associated with it. + * Determines if any instruction in the LIR has debug info associated with it. */ public boolean hasDebugInfo() { for (Block b : linearScanOrder()) { @@ -159,11 +146,6 @@ for (Block b : codeEmittingOrder()) { emitBlock(tasm, b); } - - // generate code stubs - for (Code c : stubs) { - emitCodeStub(tasm, c); - } } private void emitBlock(TargetMethodAssembler tasm, Block block) { @@ -194,13 +176,6 @@ } } - private static void emitCodeStub(TargetMethodAssembler tasm, Code code) { - if (Debug.isDumpEnabled()) { - tasm.blockComment(String.format("code stub: %s", code.description())); - } - code.emitCode(tasm); - } - public void setHasArgInCallerFrame() { hasArgInCallerFrame = true; } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java Thu Mar 21 14:11:13 2013 +0100 @@ -42,11 +42,13 @@ private final VirtualObject[] virtualObjects; public final LabelRef exceptionEdge; private DebugInfo debugInfo; + private final short deoptimizationReason; - public LIRFrameState(BytecodeFrame topFrame, VirtualObject[] virtualObjects, LabelRef exceptionEdge) { + public LIRFrameState(BytecodeFrame topFrame, VirtualObject[] virtualObjects, LabelRef exceptionEdge, short deoptimizationReason) { this.topFrame = topFrame; this.virtualObjects = virtualObjects; this.exceptionEdge = exceptionEdge; + this.deoptimizationReason = deoptimizationReason; } public boolean hasDebugInfo() { @@ -111,7 +113,7 @@ } public void finish(BitSet registerRefMap, BitSet frameRefMap) { - debugInfo = new DebugInfo(topFrame, registerRefMap, frameRefMap); + debugInfo = new DebugInfo(topFrame, registerRefMap, frameRefMap, deoptimizationReason); } @Override diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java Thu Mar 21 14:11:13 2013 +0100 @@ -166,9 +166,9 @@ STACK, /** - * The value can be a {@link Address}. + * The value can be a {@link CompositeValue}. */ - ADDR, + COMPOSITE, /** * The value can be a {@link Constant}. @@ -181,6 +181,11 @@ ILLEGAL, /** + * The value can be {@link AllocatableValue#UNUSED}. + */ + UNUSED, + + /** * The register allocator should try to assign a certain register to improve code quality. * Use {@link LIRInstruction#forEachRegisterHint} to access the register hints. */ @@ -200,10 +205,10 @@ static { ALLOWED_FLAGS = new EnumMap<>(OperandMode.class); - ALLOWED_FLAGS.put(USE, EnumSet.of(REG, STACK, ADDR, CONST, ILLEGAL, HINT, UNINITIALIZED)); - ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, ADDR, CONST, ILLEGAL, HINT, UNINITIALIZED)); - ALLOWED_FLAGS.put(TEMP, EnumSet.of(REG, CONST, ILLEGAL, HINT)); - ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, ILLEGAL, HINT)); + ALLOWED_FLAGS.put(USE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNUSED, UNINITIALIZED)); + ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNUSED, UNINITIALIZED)); + ALLOWED_FLAGS.put(TEMP, EnumSet.of(REG, COMPOSITE, CONST, ILLEGAL, UNUSED, HINT)); + ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, UNUSED, HINT)); } /** diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 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 @@ -22,12 +22,8 @@ */ package com.oracle.graal.lir; -import static com.oracle.graal.api.code.ValueUtil.*; - -import java.lang.annotation.*; import java.lang.reflect.*; import java.util.*; -import java.util.Map.Entry; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; @@ -37,7 +33,7 @@ import com.oracle.graal.lir.LIRInstruction.StateProcedure; import com.oracle.graal.lir.LIRInstruction.ValueProcedure; -public class LIRInstructionClass extends FieldIntrospection { +public class LIRInstructionClass extends LIRIntrospection { public static final LIRInstructionClass get(Class c) { LIRInstructionClass clazz = (LIRInstructionClass) allClasses.get(c); @@ -56,10 +52,8 @@ } } - private static final Class INSTRUCTION_CLASS = LIRInstruction.class; - private static final Class VALUE_CLASS = Value.class; - private static final Class VALUE_ARRAY_CLASS = Value[].class; - private static final Class STATE_CLASS = LIRFrameState.class; + private static final Class INSTRUCTION_CLASS = LIRInstruction.class; + private static final Class STATE_CLASS = LIRFrameState.class; private final int directUseCount; private final long[] useOffsets; @@ -80,11 +74,11 @@ private long opcodeOffset; @SuppressWarnings("unchecked") - public LIRInstructionClass(Class clazz) { + public LIRInstructionClass(Class clazz) { super(clazz); assert INSTRUCTION_CLASS.isAssignableFrom(clazz); - FieldScanner scanner = new FieldScanner(new DefaultCalcOffset()); + InstructionFieldScanner scanner = new InstructionFieldScanner(new DefaultCalcOffset()); scanner.scan(clazz); OperandModeAnnotation mode = scanner.valueAnnotations.get(LIRInstruction.Use.class); @@ -119,7 +113,7 @@ @Override protected void rescanFieldOffsets(CalcOffset calc) { - FieldScanner scanner = new FieldScanner(calc); + InstructionFieldScanner scanner = new InstructionFieldScanner(calc); scanner.scan(clazz); OperandModeAnnotation mode = scanner.valueAnnotations.get(LIRInstruction.Use.class); @@ -143,44 +137,22 @@ opcodeOffset = scanner.opcodeOffset; } - private static class OperandModeAnnotation { - - public final ArrayList scalarOffsets = new ArrayList<>(); - public final ArrayList arrayOffsets = new ArrayList<>(); - public final Map> flags = new HashMap<>(); - } - - protected static class FieldScanner extends BaseFieldScanner { - - public final Map, OperandModeAnnotation> valueAnnotations; - public final ArrayList stateOffsets = new ArrayList<>(); + private static class InstructionFieldScanner extends FieldScanner { private String opcodeConstant; private long opcodeOffset; - public FieldScanner(CalcOffset calc) { + public InstructionFieldScanner(CalcOffset calc) { super(calc); - valueAnnotations = new HashMap<>(); - valueAnnotations.put(LIRInstruction.Use.class, new OperandModeAnnotation()); // LIRInstruction.Use.class)); - valueAnnotations.put(LIRInstruction.Alive.class, new OperandModeAnnotation()); // LIRInstruction.Alive.class)); - valueAnnotations.put(LIRInstruction.Temp.class, new OperandModeAnnotation()); // LIRInstruction.Temp.class)); - valueAnnotations.put(LIRInstruction.Def.class, new OperandModeAnnotation()); // LIRInstruction.Def.class)); + valueAnnotations.put(LIRInstruction.Use.class, new OperandModeAnnotation()); + valueAnnotations.put(LIRInstruction.Alive.class, new OperandModeAnnotation()); + valueAnnotations.put(LIRInstruction.Temp.class, new OperandModeAnnotation()); + valueAnnotations.put(LIRInstruction.Def.class, new OperandModeAnnotation()); } - private OperandModeAnnotation getOperandModeAnnotation(Field field) { - OperandModeAnnotation result = null; - for (Entry, OperandModeAnnotation> entry : valueAnnotations.entrySet()) { - Annotation annotation = field.getAnnotation(entry.getKey()); - if (annotation != null) { - assert result == null : "Field has two operand mode annotations: " + field; - result = entry.getValue(); - } - } - return result; - } - - private static EnumSet getFlags(Field field) { + @Override + protected EnumSet getFlags(Field field) { EnumSet result = EnumSet.noneOf(OperandFlag.class); // Unfortunately, annotations cannot have class hierarchies or implement interfaces, so // we have to duplicate the code for every operand mode. @@ -219,26 +191,12 @@ @Override protected void scanField(Field field, Class type, long offset) { - if (VALUE_CLASS.isAssignableFrom(type)) { - assert Modifier.isProtected(field.getModifiers()) && !Modifier.isFinal(field.getModifiers()) : "Value field must not be declared final or [package] private because it is modified by register allocator: " + - field; - OperandModeAnnotation annotation = getOperandModeAnnotation(field); - assert annotation != null : "Field must have operand mode annotation: " + field; - annotation.scalarOffsets.add(offset); - annotation.flags.put(offset, getFlags(field)); - } else if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) { - OperandModeAnnotation annotation = getOperandModeAnnotation(field); - assert annotation != null : "Field must have operand mode annotation: " + field; - annotation.arrayOffsets.add(offset); - annotation.flags.put(offset, getFlags(field)); - } else if (STATE_CLASS.isAssignableFrom(type)) { + if (STATE_CLASS.isAssignableFrom(type)) { assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field; assert field.getAnnotation(LIRInstruction.State.class) != null : "Field must have state annotation: " + field; stateOffsets.add(offset); } else { - assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field; - assert field.getAnnotation(LIRInstruction.State.class) == null : "Field must not have state annotation: " + field; - dataOffsets.add(offset); + super.scanField(field, type, offset); } if (field.getAnnotation(LIRInstruction.Opcode.class) != null) { @@ -334,37 +292,6 @@ } } - private static void forEach(LIRInstruction obj, int directCount, long[] offsets, OperandMode mode, EnumSet[] flags, ValueProcedure proc) { - for (int i = 0; i < offsets.length; i++) { - assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(flags[i]); - - if (i < directCount) { - Value value = getValue(obj, offsets[i]); - if (isAddress(value)) { - doAddress(asAddress(value), mode, flags[i], proc); - } else { - setValue(obj, offsets[i], proc.doValue(value, mode, flags[i])); - } - } else { - Value[] values = getValueArray(obj, offsets[i]); - for (int j = 0; j < values.length; j++) { - Value value = values[j]; - if (isAddress(value)) { - doAddress(asAddress(value), mode, flags[i], proc); - } else { - values[j] = proc.doValue(value, mode, flags[i]); - } - } - } - } - } - - private static void doAddress(Address address, OperandMode mode, EnumSet flags, ValueProcedure proc) { - assert flags.contains(OperandFlag.ADDR); - address.setBase(proc.doValue(address.getBase(), mode, LIRInstruction.ADDRESS_FLAGS)); - address.setIndex(proc.doValue(address.getIndex(), mode, LIRInstruction.ADDRESS_FLAGS)); - } - public final Value forEachRegisterHint(LIRInstruction obj, OperandMode mode, ValueProcedure proc) { int hintDirectCount = 0; long[] hintOffsets = null; @@ -399,18 +326,6 @@ return null; } - private static Value getValue(LIRInstruction obj, long offset) { - return (Value) unsafe.getObject(obj, offset); - } - - private static void setValue(LIRInstruction obj, long offset, Value value) { - unsafe.putObject(obj, offset, value); - } - - private static Value[] getValueArray(LIRInstruction obj, long offset) { - return (Value[]) unsafe.getObject(obj, offset); - } - private static LIRFrameState getState(LIRInstruction obj, long offset) { return (LIRFrameState) unsafe.getObject(obj, offset); } @@ -445,65 +360,4 @@ return result.toString(); } - - private void appendValues(StringBuilder result, LIRInstruction obj, String start, String end, String startMultiple, String endMultiple, String[] prefix, long[]... moffsets) { - int total = 0; - for (long[] offsets : moffsets) { - total += offsets.length; - } - if (total == 0) { - return; - } - - result.append(start); - if (total > 1) { - result.append(startMultiple); - } - String sep = ""; - for (int i = 0; i < moffsets.length; i++) { - long[] offsets = moffsets[i]; - - for (int j = 0; j < offsets.length; j++) { - result.append(sep).append(prefix[i]); - long offset = offsets[j]; - if (total > 1) { - result.append(fieldNames.get(offset)).append(": "); - } - result.append(getFieldString(obj, offset)); - sep = ", "; - } - } - if (total > 1) { - result.append(endMultiple); - } - result.append(end); - } - - private String getFieldString(Object obj, long offset) { - Class type = fieldTypes.get(offset); - if (type == int.class) { - return String.valueOf(unsafe.getInt(obj, offset)); - } else if (type == long.class) { - return String.valueOf(unsafe.getLong(obj, offset)); - } else if (type == boolean.class) { - return String.valueOf(unsafe.getBoolean(obj, offset)); - } else if (type == float.class) { - return String.valueOf(unsafe.getFloat(obj, offset)); - } else if (type == double.class) { - return String.valueOf(unsafe.getDouble(obj, offset)); - } else if (!type.isPrimitive()) { - Object value = unsafe.getObject(obj, offset); - if (!type.isArray()) { - return String.valueOf(value); - } else if (type == int[].class) { - return Arrays.toString((int[]) value); - } else if (type == double[].class) { - return Arrays.toString((double[]) value); - } else if (!type.getComponentType().isPrimitive()) { - return Arrays.toString((Object[]) value); - } - } - assert false : "unhandled field type: " + type; - return ""; - } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,220 @@ +/* + * 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 + * 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.OperandFlag.*; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.*; +import java.util.Map.Entry; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.lir.LIRInstruction.OperandFlag; +import com.oracle.graal.lir.LIRInstruction.OperandMode; +import com.oracle.graal.lir.LIRInstruction.ValueProcedure; + +abstract class LIRIntrospection extends FieldIntrospection { + + private static final Class VALUE_CLASS = Value.class; + private static final Class CONSTANT_CLASS = Constant.class; + private static final Class REGISTER_VALUE_CLASS = RegisterValue.class; + private static final Class STACK_SLOT_CLASS = StackSlot.class; + private static final Class VALUE_ARRAY_CLASS = Value[].class; + + public LIRIntrospection(Class clazz) { + super(clazz); + } + + protected static class OperandModeAnnotation { + + public final ArrayList scalarOffsets = new ArrayList<>(); + public final ArrayList arrayOffsets = new ArrayList<>(); + public final Map> flags = new HashMap<>(); + } + + protected abstract static class FieldScanner extends BaseFieldScanner { + + public final Map, OperandModeAnnotation> valueAnnotations; + public final ArrayList stateOffsets = new ArrayList<>(); + + public FieldScanner(CalcOffset calc) { + super(calc); + + valueAnnotations = new HashMap<>(); + } + + protected OperandModeAnnotation getOperandModeAnnotation(Field field) { + OperandModeAnnotation result = null; + for (Entry, OperandModeAnnotation> entry : valueAnnotations.entrySet()) { + Annotation annotation = field.getAnnotation(entry.getKey()); + if (annotation != null) { + assert result == null : "Field has two operand mode annotations: " + field; + result = entry.getValue(); + } + } + return result; + } + + protected abstract EnumSet getFlags(Field field); + + @Override + protected void scanField(Field field, Class type, long offset) { + if (VALUE_CLASS.isAssignableFrom(type) && type != CONSTANT_CLASS) { + assert !Modifier.isFinal(field.getModifiers()) : "Value field must not be declared final because it is modified by register allocator: " + field; + OperandModeAnnotation annotation = getOperandModeAnnotation(field); + assert annotation != null : "Field must have operand mode annotation: " + field; + annotation.scalarOffsets.add(offset); + EnumSet flags = getFlags(field); + assert verifyFlags(field, type, flags); + annotation.flags.put(offset, getFlags(field)); + } else if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) { + OperandModeAnnotation annotation = getOperandModeAnnotation(field); + assert annotation != null : "Field must have operand mode annotation: " + field; + annotation.arrayOffsets.add(offset); + EnumSet flags = getFlags(field); + assert verifyFlags(field, type.getComponentType(), flags); + annotation.flags.put(offset, getFlags(field)); + } else { + assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field; + assert field.getAnnotation(LIRInstruction.State.class) == null : "Field must not have state annotation: " + field; + dataOffsets.add(offset); + } + } + + private static boolean verifyFlags(Field field, Class type, EnumSet flags) { + if (flags.contains(REG)) { + assert type.isAssignableFrom(REGISTER_VALUE_CLASS) : "Cannot assign RegisterValue to field with REG flag:" + field; + } + if (flags.contains(STACK)) { + assert type.isAssignableFrom(STACK_SLOT_CLASS) : "Cannot assign StackSlot to field with STACK flag:" + field; + } + if (flags.contains(CONST)) { + assert type.isAssignableFrom(CONSTANT_CLASS) : "Cannot assign Constant to field with CONST flag:" + field; + } + return true; + } + } + + protected static void forEach(Object obj, int directCount, long[] offsets, OperandMode mode, EnumSet[] flags, ValueProcedure proc) { + for (int i = 0; i < offsets.length; i++) { + assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(flags[i]); + + if (i < directCount) { + Value value = getValue(obj, offsets[i]); + if (value instanceof CompositeValue) { + CompositeValue composite = (CompositeValue) value; + composite.forEachComponent(mode, proc); + } else { + setValue(obj, offsets[i], proc.doValue(value, mode, flags[i])); + } + } else { + Value[] values = getValueArray(obj, offsets[i]); + for (int j = 0; j < values.length; j++) { + Value value = values[j]; + if (value instanceof CompositeValue) { + CompositeValue composite = (CompositeValue) value; + composite.forEachComponent(mode, proc); + } else { + values[j] = proc.doValue(value, mode, flags[i]); + } + } + } + } + } + + protected static Value getValue(Object obj, long offset) { + return (Value) unsafe.getObject(obj, offset); + } + + protected static void setValue(Object obj, long offset, Value value) { + unsafe.putObject(obj, offset, value); + } + + protected static Value[] getValueArray(Object obj, long offset) { + return (Value[]) unsafe.getObject(obj, offset); + } + + protected void appendValues(StringBuilder result, Object obj, String start, String end, String startMultiple, String endMultiple, String[] prefix, long[]... moffsets) { + int total = 0; + for (long[] offsets : moffsets) { + total += offsets.length; + } + if (total == 0) { + return; + } + + result.append(start); + if (total > 1) { + result.append(startMultiple); + } + String sep = ""; + for (int i = 0; i < moffsets.length; i++) { + long[] offsets = moffsets[i]; + + for (int j = 0; j < offsets.length; j++) { + result.append(sep).append(prefix[i]); + long offset = offsets[j]; + if (total > 1) { + result.append(fieldNames.get(offset)).append(": "); + } + result.append(getFieldString(obj, offset)); + sep = ", "; + } + } + if (total > 1) { + result.append(endMultiple); + } + result.append(end); + } + + protected String getFieldString(Object obj, long offset) { + Class type = fieldTypes.get(offset); + if (type == int.class) { + return String.valueOf(unsafe.getInt(obj, offset)); + } else if (type == long.class) { + return String.valueOf(unsafe.getLong(obj, offset)); + } else if (type == boolean.class) { + return String.valueOf(unsafe.getBoolean(obj, offset)); + } else if (type == float.class) { + return String.valueOf(unsafe.getFloat(obj, offset)); + } else if (type == double.class) { + return String.valueOf(unsafe.getDouble(obj, offset)); + } else if (!type.isPrimitive()) { + Object value = unsafe.getObject(obj, offset); + if (!type.isArray()) { + return String.valueOf(value); + } else if (type == int[].class) { + return Arrays.toString((int[]) value); + } else if (type == double[].class) { + return Arrays.toString((double[]) value); + } else if (!type.getComponentType().isPrimitive()) { + return Arrays.toString((Object[]) value); + } + } + assert false : "unhandled field type: " + type; + return ""; + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java Thu Mar 21 14:11:13 2013 +0100 @@ -232,7 +232,8 @@ private static Value allowed(Object op, Value value, OperandMode mode, EnumSet flags) { if ((isVariable(value) && flags.contains(OperandFlag.REG)) || (isRegister(value) && flags.contains(OperandFlag.REG)) || (isStackSlot(value) && flags.contains(OperandFlag.STACK)) || - (isConstant(value) && flags.contains(OperandFlag.CONST) && mode != OperandMode.DEF) || (isIllegal(value) && flags.contains(OperandFlag.ILLEGAL))) { + (isConstant(value) && flags.contains(OperandFlag.CONST) && mode != OperandMode.DEF) || (isIllegal(value) && flags.contains(OperandFlag.ILLEGAL)) || + (value == AllocatableValue.UNUSED && flags.contains(OperandFlag.UNUSED))) { return value; } TTY.println("instruction %s", op); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java Thu Mar 21 14:11:13 2013 +0100 @@ -32,39 +32,13 @@ * reference of block B from block A only via the tuple (A, successor-index-of-B), i.e., indirectly * by storing the index into the successor list of A. Note that therefore it is not allowed to * reorder the successor list! - * - * Labels of out-of-line stubs can be referenced directly, therefore it is also possible to - * construct a LabelRef for a Label directly via {@link #forLabel}. */ public abstract class LabelRef { public abstract Label label(); /** - * Returns a new reference to a statically defined label. - * - * @param label The label that is always returned. - * @return The newly created label reference. - */ - public static LabelRef forLabel(final Label label) { - return new LabelRef() { - - @Override - public Label label() { - return label; - } - - @Override - public String toString() { - return label.toString(); - } - }; - } - - /** - * Returns a new reference to a successor of the given block. This allows to reference the given - * successor even when the successor list is modified between the creation of the reference and - * the call to {@link #forLabel(Label)}. + * Returns a new reference to a successor of the given block. * * @param block The base block that contains the successor list. * @param suxIndex The index of the successor. diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Thu Mar 21 14:11:13 2013 +0100 @@ -33,8 +33,6 @@ */ public class StandardOp { - private static Value[] EMPTY = new Value[0]; - /** * Marker interface for LIR ops that can fall through to the next operation, like a switch * statement. setFallThroughTarget(null) can be used to make the operation fall through to the @@ -82,11 +80,9 @@ public static class JumpOp extends LIRInstruction { private final LabelRef destination; - @State protected LIRFrameState state; - public JumpOp(LabelRef destination, LIRFrameState state) { + public JumpOp(LabelRef destination) { this.destination = destination; - this.state = state; } @Override @@ -99,24 +95,6 @@ } } - public static class PhiJumpOp extends JumpOp { - - @Alive({REG, STACK, CONST}) protected Value[] phiInputs; - - public PhiJumpOp(LabelRef destination, Value[] phiInputs) { - super(destination, null); - this.phiInputs = phiInputs; - } - - public void markResolved() { - phiInputs = EMPTY; - } - - public Value[] getPhiInputs() { - return phiInputs; - } - } - /** * Marker interface for a LIR operation that is a conditional jump to {@link #destination()}. * Conditional jumps may be negated or optimized away after register allocation. diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/Variable.java Thu Mar 21 14:11:13 2013 +0100 @@ -29,7 +29,7 @@ * Represents a value that is yet to be bound to a machine location (such as a {@link RegisterValue} * or {@link StackSlot}) by a register allocator. */ -public final class Variable extends Value { +public final class Variable extends AllocatableValue { private static final long serialVersionUID = 4507578431686109809L; diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java Thu Mar 21 14:11:13 2013 +0100 @@ -32,7 +32,6 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; -import com.oracle.graal.lir.LIR.Code; public class TargetMethodAssembler { @@ -48,77 +47,65 @@ } public final AbstractAssembler asm; - public final CompilationResult targetMethod; + public final CompilationResult compilationResult; public final TargetDescription target; public final CodeCacheProvider runtime; public final FrameMap frameMap; /** - * Out-of-line stubs to be emitted. - */ - public final List stubs; - - /** * The object that emits code for managing a method's frame. If null, no frame is used by the * method. */ public final FrameContext frameContext; private List exceptionInfoList; - private int lastSafepointPos; - public TargetMethodAssembler(TargetDescription target, CodeCacheProvider runtime, FrameMap frameMap, AbstractAssembler asm, FrameContext frameContext, List stubs) { + public TargetMethodAssembler(TargetDescription target, CodeCacheProvider runtime, FrameMap frameMap, AbstractAssembler asm, FrameContext frameContext, CompilationResult compilationResult) { this.target = target; this.runtime = runtime; this.frameMap = frameMap; - this.stubs = stubs; this.asm = asm; - this.targetMethod = new CompilationResult(); + this.compilationResult = compilationResult; this.frameContext = frameContext; - // 0 is a valid pc for safepoints in template methods - this.lastSafepointPos = -1; } public void setFrameSize(int frameSize) { - targetMethod.setFrameSize(frameSize); + compilationResult.setFrameSize(frameSize); } private static final CompilationResult.Mark[] NO_REFS = {}; public CompilationResult.Mark recordMark(Object id) { - return targetMethod.recordMark(asm.codeBuffer.position(), id, NO_REFS); + return compilationResult.recordMark(asm.codeBuffer.position(), id, NO_REFS); } public CompilationResult.Mark recordMark(Object id, CompilationResult.Mark... references) { - return targetMethod.recordMark(asm.codeBuffer.position(), id, references); + return compilationResult.recordMark(asm.codeBuffer.position(), id, references); } public void blockComment(String s) { - targetMethod.addAnnotation(new CompilationResult.CodeComment(asm.codeBuffer.position(), s)); + compilationResult.addAnnotation(new CompilationResult.CodeComment(asm.codeBuffer.position(), s)); } public CompilationResult finishTargetMethod(Object name, boolean isStub) { // Install code, data and frame size - targetMethod.setTargetCode(asm.codeBuffer.close(false), asm.codeBuffer.position()); + compilationResult.setTargetCode(asm.codeBuffer.close(false), asm.codeBuffer.position()); // Record exception handlers if they exist if (exceptionInfoList != null) { for (ExceptionInfo ei : exceptionInfoList) { int codeOffset = ei.codeOffset; - targetMethod.recordExceptionHandler(codeOffset, ei.exceptionEdge.label().position()); + compilationResult.recordExceptionHandler(codeOffset, ei.exceptionEdge.label().position()); } } - // Set the info on callee-saved registers - targetMethod.setCalleeSaveLayout(frameMap.registerConfig.getCalleeSaveLayout()); - Debug.metric("TargetMethods").increment(); - Debug.metric("CodeBytesEmitted").add(targetMethod.getTargetCodeSize()); - Debug.metric("SafepointsEmitted").add(targetMethod.getSafepoints().size()); - Debug.metric("DataPatches").add(targetMethod.getDataReferences().size()); - Debug.metric("ExceptionHandlersEmitted").add(targetMethod.getExceptionHandlers().size()); + Debug.metric("CodeBytesEmitted").add(compilationResult.getTargetCodeSize()); + Debug.metric("SafepointsEmitted").add(compilationResult.getSafepoints().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); - return targetMethod; + return compilationResult; } public void recordExceptionHandlers(int pcOffset, LIRFrameState info) { @@ -135,45 +122,33 @@ public void recordImplicitException(int pcOffset, LIRFrameState info) { // record an implicit exception point if (info != null) { - assert lastSafepointPos < pcOffset : lastSafepointPos + "<" + pcOffset; - lastSafepointPos = pcOffset; - targetMethod.recordSafepoint(pcOffset, info.debugInfo()); + compilationResult.recordSafepoint(pcOffset, info.debugInfo()); assert info.exceptionEdge == null; } } - public void recordDirectCall(int posBefore, int posAfter, Object callTarget, LIRFrameState info) { + public void recordDirectCall(int posBefore, int posAfter, InvokeTarget callTarget, LIRFrameState info) { DebugInfo debugInfo = info != null ? info.debugInfo() : null; - assert lastSafepointPos < posAfter; - lastSafepointPos = posAfter; - targetMethod.recordCall(posBefore, posAfter - posBefore, callTarget, debugInfo, true); + compilationResult.recordCall(posBefore, posAfter - posBefore, callTarget, debugInfo, true); } - public void recordIndirectCall(int posBefore, int posAfter, Object callTarget, LIRFrameState info) { + public void recordIndirectCall(int posBefore, int posAfter, InvokeTarget callTarget, LIRFrameState info) { DebugInfo debugInfo = info != null ? info.debugInfo() : null; - assert lastSafepointPos < posAfter; - lastSafepointPos = posAfter; - targetMethod.recordCall(posBefore, posAfter - posBefore, callTarget, debugInfo, false); + compilationResult.recordCall(posBefore, posAfter - posBefore, callTarget, debugInfo, false); } public void recordSafepoint(int pos, LIRFrameState info) { // safepoints always need debug info DebugInfo debugInfo = info.debugInfo(); - assert lastSafepointPos < pos; - lastSafepointPos = pos; - targetMethod.recordSafepoint(pos, debugInfo); + compilationResult.recordSafepoint(pos, debugInfo); } - public Address recordDataReferenceInCode(Constant data, int alignment, boolean inlined) { + public AbstractAddress recordDataReferenceInCode(Constant data, int alignment, boolean inlined) { assert data != null; int pos = asm.codeBuffer.position(); Debug.log("Data reference in code: pos = %d, data = %s", pos, data.toString()); - targetMethod.recordDataReference(pos, data, alignment, inlined); - return Address.Placeholder; - } - - public int lastSafepointPos() { - return lastSafepointPos; + compilationResult.recordDataReference(pos, data, alignment, inlined); + return asm.getPlaceholder(); } /** @@ -181,7 +156,7 @@ * including long constants that fit into the 32-bit range. */ public int asIntConst(Value value) { - assert (value.getKind().getStackKind() == Kind.Int || value.getKind() == Kind.Jsr || value.getKind() == Kind.Long) && isConstant(value); + assert (value.getKind().getStackKind() == Kind.Int || value.getKind() == Kind.Long) && isConstant(value); Constant constant = (Constant) value; assert !runtime.needsDataPatch(constant) : constant + " should be in a DataPatch"; long c = constant.asLong(); @@ -194,11 +169,11 @@ /** * Returns the address of a float constant that is embedded as a data references into the code. */ - public Address asFloatConstRef(Value value) { + public AbstractAddress asFloatConstRef(Value value) { return asFloatConstRef(value, 4); } - public Address asFloatConstRef(Value value, int alignment) { + public AbstractAddress asFloatConstRef(Value value, int alignment) { assert value.getKind() == Kind.Float && isConstant(value); return recordDataReferenceInCode((Constant) value, alignment, false); } @@ -206,11 +181,11 @@ /** * Returns the address of a double constant that is embedded as a data references into the code. */ - public Address asDoubleConstRef(Value value) { + public AbstractAddress asDoubleConstRef(Value value) { return asDoubleConstRef(value, 8); } - public Address asDoubleConstRef(Value value, int alignment) { + public AbstractAddress asDoubleConstRef(Value value, int alignment) { assert value.getKind() == Kind.Double && isConstant(value); return recordDataReferenceInCode((Constant) value, alignment, false); } @@ -218,41 +193,39 @@ /** * Returns the address of a long constant that is embedded as a data references into the code. */ - public Address asLongConstRef(Value value) { + public AbstractAddress asLongConstRef(Value value) { assert value.getKind() == Kind.Long && isConstant(value); return recordDataReferenceInCode((Constant) value, 8, false); } - public Address asIntAddr(Value value) { + public AbstractAddress asIntAddr(Value value) { assert value.getKind() == Kind.Int; return asAddress(value); } - public Address asLongAddr(Value value) { + public AbstractAddress asLongAddr(Value value) { assert value.getKind() == Kind.Long; return asAddress(value); } - public Address asObjectAddr(Value value) { + public AbstractAddress asObjectAddr(Value value) { assert value.getKind() == Kind.Object; return asAddress(value); } - public Address asFloatAddr(Value value) { + public AbstractAddress asFloatAddr(Value value) { assert value.getKind() == Kind.Float; return asAddress(value); } - public Address asDoubleAddr(Value value) { + public AbstractAddress asDoubleAddr(Value value) { assert value.getKind() == Kind.Double; return asAddress(value); } - public Address asAddress(Value value) { - if (isStackSlot(value)) { - StackSlot slot = (StackSlot) value; - return new Address(slot.getKind(), frameMap.registerConfig.getFrameRegister().asValue(), frameMap.offsetForStackSlot(slot)); - } - return (Address) value; + public AbstractAddress asAddress(Value value) { + assert isStackSlot(value); + StackSlot slot = asStackSlot(value); + return asm.makeAddress(frameMap.registerConfig.getFrameRegister(), frameMap.offsetForStackSlot(slot)); } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java Thu Mar 21 14:11:13 2013 +0100 @@ -179,7 +179,7 @@ }); } nodes.mark(earlyExit); - for (ValueProxyNode proxy : earlyExit.proxies()) { + for (ProxyNode proxy : earlyExit.proxies()) { nodes.mark(proxy); } } @@ -271,9 +271,9 @@ anchored.replaceFirstInput(earlyExit, merge); } - for (final ValueProxyNode vpn : earlyExit.proxies().snapshot()) { + for (final ProxyNode vpn : earlyExit.proxies().snapshot()) { final ValueNode replaceWith; - ValueProxyNode newVpn = getDuplicatedNode(vpn); + ProxyNode newVpn = getDuplicatedNode(vpn); if (newVpn != null) { PhiNode phi = graph.add(vpn.type() == PhiType.Value ? vpn.stamp() == StampFactory.virtual() ? new PhiNode(vpn.stamp(), merge) : new PhiNode(vpn.kind(), merge) : new PhiNode( vpn.type(), merge)); diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java Thu Mar 21 14:11:13 2013 +0100 @@ -60,7 +60,7 @@ while (!loopBegin.isDeleted()) { int mark = graph.getMark(); peel(loop); - new CanonicalizerPhase(null, runtime, assumptions, mark, null).apply(graph); + new CanonicalizerPhase(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 dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractCallTargetNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractCallTargetNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractCallTargetNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -32,10 +32,10 @@ private final Stamp returnStamp; private final JavaType[] signature; - private final Object target; + private final ResolvedJavaMethod target; private final CallingConvention.Type callType; - public AbstractCallTargetNode(List arguments, Stamp returnStamp, JavaType[] signature, Object target, CallingConvention.Type callType) { + public AbstractCallTargetNode(List arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType) { super(arguments); this.returnStamp = returnStamp; this.signature = signature; @@ -52,7 +52,7 @@ return signature; } - public Object target() { + public ResolvedJavaMethod target() { return target; } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -108,7 +108,7 @@ } public void removeProxies() { - for (ValueProxyNode vpn : proxies().snapshot()) { + for (ProxyNode vpn : proxies().snapshot()) { // can not use graph.replaceFloating because vpn.value may be null during killCFG vpn.replaceAtUsages(vpn.value()); vpn.safeDelete(); @@ -131,11 +131,11 @@ } public NodeIterable anchored() { - return usages().filter(isNotA(ValueProxyNode.class)); + return usages().filter(isNotA(ProxyNode.class)); } - public NodeIterable proxies() { - return usages().filter(ValueProxyNode.class); + public NodeIterable proxies() { + return usages().filter(ProxyNode.class); } public NodeIterable getBlockNodes() { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -165,17 +165,6 @@ } /** - * Returns a node for an address (jsr/ret address) constant. - * - * @param i the address value for which to create the instruction - * @param graph - * @return a node representing the address - */ - public static ConstantNode forJsr(int i, Graph graph) { - return graph.unique(new ConstantNode(Constant.forJsr(i))); - } - - /** * Returns a node for an object constant. * * @param o the object value for which to create the instruction diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSinkNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSinkNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,32 @@ +/* + * 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; + +import com.oracle.graal.nodes.type.*; + +public abstract class ControlSinkNode extends FixedNode { + + public ControlSinkNode(Stamp stamp) { + super(stamp); + } +} diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -29,9 +29,8 @@ import com.oracle.graal.nodes.type.*; @NodeInfo(shortName = "Deopt", nameTemplate = "Deopt {p#reason/s}") -public class DeoptimizeNode extends FixedNode implements Node.IterableNodeType, LIRLowerable { +public class DeoptimizeNode extends ControlSinkNode implements Node.IterableNodeType, LIRLowerable { - private String message; private final DeoptimizationAction action; private final DeoptimizationReason reason; @@ -41,14 +40,6 @@ this.reason = reason; } - public void setMessage(String message) { - this.message = message; - } - - public String message() { - return message; - } - public DeoptimizationAction action() { return action; } @@ -59,7 +50,7 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.emitDeoptimize(action, reason, message); + gen.emitDeoptimize(action, reason); } @NodeIntrinsic diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -30,18 +30,12 @@ public class DirectCallTargetNode extends AbstractCallTargetNode { - public DirectCallTargetNode(List arguments, Stamp returnStamp, JavaType[] signature, Object target, CallingConvention.Type callType) { + public DirectCallTargetNode(List arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType) { super(arguments, returnStamp, signature, target, callType); } @Override public String targetName() { - if (target() instanceof JavaMethod) { - return "Direct#" + ((JavaMethod) target()).getName(); - } else if (target() != null) { - return "Direct#" + target().getClass().getSimpleName(); - } else { - return "Direct#null"; - } + return "Direct#" + ((JavaMethod) target()).getName(); } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -29,7 +29,7 @@ import com.oracle.graal.nodes.type.*; @NodeInfo(nameTemplate = "FixedGuard(!={p#negated}) {p#reason/s}") -public final class FixedGuardNode extends FixedWithNextNode implements Simplifiable, Lowerable, LIRLowerable, Node.IterableNodeType, Negatable { +public final class FixedGuardNode extends FixedWithNextNode implements Simplifiable, Lowerable, Node.IterableNodeType, Negatable { @Input private LogicNode condition; private final DeoptimizationReason reason; @@ -79,11 +79,6 @@ } @Override - public void generate(LIRGeneratorTool gen) { - gen.emitGuardCheck(condition, reason, action, negated); - } - - @Override public void simplify(SimplifierTool tool) { if (condition instanceof LogicConstantNode) { LogicConstantNode c = (LogicConstantNode) condition; diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes; +import java.util.*; + import com.oracle.graal.nodes.type.*; public abstract class FixedNode extends ValueNode { @@ -32,6 +34,10 @@ super(stamp); } + public FixedNode(Stamp stamp, List dependencies) { + super(stamp, dependencies); + } + public FixedNode(Stamp stamp, ValueNode... dependencies) { super(stamp, dependencies); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes; +import java.util.*; + import com.oracle.graal.nodes.type.*; /** @@ -43,6 +45,10 @@ super(stamp); } + public FixedWithNextNode(Stamp stamp, List dependencies) { + super(stamp, dependencies); + } + public FixedWithNextNode(Stamp stamp, ValueNode... dependencies) { super(stamp, dependencies); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Thu Mar 21 14:11:13 2013 +0100 @@ -68,6 +68,12 @@ */ public static final int AFTER_EXCEPTION_BCI = -3; + /** + * This BCI should be used for frame states that cannot be the target of a deoptimization, like + * snippet frame states. + */ + public static final int INVALID_FRAMESTATE_BCI = -5; + @Input private FrameState outerFrameState; @Input private final NodeInputList values; diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -42,7 +42,7 @@ * control flow would have reached the guarded node (without taking exceptions into account). */ @NodeInfo(nameTemplate = "Guard(!={p#negated}) {p#reason/s}") -public final class GuardNode extends FloatingNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType, Negatable { +public final class GuardNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType, Negatable { @Input private LogicNode condition; private final DeoptimizationReason reason; @@ -91,24 +91,13 @@ } @Override - public void generate(LIRGeneratorTool gen) { - gen.emitGuardCheck(condition(), reason(), action(), negated()); - } - - @Override public ValueNode canonical(CanonicalizerTool tool) { if (condition() instanceof LogicConstantNode) { LogicConstantNode c = (LogicConstantNode) condition(); if (c.getValue() != negated) { - if (!dependencies().isEmpty()) { - for (Node usage : usages()) { - if (usage instanceof ValueNode) { - ((ValueNode) usage).dependencies().addAll(dependencies()); - } - } + if (dependencies().size() == 1) { + return dependencies().get(0); } - this.replaceAtUsages(null); - return null; } } return this; diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -152,10 +152,8 @@ ((StructuredGraph) graph()).removeSplit(this, falseSuccessor()); } } else if (trueSuccessor().guards().isEmpty() && falseSuccessor().guards().isEmpty()) { - if (removeOrMaterializeIf(tool)) { - return; - } else if (removeIntermediateMaterialization(tool)) { - return; + if (!removeOrMaterializeIf(tool)) { + removeIntermediateMaterialization(tool); } } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -32,7 +32,7 @@ @Input protected ValueNode computedAddress; - public IndirectCallTargetNode(ValueNode computedAddress, List arguments, Stamp returnStamp, JavaType[] signature, Object target, CallingConvention.Type callType) { + public IndirectCallTargetNode(ValueNode computedAddress, List arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType) { super(arguments, returnStamp, signature, target, callType); this.computedAddress = computedAddress; } @@ -43,12 +43,6 @@ @Override public String targetName() { - if (target() instanceof JavaMethod) { - return "Indirect#" + ((JavaMethod) target()).getName(); - } else if (target() != null) { - return "Indirect#" + target().getClass().getSimpleName(); - } else { - return "Indirect#null"; - } + return "Indirect#" + ((JavaMethod) target()).getName(); } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -109,6 +109,11 @@ } @Override + public Object[] getLocationIdentities() { + return new Object[]{LocationNode.ANY_LOCATION}; + } + + @Override public void lower(LoweringTool tool) { tool.getRuntime().lower(this, tool); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -161,6 +161,11 @@ return true; } + @Override + public Object[] getLocationIdentities() { + return new Object[]{LocationNode.ANY_LOCATION}; + } + public FrameState stateDuring() { FrameState tempStateAfter = stateAfter(); FrameState stateDuring = tempStateAfter.duplicateModified(bci(), tempStateAfter.rethrowException(), kind()); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -37,7 +37,8 @@ public static enum PhiType { Value(null), // normal value phis - Guard(StampFactory.dependency()), Memory(StampFactory.dependency()); + Guard(StampFactory.dependency()), + Memory(StampFactory.dependency()); public final Stamp stamp; @@ -199,6 +200,7 @@ public ValueNode singleValue() { ValueNode differentValue = null; for (ValueNode n : values()) { + assert n != null : "Must have input value!"; if (n != this) { if (differentValue == null) { differentValue = n; diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,103 @@ +/* + * 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.nodes; + +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.ValueNumberable; +import com.oracle.graal.nodes.PhiNode.PhiType; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * A value proxy that is inserted in the frame state of a loop exit for any value that is created + * inside the loop (i.e. was not live on entry to the loop) and is (potentially) used after the + * loop. + */ +@NodeInfo(nameTemplate = "{p#type/s}Proxy") +public class ProxyNode extends FloatingNode implements Node.IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable, LIRLowerable { + + @Input(notDataflow = true) private BeginNode proxyPoint; + @Input private ValueNode value; + private final PhiType type; + + public ProxyNode(ValueNode value, BeginNode exit, PhiType type) { + super(type == PhiType.Value ? value.stamp() : type.stamp); + this.type = type; + assert exit != null; + this.proxyPoint = exit; + this.value = value; + } + + public ValueNode value() { + return value; + } + + @Override + public boolean inferStamp() { + return updateStamp(value.stamp()); + } + + @Override + public Stamp stamp() { + return value().stamp(); + } + + public BeginNode proxyPoint() { + return proxyPoint; + } + + public PhiType type() { + return type; + } + + @Override + public boolean verify() { + assert value != null; + assert proxyPoint != null; + return super.verify(); + } + + @Override + public void generate(LIRGeneratorTool generator) { + assert type == PhiType.Memory; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + if (type == PhiType.Value && value.isConstant()) { + return value; + } + return this; + } + + @Override + public void virtualize(VirtualizerTool tool) { + if (type == PhiType.Value) { + State state = tool.getObjectState(value); + if (state != null && state.getState() == EscapeState.Virtual) { + tool.replaceWithVirtual(state.getVirtualObject()); + } + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -26,7 +26,7 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -public final class ReturnNode extends FixedNode implements LIRLowerable, Node.IterableNodeType { +public final class ReturnNode extends ControlSinkNode implements LIRLowerable, Node.IterableNodeType { @Input private ValueNode result; diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SafepointNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -29,10 +29,14 @@ /** * Marks a position in the graph where a safepoint should be emitted. */ -public final class SafepointNode extends FixedWithNextNode implements LIRLowerable, Node.IterableNodeType { +public class SafepointNode extends FixedWithNextNode implements LIRLowerable, Node.IterableNodeType { public SafepointNode() { - super(StampFactory.forVoid()); + this(StampFactory.forVoid()); + } + + public SafepointNode(Stamp stamp) { + super(stamp); } @Override diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -29,4 +29,8 @@ */ public class StartNode extends BeginStateSplitNode implements MemoryCheckpoint { + @Override + public Object[] getLocationIdentities() { + return new Object[]{LocationNode.ANY_LOCATION}; + } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,6 @@ */ package com.oracle.graal.nodes; -import com.oracle.graal.api.code.*; -import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.spi.*; @@ -33,9 +31,7 @@ * Unwind takes an exception object, destroys the current stack frame and passes the exception * object to the system's exception dispatch code. */ -public final class UnwindNode extends FixedNode implements LIRLowerable, Node.IterableNodeType { - - public static final Descriptor UNWIND_EXCEPTION = new Descriptor("unwindException", true, void.class, Object.class); +public final class UnwindNode extends ControlSinkNode implements Lowerable, LIRLowerable, Node.IterableNodeType { @Input private ValueNode exception; @@ -51,7 +47,11 @@ @Override public void generate(LIRGeneratorTool gen) { - RuntimeCallTarget call = gen.getRuntime().lookupRuntimeCall(UNWIND_EXCEPTION); - gen.emitCall(call, call.getCallingConvention(), false, gen.operand(exception())); + gen.emitUnwind(gen.operand(exception())); + } + + @Override + public void lower(LoweringTool tool) { + tool.getRuntime().lower(this, tool); } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -28,7 +28,6 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.iterators.*; import com.oracle.graal.nodes.type.*; -import com.oracle.graal.nodes.type.GenericStamp.*; import com.oracle.graal.nodes.util.*; /** @@ -174,9 +173,6 @@ @Override public boolean verify() { - for (ValueNode v : dependencies().nonNull()) { - assertTrue(!(v.stamp() instanceof GenericStamp) || ((GenericStamp) v.stamp()).type() == GenericStampType.Dependency, "cannot depend on node with stamp %s", v.stamp()); - } assertTrue(kind() != null, "Should have a valid kind"); assertTrue(kind() == kind().getStackKind(), "Should have a stack kind : %s", kind()); return super.verify(); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java Thu Mar 21 14:11:13 2013 +0100 @@ -31,7 +31,7 @@ public class ValueNodeUtil { public static ValueNode assertKind(Kind kind, ValueNode x) { - assert x != null && ((x.kind() == kind) || (x.kind() == Kind.Jsr && kind == Kind.Object)) : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.kind()); + assert x != null && x.kind() == kind : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.kind()); return x; } @@ -48,11 +48,6 @@ return x; } - public static ValueNode assertJsr(ValueNode x) { - assert x != null && (x.kind() == Kind.Jsr); - return x; - } - public static ValueNode assertInt(ValueNode x) { assert x != null && (x.kind() == Kind.Int); return x; diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +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.nodes; - -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.Node.ValueNumberable; -import com.oracle.graal.nodes.PhiNode.PhiType; -import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; - -/** - * A value proxy that is inserted in the frame state of a loop exit for any value that is created - * inside the loop (i.e. was not live on entry to the loop) and is (potentially) used after the - * loop. - */ -public class ValueProxyNode extends FloatingNode implements Node.IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable { - - @Input(notDataflow = true) private BeginNode proxyPoint; - @Input private ValueNode value; - private final PhiType type; - - public ValueProxyNode(ValueNode value, BeginNode exit, PhiType type) { - super(value.stamp()); - this.type = type; - assert exit != null; - this.proxyPoint = exit; - this.value = value; - } - - public ValueNode value() { - return value; - } - - @Override - public boolean inferStamp() { - return updateStamp(value.stamp()); - } - - @Override - public Stamp stamp() { - return value().stamp(); - } - - public BeginNode proxyPoint() { - return proxyPoint; - } - - public PhiType type() { - return type; - } - - @Override - public boolean verify() { - assert value != null; - assert proxyPoint != null; - return super.verify(); - } - - @Override - public ValueNode canonical(CanonicalizerTool tool) { - if (value.isConstant()) { - return value; - } - return this; - } - - @Override - public void virtualize(VirtualizerTool tool) { - State state = tool.getObjectState(value); - if (state != null && state.getState() == EscapeState.Virtual) { - tool.replaceWithVirtual(state.getVirtualObject()); - } - } -} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/Condition.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/Condition.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/Condition.java Thu Mar 21 14:11:13 2013 +0100 @@ -342,7 +342,6 @@ case Byte: case Char: case Short: - case Jsr: case Int: { int x = lt.asInt(); int y = rt.asInt(); diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -32,12 +32,29 @@ /** * The {@code ConvertNode} class represents a conversion between primitive types. */ -public final class ConvertNode extends FloatingNode implements Canonicalizable, LIRLowerable { +public final class ConvertNode extends FloatingNode implements Canonicalizable, LIRLowerable, Lowerable { public enum Op { - I2L(Int, Long), L2I(Long, Int), I2B(Int, Byte), I2C(Int, Char), I2S(Int, Short), F2D(Float, Double), D2F(Double, Float), I2F(Int, Float), I2D(Int, Double), F2I(Float, Int), D2I(Double, Int), L2F( - Long, Float), L2D(Long, Double), F2L(Float, Long), D2L(Double, Long), UNSIGNED_I2L(Int, Long), MOV_I2F(Int, Float), MOV_L2D(Long, Double), MOV_F2I(Float, Int), MOV_D2L(Double, - Long); + I2L(Int, Long), + L2I(Long, Int), + I2B(Int, Byte), + I2C(Int, Char), + I2S(Int, Short), + F2D(Float, Double), + D2F(Double, Float), + I2F(Int, Float), + I2D(Int, Double), + F2I(Float, Int), + D2I(Double, Int), + L2F(Long, Float), + L2D(Long, Double), + F2L(Float, Long), + D2L(Double, Long), + UNSIGNED_I2L(Int, Long), + MOV_I2F(Int, Float), + MOV_L2D(Long, Double), + MOV_F2I(Float, Int), + MOV_D2L(Double, Long); public final Kind from; public final Kind to; @@ -145,6 +162,11 @@ } @Override + public void lower(LoweringTool tool) { + tool.getRuntime().lower(this, tool); + } + + @Override public void generate(LIRGeneratorTool gen) { gen.setResult(this, gen.emitConvert(opcode, gen.operand(value()))); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Thu Mar 21 14:11:13 2013 +0100 @@ -47,6 +47,7 @@ protected Block() { id = ControlFlowGraph.BLOCK_ID_INITIAL; + this.linearScanNumber = -1; } public int getId() { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/CFGVerifier.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/CFGVerifier.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/CFGVerifier.java Thu Mar 21 14:11:13 2013 +0100 @@ -67,6 +67,7 @@ if (!(block.isLoopHeader() && block.getLoop() == loop)) { for (Block pred : block.getPredecessors()) { if (!loop.blocks.contains(pred)) { + assert false : "Loop " + loop + " does not contain " + pred; return false; } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Thu Mar 21 14:11:13 2013 +0100 @@ -108,9 +108,38 @@ return loops; } + public void clearNodeToBlock() { + nodeToBlock.clear(); + for (Block block : reversePostOrder) { + identifyBlock(block, block.beginNode); + } + } + protected static final int BLOCK_ID_INITIAL = -1; protected static final int BLOCK_ID_VISITED = -2; + private void identifyBlock(Block block, BeginNode begin) { + block.beginNode = begin; + Node cur = begin; + Node last; + do { + assert !cur.isDeleted(); + + assert nodeToBlock.get(cur) == null; + nodeToBlock.set(cur, block); + if (cur instanceof MergeNode) { + for (PhiNode phi : ((MergeNode) cur).phis()) { + nodeToBlock.set(phi, block); + } + } + + last = cur; + cur = cur.successors().first(); + } while (cur != null && !(cur instanceof BeginNode)); + + block.endNode = (FixedNode) last; + } + private void identifyBlocks() { // Find all block headers int numBlocks = 0; @@ -118,26 +147,7 @@ if (node instanceof BeginNode) { Block block = new Block(); numBlocks++; - - block.beginNode = (BeginNode) node; - Node cur = node; - Node last; - do { - assert !cur.isDeleted(); - - assert nodeToBlock.get(cur) == null; - nodeToBlock.set(cur, block); - if (cur instanceof MergeNode) { - for (PhiNode phi : ((MergeNode) cur).phis()) { - nodeToBlock.set(phi, block); - } - } - - last = cur; - cur = cur.successors().first(); - } while (cur != null && !(cur instanceof BeginNode)); - - block.endNode = (FixedNode) last; + identifyBlock(block, (BeginNode) node); } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,120 @@ +/* + * 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.debug; + +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.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * This node can be used to add a counter to the code that will estimate the dynamic number of calls + * by adding an increment to the compiled code. This should of course only be used for + * debugging/testing purposes, and is not 100% accurate (because of concurrency issues while + * accessing the counters). + * + * A unique counter will be created for each unique String passed to the constructor. + */ +public class DynamicCounterNode extends FixedWithNextNode implements Lowerable { + + private static final int MAX_COUNTERS = 10 * 1024; + private static final long[] COUNTERS = new long[MAX_COUNTERS]; + private static final HashMap INDEXES = new HashMap<>(); + private final String name; + private final boolean addContext; + + public DynamicCounterNode(String name, boolean addContext) { + super(StampFactory.forVoid()); + this.name = name; + this.addContext = addContext; + } + + private static synchronized int getIndex(String name) { + Integer index = INDEXES.get(name); + if (index == null) { + index = INDEXES.size(); + if (index == 0) { + Runtime.getRuntime().addShutdownHook(new Thread() { + + @Override + public void run() { + dump(); + } + }); + } + INDEXES.put(name, index); + if (index >= MAX_COUNTERS) { + throw new GraalInternalError("too many dynamic counters"); + } + return index; + } else { + return index; + } + } + + private static synchronized void dump() { + TreeMap sorted = new TreeMap<>(); + + long sum = 0; + for (int i = 0; i < MAX_COUNTERS; i++) { + sum += COUNTERS[i]; + } + int cnt = 0; + for (Map.Entry entry : INDEXES.entrySet()) { + sorted.put(COUNTERS[entry.getValue()] * MAX_COUNTERS + cnt++, entry.getKey()); + } + + for (Map.Entry entry : sorted.entrySet()) { + System.out.println((entry.getKey() / MAX_COUNTERS) + ": " + entry.getValue()); + } + System.out.println(sum + ": total"); + + } + + @Override + public void lower(LoweringTool tool) { + int index = addContext ? getIndex(name + " @ " + MetaUtil.format("%h.%n", ((StructuredGraph) graph()).method())) : getIndex(name); + + StructuredGraph graph = (StructuredGraph) graph(); + ConstantNode arrayConstant = ConstantNode.forObject(COUNTERS, tool.getRuntime(), graph); + ConstantNode indexConstant = ConstantNode.forInt(index, graph); + LoadIndexedNode load = graph.add(new LoadIndexedNode(arrayConstant, indexConstant, Kind.Long)); + IntegerAddNode add = graph.add(new IntegerAddNode(Kind.Long, load, ConstantNode.forLong(1, graph))); + StoreIndexedNode store = graph.add(new StoreIndexedNode(arrayConstant, indexConstant, Kind.Long, add)); + + graph.addBeforeFixed(this, load); + graph.addBeforeFixed(this, store); + graph.removeFixed(this); + } + + public static void createCounter(String name, FixedNode before, boolean addContext) { + StructuredGraph graph = (StructuredGraph) before.graph(); + DynamicCounterNode counter = graph.add(new DynamicCounterNode(name, addContext)); + graph.addBeforeFixed(before, counter); + } +} diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/Access.java Thu Mar 21 14:11:13 2013 +0100 @@ -29,7 +29,7 @@ ValueNode object(); - LocationNode location(); + LocationNode nullCheckLocation(); void setNullCheck(boolean check); diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,13 +22,16 @@ */ package com.oracle.graal.nodes.extended; +import java.util.*; + import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.type.*; /** * Accesses a value at an memory address specified by an {@linkplain #object object} and a - * {@linkplain #location() location}. The access does not include a null check on the object. + * {@linkplain #nullCheckLocation() location}. The access does not include a null check on the + * object. */ public abstract class AccessNode extends FixedWithNextNode implements Access { @@ -44,6 +47,10 @@ return (LocationNode) location; } + public LocationNode nullCheckLocation() { + return (LocationNode) location; + } + public boolean getNullCheck() { return nullCheck; } @@ -58,6 +65,12 @@ this.location = location; } + public AccessNode(ValueNode object, ValueNode location, Stamp stamp, List dependencies) { + super(stamp, dependencies); + this.object = object; + this.location = location; + } + public AccessNode(ValueNode object, ValueNode location, Stamp stamp, ValueNode... dependencies) { super(stamp, dependencies); this.object = object; diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -43,6 +43,10 @@ return location; } + public LocationNode nullCheckLocation() { + return location; + } + public boolean getNullCheck() { return nullCheck; } @@ -73,4 +77,6 @@ public Node node() { return this; } + + public abstract Access asFixedNode(); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -53,11 +53,16 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitLoad(gen.makeAddress(location(), object()), getNullCheck())); + gen.setResult(this, location().generateLoad(gen, object(), getNullCheck())); } @Override public ValueNode canonical(CanonicalizerTool tool) { - return ReadNode.canonicalizeRead(this, tool); + return ReadNode.canonicalizeRead(this, location(), object(), tool); + } + + @Override + public Access asFixedNode() { + return graph().add(new ReadNode(object(), nullCheckLocation(), stamp(), dependencies())); } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GenerateLEANode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GenerateLEANode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/GenerateLEANode.java Thu Mar 21 14:11:13 2013 +0100 @@ -57,7 +57,7 @@ @Override public void generate(LIRGeneratorTool gen) { - Value addr = gen.emitLea(gen.makeAddress(location(), object())); + Value addr = location().generateLea(gen, object()); gen.setResult(this, addr); } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -28,17 +28,14 @@ import com.oracle.graal.nodes.spi.*; /** - * Extension of a {@linkplain LocationNode location} to include a scaled index or an additional - * offset. + * Extension of a {@linkplain LocationNode location} to include a scaled index. Can represent + * locations in the form of [base + index * scale + disp] where base and index are nodes and scale + * and disp are integer constants. */ public final class IndexedLocationNode extends LocationNode implements Canonicalizable { - /** - * An offset or index depending on whether {@link #indexScalingEnabled} is true or false - * respectively. - */ @Input private ValueNode index; - private final boolean indexScalingEnabled; + private final int indexScaling; /** * Gets the index or offset of this location. @@ -52,21 +49,20 @@ } /** - * @return whether scaling of the index by the value kind's size is enabled (the default) or - * disabled. + * @return Constant that is used to scale the index. */ - public boolean indexScalingEnabled() { - return indexScalingEnabled; + public int indexScaling() { + return indexScaling; } - public static IndexedLocationNode create(Object identity, Kind kind, int displacement, ValueNode index, Graph graph, boolean indexScalingEnabled) { - return graph.unique(new IndexedLocationNode(identity, kind, index, displacement, indexScalingEnabled)); + public static IndexedLocationNode create(Object identity, Kind kind, int displacement, ValueNode index, Graph graph, int indexScaling) { + return graph.unique(new IndexedLocationNode(identity, kind, index, displacement, indexScaling)); } - private IndexedLocationNode(Object identity, Kind kind, ValueNode index, int displacement, boolean indexScalingEnabled) { + private IndexedLocationNode(Object identity, Kind kind, ValueNode index, int displacement, int indexScaling) { super(identity, kind, displacement); this.index = index; - this.indexScalingEnabled = indexScalingEnabled; + this.indexScaling = indexScaling; } @Override @@ -74,12 +70,7 @@ Constant constantIndex = index.asConstant(); if (constantIndex != null) { long constantIndexLong = constantIndex.asLong(); - if (indexScalingEnabled) { - if (tool.target() == null) { - return this; - } - constantIndexLong *= tool.target().sizeInBytes(getValueKind()); - } + constantIndexLong *= indexScaling; constantIndexLong += displacement(); int constantIndexInt = (int) constantIndexLong; if (constantIndexLong == constantIndexInt) { @@ -88,4 +79,19 @@ } return this; } + + @Override + public Value generateLea(LIRGeneratorTool gen, ValueNode base) { + return gen.emitLea(gen.operand(base), displacement(), gen.operand(index()), indexScaling()); + } + + @Override + public Value generateLoad(LIRGeneratorTool gen, ValueNode base, boolean canTrap) { + return gen.emitLoad(getValueKind(), gen.operand(base), displacement(), gen.operand(index()), indexScaling(), canTrap); + } + + @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); + } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -25,13 +25,15 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.ValueNumberable; +import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; /** - * A location for a memory access in terms of the kind of value accessed and the displacement (in - * bytes) from a base object or address. + * A location for a memory access in terms of the kind of value accessed and how to access it. The + * base version can represent addresses of the form [base + disp] where base is a node and disp is a + * constant. */ @NodeInfo(nameTemplate = "Loc {p#locationIdentity/s}") public class LocationNode extends FloatingNode implements LIRLowerable, ValueNumberable { @@ -41,27 +43,37 @@ private Object locationIdentity; /** + * Creates a new unique location identity for read and write operations. + * + * @param name the name of the new location identity, for debugging purposes + * @return the new location identity + */ + public static Object createLocation(final String name) { + return new Object() { + + @Override + public String toString() { + return name; + } + }; + } + + /** * 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. */ - public static final Object ANY_LOCATION = new Object() { + public static final Object ANY_LOCATION = createLocation("ANY_LOCATION"); - @Override - public String toString() { - return "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 = new Object() { - - @Override - public String toString() { - return "FINAL_LOCATION"; - } - }; + public static final Object FINAL_LOCATION = createLocation("FINAL_LOCATION"); public static Object getArrayLocation(Kind elementKind) { return elementKind; @@ -95,4 +107,16 @@ public void generate(LIRGeneratorTool generator) { // nothing to do... } + + public Value generateLea(LIRGeneratorTool gen, ValueNode base) { + 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 void generateStore(LIRGeneratorTool gen, ValueNode base, ValueNode value, boolean canTrap) { + gen.emitStore(getValueKind(), gen.operand(base), displacement(), Value.ILLEGAL, 0, gen.operand(value), canTrap); + } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -43,6 +43,11 @@ } @Override + public Object[] getLocationIdentities() { + return new Object[]{LocationNode.ANY_LOCATION}; + } + + @Override public void generate(LIRGeneratorTool generator) { generator.emitMembar(barriers); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryCheckpoint.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,6 +22,21 @@ */ package com.oracle.graal.nodes.extended; +import com.oracle.graal.nodes.*; + +/** + * This interface marks is used for subclasses of {@link FixedNode} that kill a set of memory + * locations represented by location identities (i.e. change a value at one or more locations that + * belong to these location identities). + */ public interface MemoryCheckpoint { + /** + * This method is used to determine which set of memory locations is killed by this node. + * Returning the special value {@link LocationNode#ANY_LOCATION} will kill all memory locations. + * + * @return the identities of all locations killed by this node. + */ + Object[] getLocationIdentities(); + } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,46 @@ +/* + * 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.extended; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public class NullCheckNode extends FixedWithNextNode implements LIRLowerable { + + @Input public ValueNode object; + + public NullCheckNode(ValueNode object) { + super(StampFactory.dependency()); + this.object = object; + } + + public ValueNode getObject() { + return object; + } + + @Override + public void generate(LIRGeneratorTool generator) { + generator.emitNullCheck(object); + } +} diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes.extended; +import java.util.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; @@ -37,6 +39,10 @@ super(object, location, stamp); } + public ReadNode(ValueNode object, ValueNode location, Stamp stamp, List dependencies) { + super(object, location, stamp, dependencies); + } + private ReadNode(ValueNode object, int displacement, Object locationIdentity, Kind kind) { super(object, object.graph().add(new LocationNode(locationIdentity, kind, displacement)), StampFactory.forKind(kind)); } @@ -51,40 +57,40 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitLoad(gen.makeAddress(location(), object()), getNullCheck())); + gen.setResult(this, location().generateLoad(gen, object(), getNullCheck())); } @Override public ValueNode canonical(CanonicalizerTool tool) { - return canonicalizeRead(this, tool); + return canonicalizeRead(this, location(), object(), tool); } - public static ValueNode canonicalizeRead(Access read, CanonicalizerTool tool) { + public static ValueNode canonicalizeRead(ValueNode read, LocationNode location, ValueNode object, CanonicalizerTool tool) { MetaAccessProvider runtime = tool.runtime(); - if (runtime != null && read.object() != null && read.object().isConstant()) { - if (read.location().locationIdentity() == LocationNode.FINAL_LOCATION && read.location().getClass() == LocationNode.class) { - long displacement = read.location().displacement(); - Kind kind = read.location().getValueKind(); - if (read.object().kind() == Kind.Object) { - Object base = read.object().asConstant().asObject(); + if (runtime != null && object != null && object.isConstant()) { + if (location.locationIdentity() == LocationNode.FINAL_LOCATION && location.getClass() == LocationNode.class) { + long displacement = location.displacement(); + Kind kind = location.getValueKind(); + if (object.kind() == Kind.Object) { + Object base = object.asConstant().asObject(); if (base != null) { Constant constant = tool.runtime().readUnsafeConstant(kind, base, displacement); if (constant != null) { - return ConstantNode.forConstant(constant, runtime, read.node().graph()); + return ConstantNode.forConstant(constant, runtime, read.graph()); } } - } else if (read.object().kind() == Kind.Long || read.object().kind().getStackKind() == Kind.Int) { - long base = read.object().asConstant().asLong(); + } else if (object.kind() == Kind.Long || object.kind().getStackKind() == Kind.Int) { + long base = object.asConstant().asLong(); if (base != 0L) { Constant constant = tool.runtime().readUnsafeConstant(kind, null, base + displacement); if (constant != null) { - return ConstantNode.forConstant(constant, runtime, read.node().graph()); + return ConstantNode.forConstant(constant, runtime, read.graph()); } } } } } - return (ValueNode) read; + return read; } /** diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/RuntimeCallNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -49,6 +49,11 @@ } @Override + public Object[] getLocationIdentities() { + return new Object[]{LocationNode.ANY_LOCATION}; + } + + @Override public void generate(LIRGeneratorTool gen) { gen.visitRuntimeCall(this); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -53,6 +53,9 @@ if (kind() != Kind.Object || object().kind() != Kind.Object) { return false; } + if (stamp() == StampFactory.forNodeIntrinsic()) { + return false; + } if (object().objectStamp().alwaysNull() && objectStamp().nonNull()) { // a null value flowing into a nonNull UnsafeCastNode should be guarded by a type/isNull // guard, but the @@ -93,7 +96,7 @@ 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(generator.operand(object), result); + 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 diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -33,7 +33,7 @@ * Store of a value at a location specified as an offset relative to an object. No null check is * performed before the store. */ -public class UnsafeStoreNode extends UnsafeAccessNode implements StateSplit, Lowerable, Virtualizable, Canonicalizable { +public class UnsafeStoreNode extends UnsafeAccessNode implements StateSplit, Lowerable, Virtualizable, Canonicalizable, MemoryCheckpoint { @Input private ValueNode value; @Input(notDataflow = true) private FrameState stateAfter; @@ -72,6 +72,11 @@ } @Override + public Object[] getLocationIdentities() { + return new Object[]{LocationNode.ANY_LOCATION}; + } + + @Override public void virtualize(VirtualizerTool tool) { State state = tool.getObjectState(object()); if (state != null && state.getState() == EscapeState.Virtual) { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -28,7 +28,6 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -38,9 +37,16 @@ public final class ValueAnchorNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType, Virtualizable { public ValueAnchorNode(ValueNode... values) { + this(false, values); + } + + public ValueAnchorNode(boolean permanent, ValueNode... values) { super(StampFactory.dependency(), values); + this.permanent = permanent; } + private final boolean permanent; + @Override public void generate(LIRGeneratorTool gen) { // Nothing to emit, since this node is used for structural purposes only. @@ -54,6 +60,9 @@ @Override public ValueNode canonical(CanonicalizerTool tool) { + if (permanent) { + return this; + } if (this.predecessor() instanceof ValueAnchorNode) { ValueAnchorNode previousAnchor = (ValueAnchorNode) this.predecessor(); if (previousAnchor.usages().isEmpty()) { // avoid creating cycles @@ -64,7 +73,7 @@ return previousAnchor; } } - for (Node node : dependencies().nonNull().and(isNotA(BeginNode.class))) { + for (Node node : dependencies().nonNull().and(isNotA(FixedNode.class))) { if (node instanceof ConstantNode) { continue; } @@ -88,12 +97,8 @@ @Override public void virtualize(VirtualizerTool tool) { - // don't process this node if it is anchoring the return value - if (next() instanceof MonitorExitNode) { - MonitorExitNode monitorExit = (MonitorExitNode) next(); - if (monitorExit.stateAfter() != null && monitorExit.stateAfter().bci == FrameState.AFTER_BCI && monitorExit.next() instanceof ReturnNode) { - return; - } + if (permanent) { + return; } for (ValueNode node : dependencies().nonNull().and(isNotA(BeginNode.class))) { State state = tool.getObjectState(node); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -37,6 +37,11 @@ } @Override + public Object[] getLocationIdentities() { + return new Object[]{LocationNode.ANY_LOCATION}; + } + + @Override public void generate(LIRGeneratorTool generator) { // nothing to do... } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -29,7 +29,7 @@ /** * Writes a given {@linkplain #value() value} a {@linkplain AccessNode memory location}. */ -public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable { +public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint { @Input private ValueNode value; @Input(notDataflow = true) private FrameState stateAfter; @@ -59,9 +59,14 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.emitStore(gen.makeAddress(location(), object()), gen.operand(value()), getNullCheck()); + location().generateStore(gen, object(), value(), getNullCheck()); } @NodeIntrinsic public static native void writeMemory(Object object, Object value, Object location); + + @Override + public Object[] getLocationIdentities() { + return new Object[]{location().locationIdentity()}; + } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -71,6 +71,11 @@ } @Override + public Object[] getLocationIdentities() { + return new Object[]{LocationNode.ANY_LOCATION}; + } + + @Override public void generate(LIRGeneratorTool gen) { gen.visitCompareAndSwap(this); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -32,7 +32,7 @@ * The {@code ExceptionObject} instruction represents the incoming exception object to an exception * handler. */ -public class ExceptionObjectNode extends AbstractStateSplit implements StateSplit, LIRLowerable, MemoryCheckpoint { +public class ExceptionObjectNode extends AbstractStateSplit implements StateSplit, Lowerable, LIRLowerable, MemoryCheckpoint { /** * Constructs a new ExceptionObject instruction. @@ -42,11 +42,21 @@ } @Override + public Object[] getLocationIdentities() { + return new Object[]{LocationNode.ANY_LOCATION}; + } + + @Override public void generate(LIRGeneratorTool gen) { gen.visitExceptionObject(this); } @Override + public void lower(LoweringTool tool) { + tool.getRuntime().lower(this, tool); + } + + @Override public boolean verify() { assertTrue(stateAfter() != null, "an exception handler needs a frame state"); return super.verify(); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -80,7 +80,7 @@ @Override public boolean verify() { for (Node usage : usages()) { - assertTrue(usage instanceof IfNode || usage instanceof ConditionalNode, "unsupported usage: ", usage); + assertTrue(usage instanceof IfNode || usage instanceof ConditionalNode, "unsupported usage: %s", usage); } return super.verify(); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -40,6 +40,11 @@ super(object); } + @Override + public Object[] getLocationIdentities() { + return new Object[]{LocationNode.ANY_LOCATION}; + } + public void lower(LoweringTool tool) { tool.getRuntime().lower(this, tool); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -41,6 +41,11 @@ super(object); } + @Override + public Object[] getLocationIdentities() { + return new Object[]{LocationNode.ANY_LOCATION}; + } + public void lower(LoweringTool tool) { tool.getRuntime().lower(this, tool); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -95,12 +95,12 @@ public void virtualize(VirtualizerTool tool) { if (instanceClass != null) { assert !instanceClass().isArray(); - ResolvedJavaField[] fields = instanceClass().getInstanceFields(true); + VirtualInstanceNode virtualObject = new VirtualInstanceNode(instanceClass()); + ResolvedJavaField[] fields = virtualObject.getFields(); ValueNode[] state = new ValueNode[fields.length]; for (int i = 0; i < state.length; i++) { state[i] = ConstantNode.defaultForKind(fields[i].getType().getKind(), graph()); } - VirtualObjectNode virtualObject = new VirtualInstanceNode(instanceClass(), fields); tool.createVirtualObject(virtualObject, state, 0); tool.replaceWithVirtual(virtualObject); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -32,7 +32,7 @@ * 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 { +public final class RegisterFinalizerNode extends AbstractStateSplit implements StateSplit, Canonicalizable, LIRLowerable, Virtualizable { public static final Descriptor REGISTER_FINALIZER = new Descriptor("registerFinalizer", true, void.class, Object.class); @@ -74,4 +74,12 @@ return this; } + + @Override + public void virtualize(VirtualizerTool tool) { + State state = tool.getObjectState(object); + if (state != null && !state.getVirtualObject().type().hasFinalizer()) { + tool.delete(); + } + } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/CanonicalizerTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/CanonicalizerTool.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/CanonicalizerTool.java Thu Mar 21 14:11:13 2013 +0100 @@ -28,8 +28,6 @@ public interface CanonicalizerTool { - TargetDescription target(); - Assumptions assumptions(); MetaAccessProvider runtime(); diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Thu Mar 21 14:11:13 2013 +0100 @@ -45,35 +45,25 @@ */ public abstract boolean canInlineConstant(Constant c); - /** - * Checks whether the supplied constant can be used without loading it into a register for store - * operations, i.e., on the right hand side of a memory access. - * - * @param c The constant to check. - * @return True if the constant can be used directly, false if the constant needs to be in a - * register. - */ - public abstract boolean canStoreConstant(Constant c); - public abstract RegisterAttributes attributes(Register register); public abstract Value operand(ValueNode object); - public abstract Value newVariable(Kind kind); + public abstract AllocatableValue newVariable(Kind kind); public abstract Value setResult(ValueNode x, Value operand); - public abstract Address makeAddress(LocationNode location, ValueNode object); - public abstract Value emitMove(Value input); - public abstract void emitMove(Value src, Value dst); + public abstract void emitMove(Value dst, Value src); - public abstract Value emitLoad(Value loadAddress, boolean canTrap); + public abstract Value emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap); - public abstract void emitStore(Value storeAddress, Value input, boolean canTrap); + public abstract void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value input, boolean canTrap); - public abstract Value emitLea(Value address); + public abstract Value emitLea(Value base, int displacement, Value index, int scale); + + public abstract Value emitLea(StackSlot slot); public abstract Value emitNegate(Value input); @@ -107,9 +97,9 @@ public abstract void emitMembar(int barriers); - public abstract void emitDeoptimizeOnOverflow(DeoptimizationAction action, DeoptimizationReason reason, Object deoptInfo); + public abstract void emitDeoptimize(DeoptimizationAction action, DeoptimizationReason reason); - public abstract void emitDeoptimize(DeoptimizationAction action, DeoptimizationReason reason, Object deoptInfo); + public abstract void emitNullCheck(ValueNode v); public abstract Value emitCall(RuntimeCallTarget callTarget, CallingConvention cc, boolean canTrap, Value... args); @@ -117,8 +107,6 @@ public abstract void emitConditional(ConditionalNode i); - public abstract void emitGuardCheck(LogicNode comp, DeoptimizationReason deoptReason, DeoptimizationAction deoptAction, boolean negated); - public abstract void emitSwitch(SwitchNode i); public abstract void emitInvoke(Invoke i); @@ -142,4 +130,12 @@ public abstract void visitSafepointNode(SafepointNode i); public abstract void visitBreakpointNode(BreakpointNode i); + + public abstract void emitUnwind(Value operand); + + /** + * Called just before register allocation is performed on the LIR owned by this generator. + */ + public void beforeRegisterAllocation() { + } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java Thu Mar 21 14:11:13 2013 +0100 @@ -48,4 +48,9 @@ * Gets the closest fixed node preceding the node currently being lowered. */ FixedWithNextNode lastFixedNode(); + + /** + * Sets the closest fixed node preceding the next node to be lowered. + */ + void setLastFixedNode(FixedWithNextNode n); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/IntegerStamp.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/IntegerStamp.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/IntegerStamp.java Thu Mar 21 14:11:13 2013 +0100 @@ -199,7 +199,6 @@ return 0xffffL; case Short: return 0xffffL; - case Jsr: case Int: return 0xffffffffL; case Long: diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java Thu Mar 21 14:11:13 2013 +0100 @@ -57,8 +57,6 @@ setCache(Kind.Float, new FloatStamp(Kind.Float)); setCache(Kind.Double, new FloatStamp(Kind.Double)); - setCache(Kind.Jsr, new IntegerStamp(Kind.Jsr)); - setCache(Kind.Object, objectStamp); setCache(Kind.Void, voidStamp); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Thu Mar 21 14:11:13 2013 +0100 @@ -140,18 +140,18 @@ ValueNode singleValue = phiNode.singleValue(); if (singleValue != null) { Collection phiUsages = phiNode.usages().filter(PhiNode.class).snapshot(); - Collection proxyUsages = phiNode.usages().filter(ValueProxyNode.class).snapshot(); + Collection proxyUsages = phiNode.usages().filter(ProxyNode.class).snapshot(); ((StructuredGraph) phiNode.graph()).replaceFloating(phiNode, singleValue); for (PhiNode phi : phiUsages) { checkRedundantPhi(phi); } - for (ValueProxyNode proxy : proxyUsages) { + for (ProxyNode proxy : proxyUsages) { checkRedundantProxy(proxy); } } } - public static void checkRedundantProxy(ValueProxyNode vpn) { + public static void checkRedundantProxy(ProxyNode vpn) { BeginNode proxyPoint = vpn.proxyPoint(); if (proxyPoint instanceof LoopExitNode) { LoopExitNode exit = (LoopExitNode) proxyPoint; @@ -164,12 +164,12 @@ } if (vpnValue == v2) { Collection phiUsages = vpn.usages().filter(PhiNode.class).snapshot(); - Collection proxyUsages = vpn.usages().filter(ValueProxyNode.class).snapshot(); + Collection proxyUsages = vpn.usages().filter(ProxyNode.class).snapshot(); ((StructuredGraph) vpn.graph()).replaceFloating(vpn, vpnValue); for (PhiNode phi : phiUsages) { checkRedundantPhi(phi); } - for (ValueProxyNode proxy : proxyUsages) { + for (ProxyNode proxy : proxyUsages) { checkRedundantProxy(proxy); } return; @@ -185,7 +185,7 @@ GraphUtil.checkRedundantPhi(phi); } for (LoopExitNode exit : begin.loopExits()) { - for (ValueProxyNode vpn : exit.proxies().snapshot()) { + for (ProxyNode vpn : exit.proxies().snapshot()) { GraphUtil.checkRedundantProxy(vpn); } } @@ -259,8 +259,8 @@ public static ValueNode unProxify(ValueNode proxy) { ValueNode v = proxy; - while (v instanceof ValueProxyNode) { - v = ((ValueProxyNode) v).value(); + while (v instanceof ProxyNode) { + v = ((ProxyNode) v).value(); } return v; } @@ -293,8 +293,8 @@ public static ValueNode originalValue(ValueNode proxy) { ValueNode v = proxy; do { - if (v instanceof ValueProxyNode) { - v = ((ValueProxyNode) v).value(); + if (v instanceof ProxyNode) { + v = ((ProxyNode) v).value(); } else if (v instanceof PhiNode) { v = ((PhiNode) v).singleValue(); } else { @@ -308,8 +308,8 @@ NodeWorkList worklist = proxy.graph().createNodeWorkList(); worklist.add(proxy); for (Node node : worklist) { - if (node instanceof ValueProxyNode) { - worklist.add(((ValueProxyNode) node).value()); + if (node instanceof ProxyNode) { + worklist.add(((ProxyNode) node).value()); } else if (node instanceof PhiNode) { worklist.addAll(((PhiNode) node).values()); } else { diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,6 @@ */ package com.oracle.graal.nodes.virtual; -import java.util.*; - import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; @@ -32,21 +30,10 @@ private final ResolvedJavaType type; private final ResolvedJavaField[] fields; - private final HashMap fieldMap; - public VirtualInstanceNode(ResolvedJavaType type, ResolvedJavaField[] fields) { + public VirtualInstanceNode(ResolvedJavaType type) { this.type = type; - this.fields = fields; - fieldMap = new HashMap<>(); - for (int i = 0; i < fields.length; i++) { - fieldMap.put(fields[i], i); - } - } - - private VirtualInstanceNode(ResolvedJavaType type, ResolvedJavaField[] fields, HashMap fieldMap) { - this.type = type; - this.fields = fields; - this.fieldMap = fieldMap; + this.fields = type.getInstanceFields(true); } @Override @@ -63,6 +50,10 @@ return fields[index]; } + public ResolvedJavaField[] getFields() { + return fields; + } + @Override public String toString(Verbosity verbosity) { if (verbosity == Verbosity.Name) { @@ -78,8 +69,13 @@ } public int fieldIndex(ResolvedJavaField field) { - Integer index = fieldMap.get(field); - return index == null ? -1 : index; + // on average fields.length == ~6, so a linear search is fast enough + for (int i = 0; i < fields.length; i++) { + if (fields[i] == field) { + return i; + } + } + return -1; } @Override @@ -95,6 +91,6 @@ @Override public VirtualInstanceNode duplicate() { - return new VirtualInstanceNode(type, fields, fieldMap); + return new VirtualInstanceNode(type); } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -48,7 +48,6 @@ public static final DebugMetric METRIC_GLOBAL_VALUE_NUMBERING_HITS = Debug.metric("GlobalValueNumberingHits"); private final int newNodesMark; - private final TargetDescription target; private final Assumptions assumptions; private final MetaAccessProvider runtime; private final CustomCanonicalizer customCanonicalizer; @@ -63,33 +62,31 @@ ValueNode canonicalize(Node node); } - public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions) { - this(target, runtime, assumptions, null, 0, null); + public CanonicalizerPhase(MetaAccessProvider runtime, Assumptions assumptions) { + this(runtime, assumptions, null, 0, null); } /** - * @param target * @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(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, Iterable workingSet, CustomCanonicalizer customCanonicalizer) { - this(target, runtime, assumptions, workingSet, 0, 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(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, int newNodesMark, CustomCanonicalizer customCanonicalizer) { - this(target, runtime, assumptions, null, newNodesMark, customCanonicalizer); + public CanonicalizerPhase(MetaAccessProvider runtime, Assumptions assumptions, int newNodesMark, CustomCanonicalizer customCanonicalizer) { + this(runtime, assumptions, null, newNodesMark, customCanonicalizer); } - public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, Iterable workingSet, int newNodesMark, CustomCanonicalizer customCanonicalizer) { + public CanonicalizerPhase(MetaAccessProvider runtime, Assumptions assumptions, Iterable workingSet, int newNodesMark, CustomCanonicalizer customCanonicalizer) { this.newNodesMark = newNodesMark; - this.target = target; this.assumptions = assumptions; this.runtime = runtime; this.customCanonicalizer = customCanonicalizer; @@ -108,7 +105,7 @@ if (newNodesMark > 0) { workList.addAll(graph.getNewNodes(newNodesMark)); } - tool = new Tool(workList, runtime, target, assumptions); + tool = new Tool(workList, runtime, assumptions); processWorkSet(graph); } @@ -309,13 +306,11 @@ private final NodeWorkList nodeWorkSet; private final MetaAccessProvider runtime; - private final TargetDescription target; private final Assumptions assumptions; - public Tool(NodeWorkList nodeWorkSet, MetaAccessProvider runtime, TargetDescription target, Assumptions assumptions) { + public Tool(NodeWorkList nodeWorkSet, MetaAccessProvider runtime, Assumptions assumptions) { this.nodeWorkSet = nodeWorkSet; this.runtime = runtime; - this.target = target; this.assumptions = assumptions; } @@ -326,15 +321,6 @@ } /** - * @return the current target or {@code null} if no target is available in the current - * context. - */ - @Override - public TargetDescription target() { - return target; - } - - /** * @return an object that can be used for recording assumptions or {@code null} if * assumptions are not allowed in the current context. */ diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -299,8 +299,18 @@ public ConditionalElimination(FixedNode start, State initialState) { super(start, initialState); - this.trueConstant = LogicConstantNode.tautology(graph); - this.falseConstant = LogicConstantNode.contradiction(graph); + trueConstant = LogicConstantNode.tautology(graph); + falseConstant = LogicConstantNode.contradiction(graph); + } + + @Override + public void finished() { + if (trueConstant.usages().isEmpty()) { + graph.removeFloating(trueConstant); + } + if (falseConstant.usages().isEmpty()) { + graph.removeFloating(falseConstant); + } } private void registerCondition(boolean isTrue, LogicNode condition, ValueNode anchor) { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -51,6 +51,7 @@ } for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.class)) { + assert d.isAlive(); visitDeoptBegin(findBeginNode(d), d, graph); } @@ -61,45 +62,53 @@ if (deoptBegin instanceof MergeNode) { MergeNode mergeNode = (MergeNode) deoptBegin; Debug.log("Visiting %s followed by %s", mergeNode, deopt); - List ends = mergeNode.forwardEnds().snapshot(); - for (EndNode end : ends) { - if (!end.isDeleted()) { - BeginNode beginNode = findBeginNode(end); - if (!(beginNode instanceof MergeNode)) { - visitDeoptBegin(beginNode, deopt, graph); - } - } + List begins = new ArrayList<>(); + for (EndNode end : mergeNode.forwardEnds()) { + BeginNode newBeginNode = findBeginNode(end); + assert !begins.contains(newBeginNode); + begins.add(newBeginNode); } - if (mergeNode.isDeleted()) { - if (!deopt.isDeleted()) { - Debug.log("Merge deleted, deopt moved to %s", findBeginNode(deopt)); - visitDeoptBegin(findBeginNode(deopt), deopt, graph); - } + for (BeginNode begin : begins) { + assert !begin.isDeleted(); + visitDeoptBegin(begin, deopt, graph); } + assert mergeNode.isDeleted(); + return; } else if (deoptBegin.predecessor() instanceof IfNode) { IfNode ifNode = (IfNode) deoptBegin.predecessor(); BeginNode otherBegin = ifNode.trueSuccessor(); LogicNode conditionNode = ifNode.condition(); - if (conditionNode instanceof InstanceOfNode) { + if (!(conditionNode instanceof InstanceOfNode) && !(conditionNode instanceof InstanceOfDynamicNode)) { // TODO The lowering currently does not support a FixedGuard as the usage of an // InstanceOfNode. Relax this restriction. + FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), deoptBegin == ifNode.trueSuccessor())); + FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor(); + if (deoptBegin == ifNode.trueSuccessor()) { + graph.removeSplitPropagate(ifNode, ifNode.falseSuccessor()); + } else { + graph.removeSplitPropagate(ifNode, ifNode.trueSuccessor()); + } + Debug.log("Converting %s on %-5s branch of %s to guard for remaining branch %s.", deopt, deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin); + FixedNode next = pred.next(); + pred.setNext(guard); + guard.setNext(next); return; } - boolean negated = false; - if (deoptBegin == ifNode.trueSuccessor()) { - negated = true; - otherBegin = ifNode.falseSuccessor(); - } - BeginNode ifBlockBegin = findBeginNode(ifNode); - Debug.log("Converting %s on %-5s branch of %s to guard for remaining branch %s. IfBegin=%s", deopt, deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin, - ifBlockBegin); - FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), negated)); - otherBegin.replaceAtUsages(ifBlockBegin); - FixedNode next = otherBegin.next(); - otherBegin.setNext(null); - guard.setNext(next); - ifNode.replaceAtPredecessor(guard); - GraphUtil.killCFG(ifNode); + } + + // We could not convert the control split - at least cut off control flow after the split. + FixedWithNextNode deoptPred = deoptBegin; + FixedNode next = deoptPred.next(); + if (next instanceof ExceptionObjectNode) { + deoptPred = (FixedWithNextNode) next; + next = deoptPred.next(); + } + + if (next != deopt) { + DeoptimizeNode newDeoptNode = (DeoptimizeNode) deopt.clone(graph); + deoptPred.setNext(newDeoptNode); + assert deoptPred == newDeoptNode.predecessor(); + GraphUtil.killCFG(next); } } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertUnreachedToGuardPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertUnreachedToGuardPhase.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +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.phases.common; - -import com.oracle.graal.api.code.*; -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.util.*; -import com.oracle.graal.phases.*; - -public class ConvertUnreachedToGuardPhase extends Phase { - - private OptimisticOptimizations opt; - - public ConvertUnreachedToGuardPhase(OptimisticOptimizations opt) { - this.opt = opt; - } - - @Override - protected void run(StructuredGraph graph) { - if (!opt.removeNeverExecutedCode()) { - return; - } - for (Node node : graph.getNodes()) { - if (node instanceof IfNode) { - IfNode ifNode = (IfNode) node; - BeginNode insertGuard = null; - BeginNode delete = null; - boolean inverted = false; - if (ifNode.probability(ifNode.trueSuccessor()) == 0) { - insertGuard = ifNode.falseSuccessor(); - delete = ifNode.trueSuccessor(); - inverted = true; - } else if (ifNode.probability(ifNode.falseSuccessor()) == 0) { - insertGuard = ifNode.trueSuccessor(); - delete = ifNode.falseSuccessor(); - } - if (insertGuard != null) { - GuardNode guard = graph.unique(new GuardNode(ifNode.condition(), BeginNode.prevBegin(ifNode), DeoptimizationReason.UnreachedCode, DeoptimizationAction.InvalidateReprofile, - inverted)); - graph.addBeforeFixed(ifNode, graph.add(new ValueAnchorNode(guard))); - GraphUtil.killCFG(delete); - graph.removeSplit(ifNode, inverted ? ifNode.falseSuccessor() : ifNode.trueSuccessor()); - } - } - } - - } - -} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -37,11 +37,14 @@ public class CullFrameStatesPhase extends Phase { private static final DebugMetric metricFrameStatesCulled = Debug.metric("FrameStatesCulled"); + private static final DebugMetric metricNodesRemoved = Debug.metric("NodesRemoved"); private static final DebugMetric metricMergesTraversed = Debug.metric("MergesTraversed"); @Override protected void run(StructuredGraph graph) { + int initialNodes = graph.getNodeCount(); new CullFrameStates(graph.start(), new State(null)).apply(); + metricNodesRemoved.add(initialNodes - graph.getNodeCount()); } public static class State implements MergeableState { diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -29,271 +29,236 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.graph.*; +import com.oracle.graal.phases.graph.ReentrantNodeIterator.LoopInfo; +import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; public class FloatingReadPhase extends Phase { - private IdentityHashMap> loopEndStatesMap; - - private static class LoopState { - - public LoopBeginNode loopBegin; - public MemoryMap state; - public IdentityHashMap loopPhiLocations = new IdentityHashMap<>(); - public ValueNode loopEntryAnyLocation; - - public LoopState(LoopBeginNode loopBegin, MemoryMap state, ValueNode loopEntryAnyLocation) { - this.loopBegin = loopBegin; - this.state = state; - this.loopEntryAnyLocation = loopEntryAnyLocation; - } - - @Override - public String toString() { - return "State@" + loopBegin; - } - } - - private class MemoryMap implements MergeableState { + private static class MemoryMap { private IdentityHashMap lastMemorySnapshot; - private LinkedList loops; public MemoryMap(MemoryMap memoryMap) { lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot); - loops = new LinkedList<>(memoryMap.loops); + } + + public MemoryMap(StartNode start) { + this(); + lastMemorySnapshot.put(LocationNode.ANY_LOCATION, start); } public MemoryMap() { lastMemorySnapshot = new IdentityHashMap<>(); - loops = new LinkedList<>(); + } + + private ValueNode getLastLocationAccess(Object locationIdentity) { + ValueNode lastLocationAccess; + if (locationIdentity == LocationNode.FINAL_LOCATION) { + return null; + } else { + lastLocationAccess = lastMemorySnapshot.get(locationIdentity); + if (lastLocationAccess == null) { + lastLocationAccess = lastMemorySnapshot.get(LocationNode.ANY_LOCATION); + assert lastLocationAccess != null; + } + return lastLocationAccess; + } } @Override public String toString() { - return "Map=" + lastMemorySnapshot.toString() + " Loops=" + loops.toString(); - } - - @SuppressWarnings("unchecked") - @Override - public boolean merge(MergeNode merge, List withStates) { - if (withStates.size() == 0) { - return true; - } - - int minLoops = loops.size(); - for (MemoryMap other : withStates) { - int otherLoops = other.loops.size(); - if (otherLoops < minLoops) { - minLoops = otherLoops; - } - } - while (loops.size() > minLoops) { - loops.pop(); - } - for (MemoryMap other : withStates) { - while (other.loops.size() > minLoops) { - other.loops.pop(); - } - } - - Set keys = new HashSet<>(); - for (Object key : lastMemorySnapshot.keySet()) { - keys.add(key); - } - for (MemoryMap other : withStates) { - assert other.loops.size() == loops.size(); - assert other.loops.size() < 1 || other.loops.peek().loopBegin == loops.peek().loopBegin; - for (Object key : other.lastMemorySnapshot.keySet()) { - keys.add(key); - } - } - IdentityHashMap newMemorySnapshot = (IdentityHashMap) lastMemorySnapshot.clone(); - - for (Object key : keys) { - ValueNode merged = lastMemorySnapshot.get(key); - if (merged == null) { - merged = lastMemorySnapshot.get(LocationNode.ANY_LOCATION); - } - int mergedStatesCount = 1; - boolean isPhi = false; - for (MemoryMap other : withStates) { - ValueNode otherValue = other.lastMemorySnapshot.get(key); - if (otherValue == null) { - otherValue = other.lastMemorySnapshot.get(LocationNode.ANY_LOCATION); - } - if (isPhi) { - ((PhiNode) merged).addInput(otherValue); - } else if (merged != otherValue) { - PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge)); - for (int j = 0; j < mergedStatesCount; j++) { - phi.addInput(merged); - } - phi.addInput(otherValue); - merged = phi; - isPhi = true; - newMemorySnapshot.put(key, phi); - } - mergedStatesCount++; - } - } - - lastMemorySnapshot = newMemorySnapshot; - return true; - } - - @Override - public void loopBegin(LoopBeginNode loopBegin) { - LoopState loopState = new LoopState(loopBegin, this, lastMemorySnapshot.get(LocationNode.ANY_LOCATION)); - for (Map.Entry entry : lastMemorySnapshot.entrySet()) { - PhiNode phi = loopBegin.graph().add(new PhiNode(PhiType.Memory, loopBegin)); - phi.addInput(entry.getValue()); - entry.setValue(phi); - loopState.loopPhiLocations.put(phi, entry.getKey()); - } - loops.push(loopState); - } - - @Override - public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) { - loopEndStatesMap.put(loopBegin, loopEndStates); - tryFinishLoopPhis(this, loopBegin); - } - - @Override - public void afterSplit(BeginNode node) { - // nothing - } - - @Override - public MemoryMap clone() { - return new MemoryMap(this); + return "Map=" + lastMemorySnapshot.toString(); } } + private final Map> modifiedInLoops = new IdentityHashMap<>(); + @Override protected void run(StructuredGraph graph) { - loopEndStatesMap = new IdentityHashMap<>(); - new PostOrderNodeIterator(graph.start(), new MemoryMap()) { - - @Override - protected void node(FixedNode node) { - processNode(node, state); - } - }.apply(); - } - - private void processNode(FixedNode node, MemoryMap state) { - if (node instanceof ReadNode) { - processRead((ReadNode) node, state); - } else if (node instanceof WriteNode) { - processWrite((WriteNode) node, state); - } else if (node instanceof MemoryCheckpoint) { - processCheckpoint((MemoryCheckpoint) node, state); - } else if (node instanceof LoopExitNode) { - processLoopExit((LoopExitNode) node, state); - } - } - - private static void processCheckpoint(MemoryCheckpoint checkpoint, MemoryMap state) { - processAnyLocationWrite((ValueNode) checkpoint, state); - } - - private static void processWrite(WriteNode writeNode, MemoryMap state) { - if (writeNode.location().locationIdentity() == LocationNode.ANY_LOCATION) { - processAnyLocationWrite(writeNode, state); - } - state.lastMemorySnapshot.put(writeNode.location().locationIdentity(), writeNode); - } - - private static void processAnyLocationWrite(ValueNode modifiying, MemoryMap state) { - for (Map.Entry entry : state.lastMemorySnapshot.entrySet()) { - entry.setValue(modifiying); - } - state.lastMemorySnapshot.put(LocationNode.ANY_LOCATION, modifiying); - state.loops.clear(); + ReentrantNodeIterator.apply(new CollectMemoryCheckpointsClosure(), graph.start(), new HashSet<>(), null); + ReentrantNodeIterator.apply(new FloatingReadClosure(), graph.start(), new MemoryMap(graph.start()), null); } - private void processRead(ReadNode readNode, MemoryMap state) { - StructuredGraph graph = (StructuredGraph) readNode.graph(); - assert readNode.getNullCheck() == false; - Object locationIdentity = readNode.location().locationIdentity(); - ValueNode lastLocationAccess = getLastLocationAccessForRead(state, locationIdentity); - FloatingReadNode floatingRead = graph.unique(new FloatingReadNode(readNode.object(), readNode.location(), lastLocationAccess, readNode.stamp(), readNode.dependencies())); - floatingRead.setNullCheck(readNode.getNullCheck()); - ValueAnchorNode anchor = null; - for (GuardNode guard : readNode.dependencies().filter(GuardNode.class)) { - if (anchor == null) { - anchor = graph.add(new ValueAnchorNode()); - } - anchor.addAnchoredNode(guard); - } - if (anchor != null) { - graph.addAfterFixed(readNode, anchor); - } - graph.replaceFixedWithFloating(readNode, floatingRead); - } + private class CollectMemoryCheckpointsClosure extends NodeIteratorClosure> { - private ValueNode getLastLocationAccessForRead(MemoryMap state, Object locationIdentity) { - ValueNode lastLocationAccess; - if (locationIdentity == LocationNode.FINAL_LOCATION) { - lastLocationAccess = null; - } else { - lastLocationAccess = state.lastMemorySnapshot.get(locationIdentity); - if (lastLocationAccess == null) { - LoopState lastLoop = state.loops.peek(); - if (lastLoop == null) { - lastLocationAccess = state.lastMemorySnapshot.get(LocationNode.ANY_LOCATION); - } else { - ValueNode phiInit; - if (state.loops.size() > 1) { - phiInit = getLastLocationAccessForRead(state.loops.get(1).state, locationIdentity); - } else { - phiInit = lastLoop.loopEntryAnyLocation; - } - PhiNode phi = lastLoop.loopBegin.graph().add(new PhiNode(PhiType.Memory, lastLoop.loopBegin)); - phi.addInput(phiInit); - lastLoop.state.lastMemorySnapshot.put(locationIdentity, phi); - lastLoop.loopPhiLocations.put(phi, locationIdentity); - tryFinishLoopPhis(lastLoop.state, lastLoop.loopBegin); - lastLocationAccess = phi; - } - state.lastMemorySnapshot.put(locationIdentity, lastLocationAccess); - } - } - return lastLocationAccess; - } - - private static void processLoopExit(LoopExitNode exit, MemoryMap state) { - for (Map.Entry entry : state.lastMemorySnapshot.entrySet()) { - entry.setValue(exit.graph().unique(new ValueProxyNode(entry.getValue(), exit, PhiType.Memory))); - } - if (!state.loops.isEmpty()) { - state.loops.pop(); - } - } - - private void tryFinishLoopPhis(MemoryMap loopMemory, LoopBeginNode loopBegin) { - List loopEndStates = loopEndStatesMap.get(loopBegin); - if (loopEndStates == null) { - return; - } - LoopState loopState = loopMemory.loops.get(0); - int i = 0; - while (loopState.loopBegin != loopBegin) { - loopState = loopMemory.loops.get(++i); - } - for (PhiNode phi : loopBegin.phis()) { - if (phi.type() == PhiType.Memory && phi.valueCount() == 1) { - Object location = loopState.loopPhiLocations.get(phi); - assert location != null : "unknown location for " + phi; - for (MemoryMap endState : loopEndStates) { - ValueNode otherNode = endState.lastMemorySnapshot.get(location); - if (otherNode == null) { - otherNode = endState.lastMemorySnapshot.get(LocationNode.ANY_LOCATION); - } - phi.addInput(otherNode); + @Override + protected void processNode(FixedNode node, Set currentState) { + if (node instanceof MemoryCheckpoint) { + for (Object identity : ((MemoryCheckpoint) node).getLocationIdentities()) { + currentState.add(identity); } } } + + @Override + protected Set merge(MergeNode merge, List> states) { + Set result = new HashSet<>(); + for (Set other : states) { + result.addAll(other); + } + return result; + } + + @Override + protected Set afterSplit(BeginNode node, Set oldState) { + return new HashSet<>(oldState); + } + + @Override + protected Map> processLoop(LoopBeginNode loop, Set initialState) { + LoopInfo> loopInfo = ReentrantNodeIterator.processLoop(this, loop, new HashSet<>()); + Set modifiedLocations = new HashSet<>(); + for (Set end : loopInfo.endStates.values()) { + modifiedLocations.addAll(end); + } + for (Set exit : loopInfo.exitStates.values()) { + exit.addAll(modifiedLocations); + exit.addAll(initialState); + } + assert !modifiedLocations.contains(LocationNode.FINAL_LOCATION); + modifiedInLoops.put(loop, modifiedLocations); + return loopInfo.exitStates; + } + + } + + private class FloatingReadClosure extends NodeIteratorClosure { + + @Override + protected void processNode(FixedNode node, MemoryMap state) { + if (node instanceof ReadNode) { + processRead((ReadNode) node, state); + } else if (node instanceof MemoryCheckpoint) { + processCheckpoint((MemoryCheckpoint) node, state); + } + } + + private void processCheckpoint(MemoryCheckpoint checkpoint, MemoryMap state) { + for (Object identity : checkpoint.getLocationIdentities()) { + if (identity == LocationNode.ANY_LOCATION) { + state.lastMemorySnapshot.clear(); + } + state.lastMemorySnapshot.put(identity, (ValueNode) checkpoint); + } + } + + private void processRead(ReadNode readNode, MemoryMap state) { + StructuredGraph graph = (StructuredGraph) readNode.graph(); + assert readNode.getNullCheck() == false; + Object locationIdentity = readNode.location().locationIdentity(); + if (locationIdentity != LocationNode.UNKNOWN_LOCATION) { + ValueNode lastLocationAccess = state.getLastLocationAccess(locationIdentity); + FloatingReadNode floatingRead = graph.unique(new FloatingReadNode(readNode.object(), readNode.location(), lastLocationAccess, readNode.stamp(), readNode.dependencies())); + floatingRead.setNullCheck(readNode.getNullCheck()); + ValueAnchorNode anchor = null; + for (GuardNode guard : readNode.dependencies().filter(GuardNode.class)) { + if (anchor == null) { + anchor = graph.add(new ValueAnchorNode()); + graph.addAfterFixed(readNode, anchor); + } + anchor.addAnchoredNode(guard); + } + graph.replaceFixedWithFloating(readNode, floatingRead); + } + } + + @Override + protected MemoryMap merge(MergeNode merge, List states) { + MemoryMap newState = new MemoryMap(); + + Set keys = new HashSet<>(); + for (MemoryMap other : states) { + keys.addAll(other.lastMemorySnapshot.keySet()); + } + assert !keys.contains(LocationNode.FINAL_LOCATION); + + for (Object key : keys) { + int mergedStatesCount = 0; + boolean isPhi = false; + ValueNode merged = null; + for (MemoryMap state : states) { + ValueNode last = state.getLastLocationAccess(key); + if (isPhi) { + ((PhiNode) merged).addInput(last); + } else { + if (merged == last) { + // nothing to do + } else if (merged == null) { + merged = last; + } else { + PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge)); + for (int j = 0; j < mergedStatesCount; j++) { + phi.addInput(merged); + } + phi.addInput(last); + merged = phi; + isPhi = true; + } + } + mergedStatesCount++; + } + newState.lastMemorySnapshot.put(key, merged); + } + return newState; + } + + @Override + protected MemoryMap afterSplit(BeginNode node, MemoryMap oldState) { + MemoryMap result = new MemoryMap(oldState); + if (node.predecessor() instanceof InvokeWithExceptionNode) { + /* + * InvokeWithException cannot be the lastLocationAccess for a FloatingReadNode. + * Since it is both the invoke and a control flow split, the scheduler cannot + * schedule anything immediately the invoke. It can only schedule in the normal or + * exceptional successor - and we have to tell the scheduler here which side it + * needs to choose by putting in the location identity on both successors. + */ + InvokeWithExceptionNode checkpoint = (InvokeWithExceptionNode) node.predecessor(); + for (Object identity : checkpoint.getLocationIdentities()) { + result.lastMemorySnapshot.put(identity, node); + } + } + return result; + } + + @Override + protected Map processLoop(LoopBeginNode loop, MemoryMap initialState) { + Set modifiedLocations = modifiedInLoops.get(loop); + if (modifiedLocations.contains(LocationNode.ANY_LOCATION)) { + // create phis for all locations if ANY is modified in the loop + modifiedLocations = new HashSet<>(modifiedLocations); + modifiedLocations.addAll(initialState.lastMemorySnapshot.keySet()); + } + + Map phis = new HashMap<>(); + for (Object location : modifiedLocations) { + PhiNode phi = loop.graph().add(new PhiNode(PhiType.Memory, loop)); + phi.addInput(initialState.getLastLocationAccess(location)); + phis.put(location, phi); + initialState.lastMemorySnapshot.put(location, phi); + } + + LoopInfo loopInfo = ReentrantNodeIterator.processLoop(this, loop, initialState); + + for (Map.Entry entry : loopInfo.endStates.entrySet()) { + int endIndex = loop.phiPredecessorIndex(entry.getKey()); + for (Map.Entry phiEntry : phis.entrySet()) { + Object key = phiEntry.getKey(); + PhiNode phi = phiEntry.getValue(); + phi.initializeValueAt(endIndex, entry.getValue().getLastLocationAccess(key)); + } + } + for (Map.Entry entry : loopInfo.exitStates.entrySet()) { + LoopExitNode exit = entry.getKey(); + MemoryMap state = entry.getValue(); + for (Object location : modifiedLocations) { + ValueNode lastAccessAtExit = state.lastMemorySnapshot.get(location); + if (lastAccessAtExit != null) { + state.lastMemorySnapshot.put(location, loop.graph().add(new ProxyNode(lastAccessAtExit, exit, PhiType.Memory))); + } + } + } + return loopInfo.exitStates; + } } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,223 @@ +/* + * 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 java.util.Map.Entry; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.schedule.*; + +public class GuardLoweringPhase extends Phase { + + private abstract static class ScheduledNodeIterator { + + private FixedWithNextNode lastFixed; + private FixedWithNextNode reconnect; + private ListIterator iterator; + + public void processNodes(List nodes, FixedWithNextNode begin) { + assert begin != null; + lastFixed = begin; + reconnect = null; + iterator = nodes.listIterator(); + while (iterator.hasNext()) { + Node node = iterator.next(); + if (!node.isAlive()) { + continue; + } + if (reconnect != null && node instanceof FixedNode) { + reconnect.setNext((FixedNode) node); + reconnect = null; + } + if (node instanceof FixedWithNextNode) { + lastFixed = (FixedWithNextNode) node; + } + processNode(node); + } + } + + protected void insert(FixedNode start, FixedWithNextNode end) { + this.lastFixed.setNext(start); + this.lastFixed = end; + this.reconnect = end; + } + + protected void replaceCurrent(FixedWithNextNode newNode) { + Node current = iterator.previous(); + iterator.next(); // needed because of the previous() call + current.replaceAndDelete(newNode); + insert(newNode, newNode); + iterator.set(newNode); + } + + protected abstract void processNode(Node node); + } + + private class UseImplicitNullChecks extends ScheduledNodeIterator { + + private final IdentityHashMap nullGuarded = new IdentityHashMap<>(); + + @Override + protected void processNode(Node node) { + if (node instanceof GuardNode) { + processGuard(node); + } else if (node instanceof Access) { + processAccess((Access) node); + } + if (node instanceof StateSplit && ((StateSplit) node).stateAfter() != null) { + nullGuarded.clear(); + } else { + Iterator> it = nullGuarded.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + GuardNode guard = entry.getValue(); + if (guard.usages().contains(node)) { + it.remove(); + } + } + } + } + + private void processAccess(Access access) { + GuardNode guard = nullGuarded.get(access.object()); + if (guard != null && isImplicitNullCheck(access.nullCheckLocation())) { + NodeInputList dependencies = ((ValueNode) access).dependencies(); + dependencies.remove(guard); + Access fixedAccess = access; + if (access instanceof FloatingAccessNode) { + fixedAccess = ((FloatingAccessNode) access).asFixedNode(); + replaceCurrent((FixedWithNextNode) fixedAccess.node()); + } + assert fixedAccess instanceof FixedNode; + fixedAccess.setNullCheck(true); + LogicNode condition = guard.condition(); + guard.replaceAndDelete(fixedAccess.node()); + if (condition.usages().isEmpty()) { + GraphUtil.killWithUnusedFloatingInputs(condition); + } + nullGuarded.remove(fixedAccess.object()); + } + } + + private void processGuard(Node node) { + GuardNode guard = (GuardNode) node; + if (guard.negated() && guard.condition() instanceof IsNullNode) { + ValueNode obj = ((IsNullNode) guard.condition()).object(); + nullGuarded.put(obj, guard); + } + } + } + + private class LowerGuards extends ScheduledNodeIterator { + + private final Block block; + + public LowerGuards(Block block) { + this.block = block; + } + + @Override + protected void processNode(Node node) { + if (node instanceof GuardNode) { + GuardNode guard = (GuardNode) node; + if (guard.negated() && guard.condition() instanceof IsNullNode) { + lowerToNullCheck(guard); + } else { + lowerToIf(guard); + } + } + } + + private void lowerToIf(GuardNode guard) { + StructuredGraph graph = (StructuredGraph) guard.graph(); + BeginNode fastPath = graph.add(new BeginNode()); + DeoptimizeNode deopt = graph.add(new DeoptimizeNode(guard.action(), guard.reason())); + BeginNode deoptBranch = BeginNode.begin(deopt); + BeginNode trueSuccessor; + BeginNode falseSuccessor; + insertLoopExits(deopt); + if (guard.negated()) { + trueSuccessor = deoptBranch; + falseSuccessor = fastPath; + } else { + trueSuccessor = fastPath; + falseSuccessor = deoptBranch; + } + IfNode ifNode = graph.add(new IfNode(guard.condition(), trueSuccessor, falseSuccessor, trueSuccessor == fastPath ? 1 : 0)); + guard.replaceAndDelete(fastPath); + insert(ifNode, fastPath); + } + + private void lowerToNullCheck(GuardNode guard) { + IsNullNode isNull = (IsNullNode) guard.condition(); + NullCheckNode nullCheck = guard.graph().add(new NullCheckNode(isNull.object())); + replaceCurrent(nullCheck); + } + + private void insertLoopExits(DeoptimizeNode deopt) { + Loop loop = block.getLoop(); + StructuredGraph graph = (StructuredGraph) deopt.graph(); + while (loop != null) { + LoopExitNode exit = graph.add(new LoopExitNode(loop.loopBegin())); + graph.addBeforeFixed(deopt, exit); + loop = loop.parent; + } + } + } + + private TargetDescription target; + + public GuardLoweringPhase(TargetDescription target) { + this.target = target; + } + + @Override + protected void run(StructuredGraph graph) { + SchedulePhase schedule = new SchedulePhase(); + schedule.apply(graph); + + for (Block block : schedule.getCFG().getBlocks()) { + processBlock(block, schedule); + } + } + + private void processBlock(Block block, SchedulePhase schedule) { + List nodes = schedule.nodesFor(block); + if (GraalOptions.OptImplicitNullChecks && target.implicitNullCheckLimit > 0) { + new UseImplicitNullChecks().processNodes(nodes, block.getBeginNode()); + } + new LowerGuards(block).processNodes(nodes, block.getBeginNode()); + } + + private boolean isImplicitNullCheck(LocationNode location) { + return !(location instanceof IndexedLocationNode) && location.displacement() < target.implicitNullCheckLimit; + } +} diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,6 +24,7 @@ import java.lang.reflect.*; import java.util.*; +import java.util.concurrent.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; @@ -47,7 +48,6 @@ * invoke.bci, method, true); */ - private final TargetDescription target; private final PhasePlan plan; private final GraalCodeCacheProvider runtime; @@ -63,18 +63,15 @@ private static final DebugMetric metricInliningStoppedByMaxDesiredSize = Debug.metric("InliningStoppedByMaxDesiredSize"); private static final DebugMetric metricInliningRuns = Debug.metric("Runs"); - public InliningPhase(TargetDescription target, GraalCodeCacheProvider runtime, Collection hints, Assumptions assumptions, GraphCache cache, PhasePlan plan, - OptimisticOptimizations optimisticOpts) { - this(target, runtime, assumptions, cache, plan, createInliningPolicy(runtime, assumptions, optimisticOpts, hints), optimisticOpts); + public InliningPhase(GraalCodeCacheProvider runtime, Collection hints, Assumptions assumptions, GraphCache cache, PhasePlan plan, OptimisticOptimizations optimisticOpts) { + this(runtime, assumptions, cache, plan, createInliningPolicy(runtime, assumptions, optimisticOpts, hints), optimisticOpts); } public void setCustomCanonicalizer(CustomCanonicalizer customCanonicalizer) { this.customCanonicalizer = customCanonicalizer; } - public InliningPhase(TargetDescription target, GraalCodeCacheProvider runtime, Assumptions assumptions, GraphCache cache, PhasePlan plan, InliningPolicy inliningPolicy, - OptimisticOptimizations optimisticOpts) { - this.target = target; + public InliningPhase(GraalCodeCacheProvider runtime, Assumptions assumptions, GraphCache cache, PhasePlan plan, InliningPolicy inliningPolicy, OptimisticOptimizations optimisticOpts) { this.runtime = runtime; this.assumptions = assumptions; this.cache = cache; @@ -103,7 +100,7 @@ Iterable newNodes = graph.getNewNodes(mark); inliningPolicy.scanInvokes(newNodes); if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions, invokeUsages, mark, customCanonicalizer).apply(graph); + new CanonicalizerPhase(runtime, assumptions, invokeUsages, mark, customCanonicalizer).apply(graph); } metricInliningPerformed.increment(); } catch (BailoutException bailout) { @@ -131,26 +128,32 @@ return cachedGraph; } } - StructuredGraph newGraph = new StructuredGraph(method); - if (plan != null) { - plan.runPhases(PhasePosition.AFTER_PARSING, newGraph); - } - assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING"; + final StructuredGraph newGraph = new StructuredGraph(method); + return Debug.scope("InlineGraph", newGraph, new Callable() { + + @Override + public StructuredGraph call() throws Exception { + if (plan != null) { + plan.runPhases(PhasePosition.AFTER_PARSING, newGraph); + } + assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING"; - if (GraalOptions.ProbabilityAnalysis) { - new DeadCodeEliminationPhase().apply(newGraph); - new ComputeProbabilityPhase().apply(newGraph); - } - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions).apply(newGraph); - } - if (GraalOptions.CullFrameStates) { - new CullFrameStatesPhase().apply(newGraph); - } - if (GraalOptions.CacheGraphs && cache != null) { - cache.put(newGraph); - } - return newGraph; + if (GraalOptions.ProbabilityAnalysis) { + new DeadCodeEliminationPhase().apply(newGraph); + new ComputeProbabilityPhase().apply(newGraph); + } + if (GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase(runtime, assumptions).apply(newGraph); + } + if (GraalOptions.CullFrameStates) { + new CullFrameStatesPhase().apply(newGraph); + } + if (GraalOptions.CacheGraphs && cache != null) { + cache.put(newGraph); + } + return newGraph; + } + }); } private interface InliningDecision { @@ -440,11 +443,7 @@ queueSuccessors(current); } else if (current instanceof EndNode) { queueMerge((EndNode) current); - } else if (current instanceof DeoptimizeNode) { - // nothing todo - } else if (current instanceof ReturnNode) { - // nothing todo - } else if (current instanceof UnwindNode) { + } else if (current instanceof ControlSinkNode) { // nothing todo } else if (current instanceof ControlSplitNode) { queueSuccessors(current); diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Thu Mar 21 14:11:13 2013 +0100 @@ -696,7 +696,8 @@ ResolvedJavaMethod targetMethod = methodCallTarget.targetMethod(); ResolvedJavaType leastCommonType = getLeastCommonType(); // check if we have a common base type that implements the interface -> in that case -// we have a vtable entry for the interface method and can use a less expensive virtual call + // we have a vtable entry for the interface method and can use a less expensive + // virtual call if (!leastCommonType.isInterface() && targetMethod.getDeclaringClass().isAssignableFrom(leastCommonType)) { ResolvedJavaMethod baseClassTargetMethod = leastCommonType.resolveMethod(targetMethod); if (baseClassTargetMethod != null) { @@ -966,8 +967,6 @@ return logNotInlinedMethodAndReturnFalse(invoke, method, "the method's class is not initialized"); } else if (!method.canBeInlined()) { return logNotInlinedMethodAndReturnFalse(invoke, method, "it is marked non-inlinable"); - } else if (computeInliningLevel(invoke) > GraalOptions.MaximumInlineLevel) { - return logNotInlinedMethodAndReturnFalse(invoke, method, "it exceeds the maximum inlining depth"); } else if (computeRecursiveInliningLevel(invoke.stateAfter(), method) > GraalOptions.MaximumRecursiveInlining) { return logNotInlinedMethodAndReturnFalse(invoke, method, "it exceeds the maximum recursive inlining depth"); } else if (new OptimisticOptimizations(method).lessOptimisticThan(optimisticOpts)) { @@ -1001,6 +1000,17 @@ return count; } + static MonitorExitNode findPrecedingMonitorExit(UnwindNode unwind) { + Node pred = unwind.predecessor(); + while (pred != null) { + if (pred instanceof MonitorExitNode) { + return (MonitorExitNode) pred; + } + pred = pred.predecessor(); + } + return null; + } + /** * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph. * @@ -1071,13 +1081,13 @@ } else { if (unwindNode != null) { UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode); + MonitorExitNode monitorExit = findPrecedingMonitorExit(unwindDuplicate); DeoptimizeNode deoptimizeNode = new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler); unwindDuplicate.replaceAndDelete(graph.add(deoptimizeNode)); // move the deopt upwards if there is a monitor exit that tries to use the // "after exception" frame state // (because there is no "after exception" frame state!) - if (deoptimizeNode.predecessor() instanceof MonitorExitNode) { - MonitorExitNode monitorExit = (MonitorExitNode) deoptimizeNode.predecessor(); + if (monitorExit != null) { if (monitorExit.stateAfter() != null && monitorExit.stateAfter().bci == FrameState.AFTER_EXCEPTION_BCI) { FrameState monitorFrameState = monitorExit.stateAfter(); graph.removeFixed(monitorExit); @@ -1123,7 +1133,7 @@ } else { // only handle the outermost frame states if (frameState.outerFrameState() == null) { - assert frameState.method() == inlineGraph.method(); + 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.setDuringCall(true); diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -33,12 +33,10 @@ public class IterativeConditionalEliminationPhase extends Phase { - private final TargetDescription target; private final MetaAccessProvider runtime; private final Assumptions assumptions; - public IterativeConditionalEliminationPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions) { - this.target = target; + public IterativeConditionalEliminationPhase(MetaAccessProvider runtime, Assumptions assumptions) { this.runtime = runtime; this.assumptions = assumptions; } @@ -55,7 +53,7 @@ if (canonicalizationRoots.isEmpty()) { break; } - new CanonicalizerPhase(target, runtime, assumptions, canonicalizationRoots, null).apply(graph); + new CanonicalizerPhase(runtime, assumptions, canonicalizationRoots, null).apply(graph); canonicalizationRoots.clear(); } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoopSafepointInsertionPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoopSafepointInsertionPhase.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +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.graph.iterators.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.util.*; -import com.oracle.graal.phases.*; - -/** - * Adds safepoints to loops. - */ -public class LoopSafepointInsertionPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - nextLoop: for (LoopEndNode loopEnd : graph.getNodes(LoopEndNode.class)) { - if (!loopEnd.canSafepoint()) { - continue; - } - if (GraalOptions.OptSafepointElimination) { - // We 'eliminate' safepoints by simply never placing them into loops that have at - // least one call - NodeIterable it = NodeIterators.dominators(loopEnd).until(loopEnd.loopBegin()); - for (FixedNode n : it) { - if (n instanceof Invoke) { - continue nextLoop; - } - } - } - SafepointNode safepoint = graph.add(new SafepointNode()); - graph.addBeforeFixed(loopEnd, safepoint); - } - } -} diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -83,8 +83,8 @@ public ValueNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) { if (GraalOptions.OptEliminateGuards) { for (Node usage : condition.usages()) { - if (!activeGuards.isNew(usage) && activeGuards.isMarked(usage)) { - return (ValueNode) usage; + if (!activeGuards.isNew(usage) && activeGuards.isMarked(usage) && ((GuardNode) usage).negated() == negated) { + return (GuardNode) usage; } } } @@ -104,6 +104,11 @@ public FixedWithNextNode lastFixedNode() { return lastFixedNode; } + + public void setLastFixedNode(FixedWithNextNode n) { + assert n == null || n.isAlive() : n; + lastFixedNode = n; + } } private final TargetDescription target; @@ -139,7 +144,7 @@ deferred = false; processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null, schedule, processed); Debug.dump(graph, "Lowering iteration %d", i++); - new CanonicalizerPhase(null, runtime, assumptions, mark, null).apply(graph); + new CanonicalizerPhase(runtime, assumptions, mark, null).apply(graph); if (!deferred && !containsLowerable(graph.getNewNodes(mark))) { // No new lowerable nodes - done! @@ -187,15 +192,15 @@ List nodes = schedule.nodesFor(b); for (Node node : nodes) { - FixedNode lastFixedNext = null; - if (node instanceof FixedWithNextNode) { + FixedNode nextFixedNode = null; + if (node instanceof FixedWithNextNode && node.isAlive()) { FixedWithNextNode fixed = (FixedWithNextNode) node; - lastFixedNext = fixed.next(); - loweringTool.lastFixedNode = fixed; + nextFixedNode = fixed.next(); + loweringTool.setLastFixedNode(fixed); } if (node.isAlive() && !processed.isMarked(node) && node instanceof Lowerable) { - if (loweringTool.lastFixedNode == null) { + if (loweringTool.lastFixedNode() == null) { // We cannot lower the node now because we don't have a fixed node to anchor the // replacements. // This can happen when previous lowerings in this lowering iteration deleted @@ -209,17 +214,17 @@ } } - if (loweringTool.lastFixedNode == node && !node.isAlive()) { - if (lastFixedNext == null) { - loweringTool.lastFixedNode = null; + if (loweringTool.lastFixedNode() == node && !node.isAlive()) { + if (nextFixedNode == null || !nextFixedNode.isAlive()) { + loweringTool.setLastFixedNode(null); } else { - Node prev = lastFixedNext.predecessor(); + Node prev = nextFixedNode.predecessor(); if (prev != node && prev instanceof FixedWithNextNode) { - loweringTool.lastFixedNode = (FixedWithNextNode) prev; - } else if (lastFixedNext instanceof FixedWithNextNode) { - loweringTool.lastFixedNode = (FixedWithNextNode) lastFixedNext; + loweringTool.setLastFixedNode((FixedWithNextNode) prev); + } else if (nextFixedNode instanceof FixedWithNextNode) { + loweringTool.setLastFixedNode((FixedWithNextNode) nextFixedNode); } else { - loweringTool.lastFixedNode = null; + loweringTool.setLastFixedNode(null); } } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -59,8 +59,8 @@ if (visited.isMarked(lastLocationAccess)) { return true; // dataflow loops must come from Phis assume them ok until proven wrong } - if (lastLocationAccess instanceof ValueProxyNode) { - return isWrites(n, ((ValueProxyNode) lastLocationAccess).value(), visited); + if (lastLocationAccess instanceof ProxyNode) { + return isWrites(n, ((ProxyNode) lastLocationAccess).value(), visited); } if (lastLocationAccess instanceof WriteNode) { WriteNode other = (WriteNode) lastLocationAccess; @@ -83,10 +83,10 @@ if (exisiting != null) { return exisiting; } - if (lastLocationAccess instanceof ValueProxyNode) { - ValueProxyNode proxy = (ValueProxyNode) lastLocationAccess; + if (lastLocationAccess instanceof ProxyNode) { + ProxyNode proxy = (ProxyNode) lastLocationAccess; ValueNode value = getValue(n, proxy.value(), nodeMap); - return lastLocationAccess.graph().add(new ValueProxyNode(value, proxy.proxyPoint(), PhiType.Value)); + return lastLocationAccess.graph().add(new ProxyNode(value, proxy.proxyPoint(), PhiType.Value)); } if (lastLocationAccess instanceof WriteNode) { return ((WriteNode) lastLocationAccess).value(); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/RemoveValueProxyPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/RemoveValueProxyPhase.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/RemoveValueProxyPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -23,14 +23,17 @@ package com.oracle.graal.phases.common; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.PhiNode.*; import com.oracle.graal.phases.*; public class RemoveValueProxyPhase extends Phase { @Override protected void run(StructuredGraph graph) { - for (ValueProxyNode vpn : graph.getNodes(ValueProxyNode.class)) { - graph.replaceFloating(vpn, vpn.value()); + for (ProxyNode vpn : graph.getNodes(ProxyNode.class)) { + if (vpn.type() == PhiType.Value) { + graph.replaceFloating(vpn, vpn.value()); + } } for (LoopExitNode exit : graph.getNodes(LoopExitNode.class)) { FrameState stateAfter = exit.stateAfter(); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/SafepointInsertionPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/SafepointInsertionPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,55 @@ +/* + * 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.common; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; + +/** + * Adds safepoints to loops and return points. + */ +public class SafepointInsertionPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + if (GraalOptions.GenLoopSafepoints) { + for (LoopEndNode loopEndNode : graph.getNodes(LoopEndNode.class)) { + if (!loopEndNode.canSafepoint()) { + continue; + } + SafepointNode safepointNode = graph.add(new SafepointNode()); + graph.addBeforeFixed(loopEndNode, safepointNode); + } + } + + if (GraalOptions.GenSafepoints) { + if (!GraalOptions.OptEliminateSafepoints || graph.getNodes(MethodCallTargetNode.class).isNotEmpty()) { + for (ReturnNode returnNode : graph.getNodes(ReturnNode.class)) { + SafepointNode safepoint = graph.add(new SafepointNode()); + graph.addBeforeFixed(returnNode, safepoint); + } + } + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Thu Mar 21 14:11:13 2013 +0100 @@ -43,7 +43,6 @@ static boolean InlineMonomorphicCalls = true; static boolean InlinePolymorphicCalls = true; static boolean InlineMegamorphicCalls = ____; - public static int MaximumInlineLevel = 30; public static int MaximumDesiredSize = 5000; public static int MaximumRecursiveInlining = 1; public static boolean LimitInlinedProbability = ____; @@ -106,11 +105,9 @@ public static int LoopUnswitchUncertaintyBoost = 5; // debugging settings - public static int MethodEndBreakpointGuards = 2; public static boolean ZapStackOnMethodEntry = ____; public static boolean DeoptALot = ____; public static boolean VerifyPhases = true; - public static boolean CreateDeoptInfo = ____; public static String PrintFilter = null; @@ -150,13 +147,16 @@ public static boolean ExitVMOnBailout = ____; public static boolean ExitVMOnException = true; + // Register allocator debugging + public static String RegisterPressure = null; + // Code generator settings - public static boolean CheckCastElimination = true; + public static boolean ConditionalElimination = true; public static boolean CullFrameStates = ____; public static boolean UseProfilingInformation = true; static boolean RemoveNeverExecutedCode = true; static boolean UseExceptionProbability = true; - public static boolean AllowExplicitExceptionChecks = true; + static boolean UseExceptionProbabilityForOperations = true; public static boolean OmitHotExceptionStacktrace = ____; public static boolean GenSafepoints = true; public static boolean GenLoopSafepoints = true; @@ -169,6 +169,8 @@ public static boolean CanOmitFrame = true; public static int SafepointPollOffset = 256; + public static boolean MemoryAwareScheduling = true; + // Translating tableswitch instructions public static int MinimumJumpTableSize = 5; public static int RangeTestsSwitchDensity = 5; @@ -182,14 +184,15 @@ public static boolean SupportJsrBytecodes = true; public static boolean OptAssumptions = true; + public static boolean OptConvertDeoptsToGuards = true; public static boolean OptReadElimination = true; public static boolean OptCanonicalizer = true; public static boolean OptScheduleOutOfLoops = true; public static boolean OptEliminateGuards = true; + public static boolean OptEliminateSafepoints = true; public static boolean OptImplicitNullChecks = true; public static boolean OptLivenessAnalysis = true; public static boolean OptLoopTransform = true; - public static boolean OptSafepointElimination = true; public static boolean OptFloatingReads = true; public static boolean OptTailDuplication = true; public static boolean OptEliminatePartiallyRedundantGuards = true; diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java Thu Mar 21 14:11:13 2013 +0100 @@ -33,8 +33,8 @@ public static final OptimisticOptimizations NONE = new OptimisticOptimizations(EnumSet.noneOf(Optimization.class)); private static final DebugMetric disabledOptimisticOptsMetric = Debug.metric("DisabledOptimisticOpts"); - private static enum Optimization { - RemoveNeverExecutedCode, UseTypeCheckedInlining, UseTypeCheckHints, UseExceptionProbability + public static enum Optimization { + RemoveNeverExecutedCode, UseTypeCheckedInlining, UseTypeCheckHints, UseExceptionProbabilityForOperations, UseExceptionProbability } private final Set enabledOpts; @@ -42,6 +42,7 @@ public OptimisticOptimizations(ResolvedJavaMethod method) { this.enabledOpts = EnumSet.noneOf(Optimization.class); + enabledOpts.add(Optimization.UseExceptionProbabilityForOperations); addOptimization(method, DeoptimizationReason.UnreachedCode, Optimization.RemoveNeverExecutedCode); addOptimization(method, DeoptimizationReason.TypeCheckedInliningViolated, Optimization.UseTypeCheckedInlining); addOptimization(method, DeoptimizationReason.OptimizedTypeCheckViolated, Optimization.UseTypeCheckHints); @@ -56,11 +57,26 @@ * TODO (chaeubl): see GRAAL-75 (remove when we are sure that optimistic optimizations * are not disabled unnecessarily */ - TTY.println("WARN: deactivated optimistic optimization %s for %s", optimization.name(), MetaUtil.format("%H.%n(%p)", method)); disabledOptimisticOptsMetric.increment(); } } + public OptimisticOptimizations remove(Optimization... optimizations) { + Set newOptimizations = EnumSet.copyOf(enabledOpts); + for (Optimization o : optimizations) { + newOptimizations.remove(o); + } + return new OptimisticOptimizations(newOptimizations); + } + + public OptimisticOptimizations add(Optimization... optimizations) { + Set newOptimizations = EnumSet.copyOf(enabledOpts); + for (Optimization o : optimizations) { + newOptimizations.add(o); + } + return new OptimisticOptimizations(newOptimizations); + } + private OptimisticOptimizations(Set enabledOpts) { this.enabledOpts = enabledOpts; } @@ -93,6 +109,10 @@ return GraalOptions.UseExceptionProbability && enabledOpts.contains(Optimization.UseExceptionProbability); } + public boolean useExceptionProbabilityForOperations() { + return GraalOptions.UseExceptionProbabilityForOperations && enabledOpts.contains(Optimization.UseExceptionProbabilityForOperations); + } + public boolean lessOptimisticThan(OptimisticOptimizations other) { for (Optimization opt : Optimization.values()) { if (!enabledOpts.contains(opt) && other.enabledOpts.contains(opt)) { diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java Thu Mar 21 14:11:13 2013 +0100 @@ -89,14 +89,8 @@ end((EndNode) current); queueMerge((EndNode) current); current = nextQueuedNode(); - } else if (current instanceof DeoptimizeNode) { - deoptimize((DeoptimizeNode) current); - current = nextQueuedNode(); - } else if (current instanceof ReturnNode) { - returnNode((ReturnNode) current); - current = nextQueuedNode(); - } else if (current instanceof UnwindNode) { - unwind((UnwindNode) current); + } else if (current instanceof ControlSinkNode) { + node(current); current = nextQueuedNode(); } else if (current instanceof ControlSplitNode) { Set successors = controlSplit((ControlSplitNode) current); @@ -106,6 +100,7 @@ assert false : current; } } while (current != null); + finished(); } private void queueSuccessors(FixedNode x, Set successors) { @@ -216,24 +211,16 @@ node(loopEnd); } - protected void deoptimize(DeoptimizeNode deoptimize) { - node(deoptimize); - } - protected Set controlSplit(ControlSplitNode controlSplit) { node(controlSplit); return null; } - protected void returnNode(ReturnNode returnNode) { - node(returnNode); - } - protected void invoke(Invoke invoke) { node(invoke.node()); } - protected void unwind(UnwindNode unwind) { - node(unwind); + protected void finished() { + // nothing to do } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java Thu Mar 21 14:11:13 2013 +0100 @@ -29,54 +29,49 @@ public final class ReentrantBlockIterator { - public abstract static class MergeableBlockState { + public static class LoopInfo { - public abstract T cloneState(); + public final List endStates = new ArrayList<>(); + public final List exitStates = new ArrayList<>(); } - public static class LoopInfo> { + public abstract static class BlockIteratorClosure { - public final List endStates = new ArrayList<>(); - public final List exitStates = new ArrayList<>(); - } - - public abstract static class BlockIteratorClosure> { + protected abstract void processBlock(Block block, StateT currentState); - protected abstract void processBlock(Block block, T currentState); - - protected abstract T merge(MergeNode merge, List states); + protected abstract StateT merge(MergeNode merge, List states); - protected abstract T afterSplit(FixedNode node, T oldState); + protected abstract StateT afterSplit(FixedNode node, StateT oldState); - protected abstract List processLoop(Loop loop, T initialState); + protected abstract List processLoop(Loop loop, StateT initialState); } private ReentrantBlockIterator() { // no instances allowed } - public static > LoopInfo processLoop(BlockIteratorClosure closure, Loop loop, T initialState) { - IdentityHashMap blockEndStates = apply(closure, loop.header, initialState, new HashSet<>(loop.blocks)); + public static LoopInfo processLoop(BlockIteratorClosure closure, Loop loop, StateT initialState) { + IdentityHashMap blockEndStates = apply(closure, loop.header, initialState, new HashSet<>(loop.blocks)); - LoopInfo info = new LoopInfo<>(); + LoopInfo info = new LoopInfo<>(); List predecessors = loop.header.getPredecessors(); for (int i = 1; i < predecessors.size(); i++) { info.endStates.add(blockEndStates.get(predecessors.get(i).getEndNode())); } for (Block loopExit : loop.exits) { assert loopExit.getPredecessorCount() == 1; - T exitState = blockEndStates.get(loopExit.getFirstPredecessor().getEndNode()); + StateT exitState = blockEndStates.get(loopExit.getFirstPredecessor().getEndNode()); assert exitState != null; info.exitStates.add(exitState); } return info; } - public static > IdentityHashMap apply(BlockIteratorClosure closure, Block start, T initialState, Set boundary) { + public static IdentityHashMap apply(BlockIteratorClosure closure, Block start, StateT initialState, Set boundary) { Deque blockQueue = new ArrayDeque<>(); - IdentityHashMap blockEndStates = new IdentityHashMap<>(); + IdentityHashMap blockEndStates = new IdentityHashMap<>(); - T state = initialState; + StateT state = initialState; Block current = start; do { @@ -98,7 +93,7 @@ LoopBeginNode loopBegin = loop.loopBegin(); assert successor.getBeginNode() == loopBegin; - List exitStates = closure.processLoop(loop, state); + List exitStates = closure.processLoop(loop, state); int i = 0; assert loop.exits.size() == exitStates.size(); @@ -123,8 +118,8 @@ blockEndStates.put(end, state); MergeNode merge = end.merge(); boolean endsVisited = true; - for (int i = 0; i < merge.forwardEndCount(); i++) { - if (!blockEndStates.containsKey(merge.forwardEndAt(i))) { + for (EndNode forwardEnd : merge.forwardEnds()) { + if (!blockEndStates.containsKey(forwardEnd)) { endsVisited = false; break; } @@ -157,9 +152,9 @@ current = blockQueue.removeFirst(); if (current.getPredecessors().size() > 1) { MergeNode merge = (MergeNode) current.getBeginNode(); - ArrayList states = new ArrayList<>(merge.forwardEndCount()); + ArrayList states = new ArrayList<>(merge.forwardEndCount()); for (int i = 0; i < merge.forwardEndCount(); i++) { - T other = blockEndStates.get(merge.forwardEndAt(i)); + StateT other = blockEndStates.get(merge.forwardEndAt(i)); assert other != null; states.add(other); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,158 @@ +/* + * 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.phases.graph; + +import java.util.*; + +import com.oracle.graal.graph.NodeClass.NodeClassIterator; +import com.oracle.graal.nodes.*; + +public final class ReentrantNodeIterator { + + public static class LoopInfo { + + public final Map endStates = new IdentityHashMap<>(4); + public final Map exitStates = new IdentityHashMap<>(2); + } + + public abstract static class NodeIteratorClosure { + + protected abstract void processNode(FixedNode node, StateT currentState); + + protected abstract StateT merge(MergeNode merge, List states); + + protected abstract StateT afterSplit(BeginNode node, StateT oldState); + + protected abstract Map processLoop(LoopBeginNode loop, StateT initialState); + } + + private ReentrantNodeIterator() { + // no instances allowed + } + + public static LoopInfo processLoop(NodeIteratorClosure closure, LoopBeginNode loop, StateT initialState) { + HashSet boundary = new HashSet<>(); + for (LoopExitNode exit : loop.loopExits()) { + boundary.add(exit); + } + Map blockEndStates = apply(closure, loop, initialState, boundary); + + LoopInfo info = new LoopInfo<>(); + for (LoopEndNode end : loop.loopEnds()) { + assert blockEndStates.containsKey(end) : "no end state for " + end; + info.endStates.put(end, blockEndStates.get(end)); + } + for (LoopExitNode exit : loop.loopExits()) { + assert blockEndStates.containsKey(exit) : "no exit state for " + exit; + info.exitStates.put(exit, blockEndStates.get(exit)); + } + return info; + } + + public static Map apply(NodeIteratorClosure closure, FixedNode start, StateT initialState, Set boundary) { + Deque nodeQueue = new ArrayDeque<>(); + IdentityHashMap blockEndStates = new IdentityHashMap<>(); + + StateT state = initialState; + FixedNode current = start; + do { + while (current instanceof FixedWithNextNode) { + if (boundary != null && boundary.contains(current)) { + blockEndStates.put(current, state); + current = null; + } else { + FixedNode next = ((FixedWithNextNode) current).next(); + closure.processNode(current, state); + current = next; + } + } + + if (current != null) { + closure.processNode(current, state); + + NodeClassIterator successors = current.successors().iterator(); + if (!successors.hasNext()) { + if (current instanceof LoopEndNode) { + blockEndStates.put(current, state); + } else if (current instanceof EndNode) { + // add the end node and see if the merge is ready for processing + MergeNode merge = ((EndNode) current).merge(); + if (merge instanceof LoopBeginNode) { + Map loopExitState = closure.processLoop((LoopBeginNode) merge, state); + for (Map.Entry entry : loopExitState.entrySet()) { + blockEndStates.put(entry.getKey(), entry.getValue()); + nodeQueue.add(entry.getKey()); + } + } else { + assert !blockEndStates.containsKey(current); + blockEndStates.put(current, state); + boolean endsVisited = true; + for (EndNode forwardEnd : merge.forwardEnds()) { + if (!blockEndStates.containsKey(forwardEnd)) { + endsVisited = false; + break; + } + } + if (endsVisited) { + ArrayList states = new ArrayList<>(merge.forwardEndCount()); + for (int i = 0; i < merge.forwardEndCount(); i++) { + EndNode forwardEnd = merge.forwardEndAt(i); + assert blockEndStates.containsKey(forwardEnd); + StateT other = blockEndStates.get(forwardEnd); + states.add(other); + } + state = closure.merge(merge, states); + current = merge; + continue; + } + } + } + } else { + FixedNode firstSuccessor = (FixedNode) successors.next(); + if (!successors.hasNext()) { + current = firstSuccessor; + continue; + } else { + while (successors.hasNext()) { + BeginNode successor = (BeginNode) successors.next(); + blockEndStates.put(successor, closure.afterSplit(successor, state)); + nodeQueue.add(successor); + } + state = closure.afterSplit((BeginNode) firstSuccessor, state); + current = firstSuccessor; + continue; + } + } + } + + // get next queued block + if (nodeQueue.isEmpty()) { + return blockEndStates; + } else { + current = nodeQueue.removeFirst(); + state = blockEndStates.get(current); + assert !(current instanceof MergeNode) && current instanceof BeginNode; + } + } while (true); + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScopedPostOrderNodeIterator.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScopedPostOrderNodeIterator.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScopedPostOrderNodeIterator.java Thu Mar 21 14:11:13 2013 +0100 @@ -73,11 +73,7 @@ queueSuccessors(current); } else if (current instanceof EndNode) { queueMerge((EndNode) current); - } else if (current instanceof DeoptimizeNode) { - // nothing todo - } else if (current instanceof ReturnNode) { - // nothing todo - } else if (current instanceof UnwindNode) { + } else if (current instanceof ControlSinkNode) { // nothing todo } else if (current instanceof ControlSplitNode) { queueSuccessors(current); diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -28,12 +28,103 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.Verbosity; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; +import com.oracle.graal.phases.graph.*; +import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure; +import com.oracle.graal.phases.graph.ReentrantBlockIterator.LoopInfo; -public class SchedulePhase extends Phase { +public final class SchedulePhase extends Phase { + + public static enum SchedulingStrategy { + EARLIEST, LATEST, LATEST_OUT_OF_LOOPS + } + + /** + * This closure iterates over all nodes of a scheduled graph (it expects a + * {@link SchedulingStrategy#EARLIEST} schedule) and keeps a list of "active" reads. Whenever it + * encounters a read, it adds it to the active reads. Whenever it encounters a memory + * checkpoint, it adds all reads that need to be committed before this checkpoint to the + * "phantom" usages and inputs, so that the read is scheduled before the checkpoint afterwards. + * + * At merges, the intersection of all sets of active reads is calculated. A read that was + * committed within one predecessor branch cannot be scheduled after the merge anyway. + * + * Similarly for loops, all reads that are killed somewhere within the loop are removed from the + * exits' active reads, since they cannot be scheduled after the exit anyway. + */ + private class MemoryScheduleClosure extends BlockIteratorClosure> { + + @Override + protected void processBlock(Block block, HashSet currentState) { + for (Node node : getBlockToNodesMap().get(block)) { + if (node instanceof FloatingReadNode) { + currentState.add((FloatingReadNode) node); + } else if (node instanceof MemoryCheckpoint) { + for (Object identity : ((MemoryCheckpoint) node).getLocationIdentities()) { + for (Iterator iter = currentState.iterator(); iter.hasNext();) { + FloatingReadNode read = iter.next(); + FixedNode fixed = (FixedNode) node; + if (identity == LocationNode.ANY_LOCATION || read.location().locationIdentity() == identity) { + addPhantomReference(read, fixed); + } + } + } + } + } + } + + public void addPhantomReference(FloatingReadNode read, FixedNode fixed) { + List usageList = phantomUsages.get(read); + if (usageList == null) { + phantomUsages.put(read, usageList = new ArrayList<>()); + } + usageList.add(fixed); + List inputList = phantomInputs.get(fixed); + if (inputList == null) { + phantomInputs.put(fixed, inputList = new ArrayList<>()); + } + inputList.add(read); + } + + @Override + protected HashSet merge(MergeNode merge, List> states) { + HashSet state = new HashSet<>(states.get(0)); + for (int i = 1; i < states.size(); i++) { + state.retainAll(states.get(i)); + } + return state; + } + + @Override + protected HashSet afterSplit(FixedNode node, HashSet oldState) { + return new HashSet<>(oldState); + } + + @Override + protected List> processLoop(Loop loop, HashSet state) { + LoopInfo> info = ReentrantBlockIterator.processLoop(this, loop, new HashSet<>(state)); + + List> loopEndStates = info.endStates; + + // collect all reads that were killed in some branch within the loop + Set killedReads = new HashSet<>(state); + Set survivingReads = new HashSet<>(loopEndStates.get(0)); + for (int i = 1; i < loopEndStates.size(); i++) { + survivingReads.retainAll(loopEndStates.get(i)); + } + killedReads.removeAll(survivingReads); + + // reads that were killed within the loop cannot be scheduled after the loop anyway + for (HashSet exitState : info.exitStates) { + exitState.removeAll(killedReads); + } + return info.exitStates; + } + } private ControlFlowGraph cfg; private NodeMap earliestCache; @@ -42,9 +133,16 @@ * Map from blocks to the nodes in each block. */ private BlockMap> blockToNodesMap; + private final Map> phantomUsages = new IdentityHashMap<>(); + private final Map> phantomInputs = new IdentityHashMap<>(); + private final SchedulingStrategy selectedStrategy; public SchedulePhase() { - super("Schedule"); + this(GraalOptions.OptScheduleOutOfLoops ? SchedulingStrategy.LATEST_OUT_OF_LOOPS : SchedulingStrategy.LATEST); + } + + public SchedulePhase(SchedulingStrategy strategy) { + this.selectedStrategy = strategy; } @Override @@ -53,8 +151,20 @@ earliestCache = graph.createNodeMap(); blockToNodesMap = new BlockMap<>(cfg); - assignBlockToNodes(graph); - sortNodesWithinBlocks(graph); + if (GraalOptions.MemoryAwareScheduling && selectedStrategy != SchedulingStrategy.EARLIEST && graph.getNodes(FloatingReadNode.class).isNotEmpty()) { + + assignBlockToNodes(graph, SchedulingStrategy.EARLIEST); + sortNodesWithinBlocks(graph, SchedulingStrategy.EARLIEST); + + MemoryScheduleClosure closure = new MemoryScheduleClosure(); + ReentrantBlockIterator.apply(closure, getCFG().getStartBlock(), new HashSet(), null); + + cfg.clearNodeToBlock(); + blockToNodesMap = new BlockMap<>(cfg); + } + + assignBlockToNodes(graph, selectedStrategy); + sortNodesWithinBlocks(graph, selectedStrategy); } /** @@ -94,7 +204,7 @@ return blockToNodesMap.get(block); } - private void assignBlockToNodes(StructuredGraph graph) { + private void assignBlockToNodes(StructuredGraph graph, SchedulingStrategy strategy) { for (Block block : cfg.getBlocks()) { List nodes = new ArrayList<>(); assert blockToNodesMap.get(block) == null; @@ -106,7 +216,7 @@ for (Node n : graph.getNodes()) { if (n instanceof ScheduledNode) { - assignBlockToNode((ScheduledNode) n); + assignBlockToNode((ScheduledNode) n, strategy); } } } @@ -115,7 +225,7 @@ * Assigns a block to the given node. This method expects that PhiNodes and FixedNodes are * already assigned to a block. */ - private void assignBlockToNode(ScheduledNode node) { + private void assignBlockToNode(ScheduledNode node, SchedulingStrategy strategy) { assert !node.isDeleted(); Block prevBlock = cfg.getNodeToBlock().get(node); @@ -126,17 +236,27 @@ // ControlFlowGraph.identifyBlocks assert !(node instanceof PhiNode) : node; assert !(node instanceof FixedNode) : node; - // if in CFG, schedule at the latest position possible in the outermost loop possible - Block latestBlock = latestBlock(node); + Block block; - if (latestBlock == null) { - block = earliestBlock(node); - } else if (GraalOptions.OptScheduleOutOfLoops && !(node instanceof VirtualObjectNode)) { - Block earliestBlock = earliestBlock(node); - block = scheduleOutOfLoops(node, latestBlock, earliestBlock); - assert earliestBlock.dominates(block) : "Graph can not be scheduled : inconsistent for " + node + " (" + earliestBlock + " needs to dominate " + block + ")"; - } else { - block = latestBlock; + switch (strategy) { + case EARLIEST: + block = earliestBlock(node); + break; + case LATEST: + case LATEST_OUT_OF_LOOPS: + block = latestBlock(node, strategy); + if (block == null) { + block = earliestBlock(node); + } else if (strategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS && !(node instanceof VirtualObjectNode)) { + // 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 + ")"; + } + break; + default: + throw new GraalInternalError("unknown scheduling strategy"); } cfg.getNodeToBlock().set(node, block); blockToNodesMap.get(block).add(node); @@ -145,17 +265,27 @@ /** * Calculates the last block that the given node could be scheduled in, i.e., the common * dominator of all usages. To do so all usages are also assigned to blocks. + * + * @param strategy */ - private Block latestBlock(ScheduledNode node) { + private Block latestBlock(ScheduledNode node, SchedulingStrategy strategy) { CommonDominatorBlockClosure cdbc = new CommonDominatorBlockClosure(null); for (Node succ : node.successors().nonNull()) { assert cfg.getNodeToBlock().get(succ) != null; cdbc.apply(cfg.getNodeToBlock().get(succ)); } - ensureScheduledUsages(node); + ensureScheduledUsages(node, strategy); for (Node usage : node.usages()) { - blocksForUsage(node, usage, cdbc); + blocksForUsage(node, usage, cdbc, strategy); } + List usages = phantomUsages.get(node); + if (usages != null) { + for (FixedNode usage : usages) { + assert cfg.getNodeToBlock().get(usage) != null; + cdbc.apply(cfg.getNodeToBlock().get(usage)); + } + } + return cdbc.block; } @@ -204,7 +334,12 @@ assert node.predecessor() == null; for (Node input : node.inputs().nonNull()) { assert input instanceof ValueNode; - Block inputEarliest = earliestBlock(input); + Block inputEarliest; + if (input instanceof InvokeWithExceptionNode) { + inputEarliest = cfg.getNodeToBlock().get(((InvokeWithExceptionNode) input).next()); + } else { + inputEarliest = earliestBlock(input); + } if (!dominators.get(inputEarliest.getId())) { earliest = inputEarliest; do { @@ -242,7 +377,7 @@ * @param usage the usage whose blocks need to be considered * @param closure the closure that will be called for each block */ - private void blocksForUsage(ScheduledNode node, Node usage, BlockClosure closure) { + private void blocksForUsage(ScheduledNode node, Node usage, BlockClosure closure, SchedulingStrategy strategy) { assert !(node instanceof PhiNode); if (usage instanceof PhiNode) { @@ -274,7 +409,7 @@ if (unscheduledUsage instanceof VirtualState) { // If a FrameState is an outer FrameState this method behaves as if the inner // FrameState was the actual usage, by recursing. - blocksForUsage(node, unscheduledUsage, closure); + blocksForUsage(node, unscheduledUsage, closure, strategy); } else if (unscheduledUsage instanceof MergeNode) { // Only FrameStates can be connected to MergeNodes. assert usage instanceof FrameState; @@ -288,20 +423,20 @@ assert usage instanceof FrameState; assert unscheduledUsage instanceof StateSplit; // Otherwise: Put the input into the same block as the usage. - assignBlockToNode((ScheduledNode) unscheduledUsage); + assignBlockToNode((ScheduledNode) unscheduledUsage, strategy); closure.apply(cfg.getNodeToBlock().get(unscheduledUsage)); } } } else { // All other types of usages: Put the input into the same block as the usage. - assignBlockToNode((ScheduledNode) usage); + assignBlockToNode((ScheduledNode) usage, strategy); closure.apply(cfg.getNodeToBlock().get(usage)); } } - private void ensureScheduledUsages(Node node) { + private void ensureScheduledUsages(Node node, SchedulingStrategy strategy) { for (Node usage : node.usages().filter(ScheduledNode.class)) { - assignBlockToNode((ScheduledNode) usage); + assignBlockToNode((ScheduledNode) usage, strategy); } // now true usages are ready } @@ -316,27 +451,43 @@ return ControlFlowGraph.commonDominator(a, b); } - private void sortNodesWithinBlocks(StructuredGraph graph) { + private void sortNodesWithinBlocks(StructuredGraph graph, SchedulingStrategy strategy) { NodeBitMap visited = graph.createNodeBitMap(); for (Block b : cfg.getBlocks()) { - sortNodesWithinBlock(b, visited); + sortNodesWithinBlock(b, visited, strategy); } } + 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; + + List sortedInstructions; + switch (strategy) { + case EARLIEST: + sortedInstructions = sortNodesWithinBlockEarliest(b, visited); + break; + case LATEST: + case LATEST_OUT_OF_LOOPS: + sortedInstructions = sortNodesWithinBlockLatest(b, visited); + break; + default: + throw new GraalInternalError("unknown scheduling strategy"); + } + blockToNodesMap.put(b, sortedInstructions); + } + /** * Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over * all inputs. This means that a node is added to the list after all its inputs have been * processed. */ - private void sortNodesWithinBlock(Block b, NodeBitMap visited) { + private List sortNodesWithinBlockLatest(Block b, NodeBitMap visited) { List instructions = blockToNodesMap.get(b); - List sortedInstructions = new ArrayList<>(instructions.size() + 2); - - assert !visited.isMarked(b.getBeginNode()) && cfg.blockFor(b.getBeginNode()) == b; - assert !visited.isMarked(b.getEndNode()) && cfg.blockFor(b.getEndNode()) == b; + List sortedInstructions = new ArrayList<>(blockToNodesMap.get(b).size() + 2); for (ScheduledNode i : instructions) { - addToSorting(b, i, sortedInstructions, visited); + addToLatestSorting(b, i, sortedInstructions, visited); } // Make sure that last node gets really last (i.e. when a frame state successor hangs off @@ -363,25 +514,25 @@ sortedInstructions.add(b.getEndNode()); } } - blockToNodesMap.put(b, sortedInstructions); + return sortedInstructions; } - private void addUnscheduledToSorting(Block b, VirtualState state, List sortedInstructions, NodeBitMap visited) { + 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); for (Node input : state.inputs()) { if (input instanceof VirtualState) { - addUnscheduledToSorting(b, (VirtualState) input, sortedInstructions, visited); + addUnscheduledToLatestSorting(b, (VirtualState) input, sortedInstructions, visited); } else { - addToSorting(b, (ScheduledNode) input, sortedInstructions, visited); + addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited); } } } } - private void addToSorting(Block b, ScheduledNode i, List sortedInstructions, NodeBitMap visited) { + private void addToLatestSorting(Block b, ScheduledNode i, List sortedInstructions, NodeBitMap visited) { if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode || i instanceof LocalNode) { return; } @@ -396,17 +547,74 @@ assert state == null; state = (FrameState) input; } else { - addToSorting(b, (ScheduledNode) input, sortedInstructions, visited); + addToLatestSorting(b, (ScheduledNode) input, sortedInstructions, visited); + } + } + List inputs = phantomInputs.get(i); + if (inputs != null) { + for (FloatingNode input : inputs) { + addToLatestSorting(b, input, sortedInstructions, visited); } } - addToSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited); + addToLatestSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited); visited.mark(i); - addUnscheduledToSorting(b, state, sortedInstructions, visited); + addUnscheduledToLatestSorting(b, state, sortedInstructions, visited); assert write == null || !visited.isMarked(write); - addToSorting(b, write, sortedInstructions, visited); + addToLatestSorting(b, write, sortedInstructions, visited); // Now predecessors and inputs are scheduled => we can add this node. sortedInstructions.add(i); } + + /** + * Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over + * all usages. The resulting list is reversed to create an earliest-possible scheduling of + * nodes. + */ + private List sortNodesWithinBlockEarliest(Block b, NodeBitMap visited) { + List sortedInstructions = new ArrayList<>(blockToNodesMap.get(b).size() + 2); + addToEarliestSorting(b, b.getEndNode(), sortedInstructions, visited); + Collections.reverse(sortedInstructions); + return sortedInstructions; + } + + private void addToEarliestSorting(Block b, ScheduledNode i, List sortedInstructions, NodeBitMap visited) { + if (i == null || visited.isMarked(i) || cfg.getNodeToBlock().get(i) != b || i instanceof PhiNode || i instanceof LocalNode) { + return; + } + + visited.mark(i); + for (Node usage : i.usages()) { + if (usage instanceof VirtualState) { + // only fixed nodes can have VirtualState -> no need to schedule them + } else { + if (i instanceof LoopExitNode && usage instanceof ProxyNode) { + // value proxies should be scheduled before the loopexit, not after + } else { + addToEarliestSorting(b, (ScheduledNode) usage, sortedInstructions, visited); + } + } + } + + if (i instanceof BeginNode) { + ArrayList proxies = (i instanceof LoopExitNode) ? new ArrayList() : null; + for (ScheduledNode inBlock : blockToNodesMap.get(b)) { + if (!visited.isMarked(inBlock)) { + if (inBlock instanceof ProxyNode) { + proxies.add((ProxyNode) inBlock); + } else { + addToEarliestSorting(b, inBlock, sortedInstructions, visited); + } + } + } + sortedInstructions.add(i); + if (proxies != null) { + sortedInstructions.addAll(proxies); + } + } else { + sortedInstructions.add(i); + addToEarliestSorting(b, (ScheduledNode) i.predecessor(), sortedInstructions, visited); + } + } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java Thu Mar 21 14:11:13 2013 +0100 @@ -28,7 +28,6 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.*; import com.oracle.graal.compiler.alloc.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.debug.*; @@ -55,6 +54,7 @@ dumpSandboxed(object, message); } catch (Throwable ex) { TTY.println("CFGPrinter: Exception during output of " + message + ": " + ex); + ex.printStackTrace(); } } @@ -100,10 +100,6 @@ private static final AtomicInteger uniqueId = new AtomicInteger(); public void dumpSandboxed(Object object, String message) { - GraalCompiler compiler = Debug.contextLookup(GraalCompiler.class); - if (compiler == null) { - return; - } if (cfgPrinter == null) { cfgFile = new File("compilations-" + timestamp + "_" + uniqueId.incrementAndGet() + ".cfg"); @@ -120,18 +116,23 @@ return; } - cfgPrinter.target = compiler.target; if (object instanceof LIR) { cfgPrinter.lir = (LIR) object; } else { cfgPrinter.lir = Debug.contextLookup(LIR.class); } cfgPrinter.lirGenerator = Debug.contextLookup(LIRGenerator.class); + if (cfgPrinter.lirGenerator != null) { + cfgPrinter.target = cfgPrinter.lirGenerator.target(); + } if (cfgPrinter.lir != null) { cfgPrinter.cfg = cfgPrinter.lir.cfg; } - CodeCacheProvider runtime = compiler.runtime; + CodeCacheProvider runtime = Debug.contextLookup(CodeCacheProvider.class); + if (runtime != null) { + cfgPrinter.target = runtime.getTarget(); + } if (object instanceof BciBlockMapping) { BciBlockMapping blockMap = (BciBlockMapping) object; @@ -150,32 +151,11 @@ cfgPrinter.printCFG(message, Arrays.asList(cfgPrinter.cfg.getBlocks())); } else if (object instanceof CompilationResult) { - final CompilationResult tm = (CompilationResult) object; - final byte[] code = Arrays.copyOf(tm.getTargetCode(), tm.getTargetCodeSize()); - CodeInfo info = new CodeInfo() { - - public ResolvedJavaMethod getMethod() { - return curMethod; - } - - public long getStart() { - return 0L; - } - - public byte[] getCode() { - return code; - } - - @Override - public String toString() { - int size = code == null ? 0 : code.length; - return getMethod() + " installed code; length = " + size; - } - }; - cfgPrinter.printMachineCode(runtime.disassemble(info, tm), message); - } else if (isCompilationResultAndCodeInfo(object)) { + final CompilationResult compResult = (CompilationResult) object; + cfgPrinter.printMachineCode(runtime.disassemble(compResult, null), message); + } else if (isCompilationResultAndInstalledCode(object)) { Object[] tuple = (Object[]) object; - cfgPrinter.printMachineCode(runtime.disassemble((CodeInfo) tuple[1], (CompilationResult) tuple[0]), message); + cfgPrinter.printMachineCode(runtime.disassemble((CompilationResult) tuple[0], (InstalledCode) tuple[1]), message); } else if (object instanceof Interval[]) { cfgPrinter.printIntervals(message, (Interval[]) object); @@ -188,10 +168,10 @@ cfgPrinter.flush(); } - private static boolean isCompilationResultAndCodeInfo(Object object) { + private static boolean isCompilationResultAndInstalledCode(Object object) { if (object instanceof Object[]) { Object[] tuple = (Object[]) object; - if (tuple.length == 2 && tuple[0] instanceof CompilationResult && tuple[1] instanceof CodeInfo) { + if (tuple.length == 2 && tuple[0] instanceof CompilationResult && tuple[1] instanceof InstalledCode) { return true; } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java Thu Mar 21 14:11:13 2013 +0100 @@ -33,6 +33,7 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.phases.*; +import com.oracle.graal.phases.schedule.*; /** * Observes compilation events and uses {@link IdealGraphPrinter} to generate a graph representation @@ -81,16 +82,22 @@ if (sdf == null) { sdf = new SimpleDateFormat("YYYY-MM-dd-HHmm"); } - String fileName = "Graphs-" + Thread.currentThread().getName() + "-" + sdf.format(new Date()) + ext; + String prefix = "Graphs-" + Thread.currentThread().getName() + "-" + sdf.format(new Date()); + String num = ""; + File file; + int i = 0; + while ((file = new File(prefix + num + ext)).exists()) { + num = "-" + Integer.toString(++i); + } try { if (GraalOptions.PrintBinaryGraphs) { - printer = new BinaryGraphPrinter(FileChannel.open(new File(fileName).toPath(), StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW)); + printer = new BinaryGraphPrinter(FileChannel.open(file.toPath(), StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW)); } else { - printer = new IdealGraphPrinter(new FileOutputStream(fileName)); + printer = new IdealGraphPrinter(new FileOutputStream(file)); } - TTY.println("Dumping IGV graphs to %s", fileName); + TTY.println("Dumping IGV graphs to %s", file.getName()); } catch (IOException e) { - TTY.println("Failed to open %s to dump IGV graphs : %s", fileName, e); + TTY.println("Failed to open %s to dump IGV graphs : %s", file.getName(), e); failuresCount++; printer = null; } @@ -153,13 +160,14 @@ // Save inline context for next dump. previousInlineContext = inlineContext; + final SchedulePhase predefinedSchedule = getPredefinedSchedule(); Debug.sandbox("PrintingGraph", new Runnable() { @Override public void run() { // Finally, output the graph. try { - printer.print(graph, message, null); + printer.print(graph, message, predefinedSchedule); } catch (IOException e) { failuresCount++; printer = null; @@ -191,6 +199,16 @@ return result; } + private static SchedulePhase getPredefinedSchedule() { + SchedulePhase result = null; + for (Object o : Debug.context()) { + if (o instanceof SchedulePhase) { + result = (SchedulePhase) o; + } + } + return result; + } + private void openScope(String name, boolean showThread) { String prefix = showThread ? Thread.currentThread().getName() + ":" : ""; try { diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/HexCodeFile.java Thu Mar 21 14:11:13 2013 +0100 @@ -30,7 +30,6 @@ import com.oracle.graal.api.code.CompilationResult.CodeAnnotation; import com.oracle.graal.api.code.CompilationResult.CodeComment; import com.oracle.graal.api.code.CompilationResult.JumpTable; -import com.oracle.graal.api.code.CompilationResult.LookupTable; /** * A HexCodeFile is a textual format for representing a chunk of machine code along with extra @@ -122,8 +121,6 @@ public final ArrayList jumpTables = new ArrayList<>(); - public final ArrayList lookupTables = new ArrayList<>(); - public final String isa; public final int wordWidth; @@ -169,10 +166,6 @@ ps.printf("JumpTable %d %d %d %d %s%n", table.position, table.entrySize, table.low, table.high, SECTION_DELIM); } - for (LookupTable table : lookupTables) { - ps.printf("LookupTable %d %d %d %d %s%n", table.position, table.npairs, table.keySize, table.keySize, SECTION_DELIM); - } - for (Map.Entry> e : comments.entrySet()) { int pos = e.getKey(); for (String comment : e.getValue()) { @@ -233,9 +226,6 @@ if (a instanceof JumpTable) { JumpTable table = (JumpTable) a; hcf.jumpTables.add(table); - } else if (a instanceof LookupTable) { - LookupTable table = (LookupTable) a; - hcf.lookupTables.add(table); } else if (a instanceof CodeComment) { CodeComment comment = (CodeComment) a; hcf.addComment(comment.position, comment.value); @@ -422,15 +412,6 @@ int low = parseInt(bodyOffset + m.start(3), m.group(3)); int high = parseInt(bodyOffset + m.start(4), m.group(4)); hcf.jumpTables.add(new JumpTable(pos, low, high, entrySize)); - } else if (header.equals("LookupTable")) { - checkHCF("LookupTable", headerOffset); - m = HexCodeFile.LOOKUP_TABLE.matcher(body); - check(m.matches(), bodyOffset, "LookupTable does not match pattern " + HexCodeFile.LOOKUP_TABLE); - int pos = parseInt(bodyOffset + m.start(1), m.group(1)); - int npairs = parseInt(bodyOffset + m.start(2), m.group(2)); - int keySize = parseInt(bodyOffset + m.start(3), m.group(3)); - int offsetSize = parseInt(bodyOffset + m.start(4), m.group(4)); - hcf.lookupTables.add(new LookupTable(pos, npairs, keySize, offsetSize)); } else { error(offset, "Unknown section header: " + header); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.ptx/src/com/oracle/graal/ptx/PTX.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.ptx/src/com/oracle/graal/ptx/PTX.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,119 @@ +/* + * 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.ptx; + +import static com.oracle.graal.api.code.MemoryBarriers.*; +import static com.oracle.graal.api.code.Register.RegisterFlag.*; + +import java.nio.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.Register.*; + +/** + * Represents the PTX architecture. + */ +public class PTX extends Architecture { + + // @formatter:off + + /* + * Register State Space + * + * Registers (.reg state space) are fast storage locations. The number of + * registers is limited, and will vary from platform to platform. When the + * limit is exceeded, register variables will be spilled to memory, causing + * changes in performance. For each architecture, there is a recommended + * maximum number of registers to use (see the "CUDA Programming Guide" for + * details). + */ + + // General purpose registers + public static final Register r0 = new Register(0, 0, 8, "r0", CPU, RegisterFlag.Byte); + public static final Register r1 = new Register(1, 1, 8, "r1", CPU, RegisterFlag.Byte); + public static final Register r2 = new Register(2, 2, 8, "r2", CPU, RegisterFlag.Byte); + public static final Register r3 = new Register(3, 3, 8, "r3", CPU, RegisterFlag.Byte); + public static final Register r4 = new Register(4, 4, 8, "r4", CPU, RegisterFlag.Byte); + public static final Register r5 = new Register(5, 5, 8, "r5", CPU, RegisterFlag.Byte); + public static final Register r6 = new Register(6, 6, 8, "r6", CPU, RegisterFlag.Byte); + public static final Register r7 = new Register(7, 7, 8, "r7", CPU, RegisterFlag.Byte); + + public static final Register r8 = new Register(8, 8, 8, "r8", CPU, RegisterFlag.Byte); + public static final Register r9 = new Register(9, 9, 8, "r9", CPU, RegisterFlag.Byte); + public static final Register r10 = new Register(10, 10, 8, "r10", CPU, RegisterFlag.Byte); + public static final Register r11 = new Register(11, 11, 8, "r11", CPU, RegisterFlag.Byte); + public static final Register r12 = new Register(12, 12, 8, "r12", CPU, RegisterFlag.Byte); + public static final Register r13 = new Register(13, 13, 8, "r13", CPU, RegisterFlag.Byte); + public static final Register r14 = new Register(14, 14, 8, "r14", CPU, RegisterFlag.Byte); + public static final Register r15 = new Register(15, 15, 8, "r15", CPU, RegisterFlag.Byte); + + public static final Register[] gprRegisters = { + r0, r1, r2, r3, r4, r5, r6, r7, + r8, r9, r10, r11, r12, r13, r14, r15 + }; + + // Floating point registers + public static final Register f0 = new Register(16, 0, 8, "f0", FPU); + public static final Register f1 = new Register(17, 1, 8, "f1", FPU); + public static final Register f2 = new Register(18, 2, 8, "f2", FPU); + public static final Register f3 = new Register(19, 3, 8, "f3", FPU); + public static final Register f4 = new Register(20, 4, 8, "f4", FPU); + public static final Register f5 = new Register(21, 5, 8, "f5", FPU); + public static final Register f6 = new Register(22, 6, 8, "f6", FPU); + public static final Register f7 = new Register(23, 7, 8, "f7", FPU); + + public static final Register f8 = new Register(24, 8, 8, "f8", FPU); + public static final Register f9 = new Register(25, 9, 8, "f9", FPU); + public static final Register f10 = new Register(26, 10, 8, "f10", FPU); + public static final Register f11 = new Register(27, 11, 8, "f11", FPU); + public static final Register f12 = new Register(28, 12, 8, "f12", FPU); + public static final Register f13 = new Register(29, 13, 8, "f13", FPU); + public static final Register f14 = new Register(30, 14, 8, "f14", FPU); + public static final Register f15 = new Register(31, 15, 8, "f15", FPU); + + public static final Register[] fpuRegisters = { + f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15 + }; + + public static final Register[] allRegisters = { + // GPR + r0, r1, r2, r3, r4, r5, r6, r7, + r8, r9, r10, r11, r12, r13, r14, r15, + // FPU + f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15 + }; + + public PTX() { + super("PTX", + 8, + ByteOrder.LITTLE_ENDIAN, + allRegisters, + LOAD_STORE | STORE_STORE, + 0, + r15.encoding + 1, + 8); + } + // @formatter:on +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets.amd64/src/com/oracle/graal/snippets/amd64/AMD64ConvertSnippets.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets.amd64/src/com/oracle/graal/snippets/amd64/AMD64ConvertSnippets.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,196 @@ +/* + * 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.snippets.amd64; + +import static com.oracle.graal.snippets.SnippetTemplate.*; +import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*; +import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*; + +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.snippets.*; +import com.oracle.graal.snippets.Snippet.Parameter; +import com.oracle.graal.snippets.SnippetTemplate.AbstractTemplates; +import com.oracle.graal.snippets.SnippetTemplate.Arguments; +import com.oracle.graal.snippets.SnippetTemplate.Key; + +/** + * Snippets used for conversion operations on AMD64 where the AMD64 instruction used does not match + * the semantics of the JVM specification. + */ +public class AMD64ConvertSnippets implements SnippetsInterface { + + /** + * Converts a float to an int. + *

+ * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the + * conversion. If the float value is a NaN, infinity or if the result of the conversion is + * larger than {@link Integer#MAX_VALUE} then CVTTSS2SI returns {@link Integer#MIN_VALUE} and + * extra tests are required on the float value to return the correct int value. + * + * @param input the float being converted + * @param result the result produced by the CVTTSS2SI instruction + */ + @Snippet + public static int f2i(@Parameter("input") float input, @Parameter("result") int result) { + if (result == Integer.MIN_VALUE) { + probability(NOT_FREQUENT_PROBABILITY); + if (Float.isNaN(input)) { + // input is NaN -> return 0 + return 0; + } else if (input > 0.0f) { + // input is > 0 -> return max int + return Integer.MAX_VALUE; + } + } + return result; + } + + /** + * Converts a float to a long. + *

+ * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the + * conversion. If the float value is a NaN or infinity then CVTTSS2SI returns + * {@link Long#MIN_VALUE} and extra tests are required on the float value to return the correct + * long value. + * + * @param input the float being converted + * @param result the result produced by the CVTTSS2SI instruction + */ + @Snippet + public static long f2l(@Parameter("input") float input, @Parameter("result") long result) { + if (result == Long.MIN_VALUE) { + probability(NOT_FREQUENT_PROBABILITY); + if (Float.isNaN(input)) { + // input is NaN -> return 0 + return 0; + } else if (input > 0.0f) { + // input is > 0 -> return max int + return Long.MAX_VALUE; + } + } + return result; + } + + /** + * Converts a double to an int. + *

+ * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the + * conversion. If the double value is a NaN, infinity or if the result of the conversion is + * larger than {@link Integer#MAX_VALUE} then CVTTSD2SI returns {@link Integer#MIN_VALUE} and + * extra tests are required on the double value to return the correct int value. + * + * @param input the double being converted + * @param result the result produced by the CVTTSS2SI instruction + */ + @Snippet + public static int d2i(@Parameter("input") double input, @Parameter("result") int result) { + if (result == Integer.MIN_VALUE) { + probability(NOT_FREQUENT_PROBABILITY); + if (Double.isNaN(input)) { + // input is NaN -> return 0 + return 0; + } else if (input > 0.0d) { + // input is positive -> return maxInt + return Integer.MAX_VALUE; + } + } + return result; + } + + /** + * Converts a double to a long. + *

+ * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the + * conversion. If the double value is a NaN, infinity or if the result of the conversion is + * larger than {@link Long#MAX_VALUE} then CVTTSD2SI returns {@link Long#MIN_VALUE} and extra + * tests are required on the double value to return the correct long value. + * + * @param input the double being converted + * @param result the result produced by the CVTTSS2SI instruction + */ + @Snippet + public static long d2l(@Parameter("input") double input, @Parameter("result") long result) { + if (result == Long.MIN_VALUE) { + probability(NOT_FREQUENT_PROBABILITY); + if (Double.isNaN(input)) { + // input is NaN -> return 0 + return 0; + } else if (input > 0.0d) { + // input is positive -> return maxInt + return Long.MAX_VALUE; + } + } + return result; + } + + public static class Templates extends AbstractTemplates { + + private final ResolvedJavaMethod f2i; + private final ResolvedJavaMethod f2l; + private final ResolvedJavaMethod d2i; + private final ResolvedJavaMethod d2l; + + 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 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); + } + } + + 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 + // Convert node can be used as an input to the snippet. All usage of the + // Convert node are replaced by the placeholder which in turn is replaced by the + // snippet. + + 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); + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/CheckCastTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/CheckCastTest.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/CheckCastTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,9 +22,9 @@ */ package com.oracle.graal.snippets; -import org.junit.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.test.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; @@ -42,7 +42,7 @@ } } - @Test + @LongTest public void test1() { test("asNumber", profile(), 111); test("asNumber", profile(Integer.class), 111); @@ -52,7 +52,7 @@ test("asNumberExt", profile(Long.class, Short.class), 111); } - @Test + @LongTest public void test2() { test("asString", profile(), "111"); test("asString", profile(String.class), "111"); @@ -68,27 +68,27 @@ test("asStringExt", profile(String.class), "111"); } - @Test + @LongTest public void test3() { test("asNumber", profile(), "111"); } - @Test + @LongTest public void test4() { test("asString", profile(String.class), 111); } - @Test + @LongTest public void test5() { test("asNumberExt", profile(), "111"); } - @Test + @LongTest public void test6() { test("asStringExt", profile(String.class), 111); } - @Test + @LongTest public void test7() { Throwable throwable = new Exception(); test("asThrowable", profile(), throwable); @@ -96,12 +96,12 @@ test("asThrowable", profile(Exception.class, Error.class), throwable); } - @Test + @LongTest public void test8() { test("arrayStore", new Object[100], "111"); } - @Test + @LongTest public void test8_1() { test("arrayFill", new Object[100], "111"); } @@ -198,7 +198,7 @@ return (Cloneable) o; } - @Test + @LongTest public void test9() { Object o = new Depth13(); test("asDepth12", profile(), o); @@ -206,7 +206,7 @@ test("asDepth12", profile(Depth13.class, Depth14.class), o); } - @Test + @LongTest public void test10() { Object o = new Depth13[3][]; test("asDepth12Arr", o); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfDynamicTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfDynamicTest.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfDynamicTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,8 +22,7 @@ */ package com.oracle.graal.snippets; -import org.junit.*; - +import com.oracle.graal.test.*; import com.oracle.graal.compiler.test.*; import com.oracle.graal.nodes.java.*; @@ -36,7 +35,7 @@ return value; } - @Test + @LongTest public void test100() { final Object nul = null; test("isStringDynamic", nul); @@ -44,7 +43,7 @@ test("isStringDynamic", Object.class); } - @Test + @LongTest public void test101() { final Object nul = null; test("isStringIntDynamic", nul); @@ -52,7 +51,7 @@ test("isStringIntDynamic", Object.class); } - @Test + @LongTest public void test103() { test("isInstanceDynamic", String.class, null); test("isInstanceDynamic", String.class, "object"); @@ -62,7 +61,7 @@ test("isInstanceDynamic", int.class, Object.class); } - @Test + @LongTest public void test104() { test("isInstanceIntDynamic", String.class, null); test("isInstanceIntDynamic", String.class, "object"); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfTest.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,12 +24,12 @@ import java.util.*; -import org.junit.*; 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.*; @@ -57,7 +57,7 @@ } } - @Test + @LongTest public void test1() { test("isString", profile(), "object"); test("isString", profile(String.class), "object"); @@ -66,7 +66,7 @@ test("isString", profile(String.class), Object.class); } - @Test + @LongTest public void test2() { test("isStringInt", profile(), "object"); test("isStringInt", profile(String.class), "object"); @@ -75,7 +75,7 @@ test("isStringInt", profile(String.class), Object.class); } - @Test + @LongTest public void test2_1() { test("isStringIntComplex", profile(), "object"); test("isStringIntComplex", profile(String.class), "object"); @@ -84,7 +84,7 @@ test("isStringIntComplex", profile(String.class), Object.class); } - @Test + @LongTest public void test3() { Throwable throwable = new Exception(); test("isThrowable", profile(), throwable); @@ -96,7 +96,7 @@ test("isThrowable", profile(Exception.class, Error.class), Object.class); } - @Test + @LongTest public void test3_1() { onlyFirstIsException(new Exception(), new Error()); test("onlyFirstIsException", profile(), new Exception(), new Error()); @@ -105,7 +105,7 @@ test("onlyFirstIsException", profile(), new Error(), new Error()); } - @Test + @LongTest public void test4() { Throwable throwable = new Exception(); test("isThrowableInt", profile(), throwable); @@ -117,7 +117,7 @@ test("isThrowableInt", profile(Exception.class, Error.class), Object.class); } - @Test + @LongTest public void test5() { Map map = new HashMap<>(); test("isMap", profile(), map); @@ -129,7 +129,7 @@ test("isMap", profile(TreeMap.class, HashMap.class), Object.class); } - @Test + @LongTest public void test6() { Map map = new HashMap<>(); test("isMapInt", profile(), map); @@ -141,7 +141,7 @@ test("isMapInt", profile(TreeMap.class, HashMap.class), Object.class); } - @Test + @LongTest public void test7() { Object o = new Depth13(); test("isDepth12", profile(), o); @@ -154,7 +154,7 @@ test("isDepth12", profile(Depth13.class, Depth14.class), o); } - @Test + @LongTest public void test8() { Object o = new Depth13(); test("isDepth12Int", profile(), o); @@ -260,7 +260,7 @@ } } - @Test + @LongTest public void test9() { MyCall callAt63 = new MyCall(63); MyMark markAt63 = new MyMark(63); @@ -277,10 +277,10 @@ return s1.offset - s2.offset; } - @Test + @LongTest public void test10() { Mark[] noMarks = {}; - Call callAt63 = new Call("ignore", 63, 5, true, null); + Call callAt63 = new Call(null, 63, 5, true, null); Mark markAt63 = new Mark(63, "1", noMarks); test("compareSites", callAt63, callAt63); test("compareSites", callAt63, markAt63); @@ -302,7 +302,7 @@ * 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}. */ - @Test + @LongTest public void test_removeIntermediateMaterialization() { List list = Arrays.asList("1", "2", "3", "4"); test("removeIntermediateMaterialization", profile(), list, "2", "yes", "no"); @@ -357,7 +357,7 @@ return o instanceof D[]; } - @Test + @LongTest public void testArray() { Object aArray = new A[10]; test("isArrayOfA", aArray); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -426,9 +426,9 @@ Assumptions assumptions = new Assumptions(true); new ComputeProbabilityPhase().apply(graph); Debug.dump(graph, "Graph"); - new InliningPhase(null, runtime(), null, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); + new InliningPhase(runtime(), null, assumptions, null, phasePlan, OptimisticOptimizations.ALL).apply(graph); Debug.dump(graph, "Graph"); - new CanonicalizerPhase(null, runtime(), assumptions).apply(graph); + new CanonicalizerPhase(runtime(), assumptions).apply(graph); new DeadCodeEliminationPhase().apply(graph); assertNotInGraph(graph, Invoke.class); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewArrayTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewArrayTest.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewArrayTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -25,6 +25,7 @@ import org.junit.*; import com.oracle.graal.compiler.test.*; +import com.oracle.graal.test.*; /** * Tests the implementation of {@code [A]NEWARRAY}. @@ -57,7 +58,7 @@ } } - @Test + @LongTest public void test1() { for (String type : new String[]{"Byte", "Char", "Short", "Int", "Float", "Long", "Double", "String"}) { test("new" + type + "Array7"); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewInstanceTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewInstanceTest.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewInstanceTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -27,6 +27,7 @@ import org.junit.*; import com.oracle.graal.compiler.test.*; +import com.oracle.graal.test.*; /** * Tests the implementation of {@code NEW}. @@ -56,12 +57,12 @@ } } - @Test + @LongTest public void test1() { test("newObject"); } - @Test + @LongTest public void test2() { test("newObjectTwice"); } @@ -70,37 +71,37 @@ return new Object(); } - @Test + @LongTest public void test3() { test("newObjectLoop", 100); } - @Test + @LongTest public void test4() { test("newBigObject"); } - @Test + @LongTest public void test5() { test("newSomeObject"); } - @Test + @LongTest public void test6() { test("newEmptyString"); } - @Test + @LongTest public void test7() { test("newString", "value"); } - @Test + @LongTest public void test8() { test("newHashMap", 31); } - @Test + @LongTest public void test9() { test("newRegression", true); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewMultiArrayTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewMultiArrayTest.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewMultiArrayTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -25,11 +25,10 @@ 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.test.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; @@ -87,7 +86,7 @@ Class bottomClass; int[] dimensions; - @Test + @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; @@ -118,7 +117,7 @@ return new Object[10][9][8]; } - @Test + @LongTest public void test2() { test("newMultiArrayException"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/PointerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/PointerTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,399 @@ +/* + * 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.snippets; + +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.snippets.Snippet.SnippetInliningPolicy; +import com.oracle.graal.word.*; + +/** + * Tests for the {@link Pointer} read and write operations. + */ +public class PointerTest extends GraalCompilerTest implements SnippetsInterface { + + 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 SnippetInstaller installer; + + public PointerTest() { + target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget(); + installer = new SnippetInstaller(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 dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,13 +24,11 @@ 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.*; import com.oracle.graal.compiler.test.*; +import com.oracle.graal.test.*; import com.oracle.graal.nodes.*; import com.oracle.graal.snippets.Snippet.SnippetInliningPolicy; import com.oracle.graal.word.*; @@ -43,7 +41,7 @@ private final SnippetInstaller installer; public WordTest() { - TargetDescription target = Graal.getRequiredCapability(GraalCompiler.class).target; + TargetDescription target = Graal.getRequiredCapability(CodeCacheProvider.class).getTarget(); installer = new SnippetInstaller(runtime, new Assumptions(false), target); } @@ -52,10 +50,10 @@ @Override protected StructuredGraph parse(Method m) { ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); - return installer.makeGraph(resolvedMethod, inliningPolicy.get(), false); + return installer.makeGraph(resolvedMethod, inliningPolicy.get()); } - @Test + @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}; @@ -67,7 +65,7 @@ } } - @Test + @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}; @@ -104,7 +102,7 @@ } } - @Test + @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) { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/ClassSubstitution.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/ClassSubstitution.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/ClassSubstitution.java Thu Mar 21 14:11:13 2013 +0100 @@ -56,6 +56,12 @@ String className() default ""; /** + * Determines if the substitutions are for classes that may not be part of the runtime. + * Substitutions for such classes are omitted if the original classes cannot be found. + */ + boolean optional() default false; + + /** * Denotes a substitute method. A substitute method can call the original/substituted method by * making a recursive call to itself. */ diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java Thu Mar 21 14:11:13 2013 +0100 @@ -95,7 +95,7 @@ } else { KeyAndArguments keyAndArguments = getKeyAndArguments(replacer, tool); SnippetTemplate template = cache.get(keyAndArguments.key, assumptions); - template.instantiate(runtime, instanceOf, replacer, tool.lastFixedNode(), keyAndArguments.arguments); + template.instantiate(runtime, instanceOf, replacer, tool, keyAndArguments.arguments); } } @@ -223,11 +223,15 @@ usage.replaceFirstInput(instanceOf, instantiation.asCondition(trueValue)); } + private boolean usageFollowsInstantiation() { + return instantiation.result != null && instantiation.result.merge().next() == usage; + } + @Override public void replace(ValueNode oldNode, ValueNode newNode) { assert newNode instanceof PhiNode; assert oldNode == instanceOf; - if (sameBlock && solitaryUsage) { + if (sameBlock && solitaryUsage && usageFollowsInstantiation()) { removeIntermediateMaterialization(newNode); } else { newNode.inferStamp(); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetFrameStateCleanupPhase.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetFrameStateCleanupPhase.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetFrameStateCleanupPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,30 +22,98 @@ */ package com.oracle.graal.snippets; -import com.oracle.graal.graph.*; +import java.util.*; + import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; +import com.oracle.graal.phases.graph.*; +import com.oracle.graal.phases.graph.ReentrantNodeIterator.LoopInfo; +import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; /** * Removes frame states from {@linkplain StateSplit#hasSideEffect() non-side-effecting} nodes in a * snippet. + * + * The frame states of side-effecting nodes are replaced with + * {@linkplain FrameState#INVALID_FRAMESTATE_BCI invalid} frame states. Loops that contain invalid + * frame states are also assigned an invalid frame state. + * + * The invalid frame states ensure that no deoptimization to a snippet frame state will happen. */ public class SnippetFrameStateCleanupPhase extends Phase { @Override protected void run(StructuredGraph graph) { - for (Node node : graph.getNodes().filterInterface(StateSplit.class)) { - StateSplit stateSplit = (StateSplit) node; - FrameState frameState = stateSplit.stateAfter(); - if (!stateSplit.hasSideEffect()) { + ReentrantNodeIterator.apply(new SnippetFrameStateCleanupClosure(), graph.start(), new CleanupState(false), null); + } + + private static class CleanupState { + + public boolean containsFrameState; + + public CleanupState(boolean containsFrameState) { + this.containsFrameState = containsFrameState; + } + } + + /** + * A proper (loop-aware) iteration over the graph is used to detect loops that contain invalid + * frame states, so that they can be marked with an invalid frame state. + */ + private static class SnippetFrameStateCleanupClosure extends NodeIteratorClosure { + + @Override + protected void processNode(FixedNode node, CleanupState currentState) { + if (node instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) node; + FrameState frameState = stateSplit.stateAfter(); if (frameState != null) { - stateSplit.setStateAfter(null); + if (stateSplit.hasSideEffect()) { + currentState.containsFrameState = true; + stateSplit.setStateAfter(node.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI))); + } else { + stateSplit.setStateAfter(null); + } if (frameState.usages().isEmpty()) { GraphUtil.killWithUnusedFloatingInputs(frameState); } } } } + + @Override + protected CleanupState merge(MergeNode merge, List states) { + for (CleanupState state : states) { + if (state.containsFrameState) { + return new CleanupState(true); + } + } + return new CleanupState(false); + } + + @Override + protected CleanupState afterSplit(BeginNode node, CleanupState oldState) { + return new CleanupState(oldState.containsFrameState); + } + + @Override + protected Map processLoop(LoopBeginNode loop, CleanupState initialState) { + LoopInfo info = ReentrantNodeIterator.processLoop(this, loop, new CleanupState(false)); + boolean containsFrameState = false; + for (CleanupState state : info.endStates.values()) { + containsFrameState |= state.containsFrameState; + } + if (containsFrameState) { + loop.setStateAfter(loop.graph().add(new FrameState(FrameState.INVALID_FRAMESTATE_BCI))); + } + if (containsFrameState || initialState.containsFrameState) { + for (CleanupState state : info.exitStates.values()) { + state.containsFrameState = true; + } + } + return info.exitStates; + } + } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java Thu Mar 21 14:11:13 2013 +0100 @@ -53,10 +53,10 @@ */ public class SnippetInstaller { - private final MetaAccessProvider runtime; - private final TargetDescription target; - private final Assumptions assumptions; - private final BoxingMethodPool pool; + protected final MetaAccessProvider runtime; + protected final TargetDescription target; + protected final Assumptions assumptions; + protected final BoxingMethodPool pool; private final Thread owner; /** @@ -89,7 +89,7 @@ } ResolvedJavaMethod snippet = runtime.lookupJavaMethod(method); assert snippet.getCompilerStorage().get(Graph.class) == null : method; - StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet), false); + StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet)); // System.out.println("snippet: " + graph); snippet.getCompilerStorage().put(Graph.class, graph); } @@ -125,14 +125,18 @@ } String originalName = originalName(substituteMethod, methodSubstitution.value()); Class[] originalParameters = originalParameters(substituteMethod, methodSubstitution.signature(), methodSubstitution.isStatic()); - Method originalMethod = originalMethod(classSubstitution, originalName, originalParameters); - installMethodSubstitution(originalMethod, substituteMethod); + 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()); - Method originalMethod = originalMethod(classSubstitution, originalName, originalParameters); - installMacroSubstitution(originalMethod, macroSubstitution.macro()); + Member originalMethod = originalMethod(classSubstitution, originalName, originalParameters); + if (originalMethod != null) { + installMacroSubstitution(originalMethod, macroSubstitution.macro()); + } } } } @@ -145,16 +149,19 @@ /** * Installs a method substitution. * - * @param originalMethod a method being substituted + * @param originalMethod a method or constructor being substituted * @param substituteMethod the substitute method */ - protected void installMethodSubstitution(Method originalMethod, Method substituteMethod) { + protected void installMethodSubstitution(Member originalMethod, Method substituteMethod) { substitute = runtime.lookupJavaMethod(substituteMethod); - original = runtime.lookupJavaMethod(originalMethod); + if (originalMethod instanceof Method) { + original = runtime.lookupJavaMethod((Method) originalMethod); + } else { + original = runtime.lookupJavaConstructor((Constructor) originalMethod); + } try { - // System.out.println("substitution: " + MetaUtil.format("%H.%n(%p)", original) + - // " --> " + MetaUtil.format("%H.%n(%p)", substitute)); - StructuredGraph graph = makeGraph(substitute, inliningPolicy(substitute), true); + 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(Graph.class, graph); assert oldValue == null; } finally { @@ -167,11 +174,16 @@ /** * Installs a macro substitution. * - * @param originalMethod a method being substituted + * @param originalMethod a method or constructor being substituted * @param macro the substitute macro node class */ - protected void installMacroSubstitution(Method originalMethod, Class macro) { - ResolvedJavaMethod originalJavaMethod = runtime.lookupJavaMethod(originalMethod); + 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; } @@ -192,23 +204,27 @@ } } - public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy, final boolean isSubstitution) { + /** + * Does final processing of a snippet graph. + */ + protected void finalizeGraph(ResolvedJavaMethod method, StructuredGraph graph) { + new SnippetIntrinsificationPhase(runtime, pool).apply(graph); + assert SnippetTemplate.hasConstantParameter(method) || SnippetIntrinsificationVerificationPhase.verify(graph); + + new SnippetFrameStateCleanupPhase().apply(graph); + new DeadCodeEliminationPhase().apply(graph); + + new InsertStateAfterPlaceholderPhase().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); - new SnippetIntrinsificationPhase(runtime, pool, SnippetTemplate.hasConstantParameter(method)).apply(graph); - - if (isSubstitution && !substituteCallsOriginal) { - // TODO (ds) remove the constraint of only processing substitutions - // once issues with the arraycopy snippets have been resolved - new SnippetFrameStateCleanupPhase().apply(graph); - new DeadCodeEliminationPhase().apply(graph); - } - - new InsertStateAfterPlaceholderPhase().apply(graph); + finalizeGraph(method, graph); Debug.dump(graph, "%s: Final", method.getName()); @@ -221,14 +237,15 @@ StructuredGraph graph = graphCache.get(method); if (graph == null) { graph = buildGraph(method, policy == null ? inliningPolicy(method) : policy); - // System.out.println("built " + graph); graphCache.put(method, graph); } return graph; } - private StructuredGraph buildGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { - assert !Modifier.isAbstract(method.getModifiers()) && !Modifier.isNative(method.getModifiers()) : method; + /** + * 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); @@ -237,8 +254,41 @@ Debug.dump(graph, "%s: %s", method.getName(), GraphBuilderPhase.class.getSimpleName()); new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph); + new SnippetIntrinsificationPhase(runtime, pool).apply(graph); - new SnippetIntrinsificationPhase(runtime, pool, true).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 SnippetIntrinsificationPhase(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(); @@ -248,36 +298,20 @@ new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(originalGraph); InliningUtil.inline(invoke, originalGraph, true); - // TODO the inlined frame states still show the call from the substitute to the - // original. - // If this poses a problem, a phase should added to fix up these frame states. - Debug.dump(graph, "after inlining %s", callee); - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions).apply(graph); - } + 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); - if (GraalOptions.OptCanonicalizer) { - new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph); - new CanonicalizerPhase(target, runtime, assumptions).apply(graph); - } + afterInline(graph, targetGraph); } } } - new SnippetIntrinsificationPhase(runtime, pool, true).apply(graph); - - new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph); - - new DeadCodeEliminationPhase().apply(graph); - if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions).apply(graph); - } + afterInlining(graph); for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) { end.disableSafepoint(); @@ -298,13 +332,23 @@ } } - private static Class resolveType(String className) { + /** + * 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 + */ + private 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); } } @@ -317,7 +361,7 @@ dimensions++; } - Class baseClass = base.getKind() != Kind.Object ? base.getKind().toJavaClass() : resolveType(toJavaName(base)); + Class baseClass = base.getKind() != Kind.Object ? base.getKind().toJavaClass() : resolveType(toJavaName(base), false); return dimensions == 0 ? baseClass : Array.newInstance(baseClass, new int[dimensions]).getClass(); } @@ -339,13 +383,21 @@ return parameters; } - private static Method originalMethod(ClassSubstitution classSubstitution, String name, Class[] parameters) { + private static Member originalMethod(ClassSubstitution classSubstitution, String name, Class[] parameters) { Class originalClass = classSubstitution.value(); if (originalClass == ClassSubstitution.class) { - originalClass = resolveType(classSubstitution.className()); + originalClass = resolveType(classSubstitution.className(), classSubstitution.optional()); + if (originalClass == null) { + // optional class was not found + return null; + } } try { - return originalClass.getDeclaredMethod(name, parameters); + if (name.equals("")) { + return originalClass.getDeclaredConstructor(parameters); + } else { + return originalClass.getDeclaredMethod(name, parameters); + } } catch (NoSuchMethodException | SecurityException e) { throw new GraalInternalError(e); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -43,45 +43,21 @@ private final MetaAccessProvider runtime; private final BoxingMethodPool pool; - private final boolean intrinsificationOrFoldingCanBeDeferred; - /** - * @param intrinsificationOrFoldingCanBeDeferred if true, then {@link NonConstantParameterError} - * s are not fatal - */ - public SnippetIntrinsificationPhase(MetaAccessProvider runtime, BoxingMethodPool pool, boolean intrinsificationOrFoldingCanBeDeferred) { + public SnippetIntrinsificationPhase(MetaAccessProvider runtime, BoxingMethodPool pool) { this.runtime = runtime; this.pool = pool; - this.intrinsificationOrFoldingCanBeDeferred = intrinsificationOrFoldingCanBeDeferred; } @Override protected void run(StructuredGraph graph) { for (Invoke i : graph.getInvokes()) { - try { - if (i.callTarget() instanceof MethodCallTargetNode) { - tryIntrinsify(i); - } - } catch (NonConstantParameterError t) { - if (!intrinsificationOrFoldingCanBeDeferred) { - throw t; - } + if (i.callTarget() instanceof MethodCallTargetNode) { + tryIntrinsify(i); } } } - /** - * Exception raised when an argument to a {@linkplain Fold foldable} or {@link NodeIntrinsic} - * method is not a constant. - */ - @SuppressWarnings("serial") - public static class NonConstantParameterError extends Error { - - public NonConstantParameterError(String message) { - super(message); - } - } - public static Class[] signatureToTypes(Signature signature, ResolvedJavaType accessingClass) { int count = signature.getParameterCount(false); Class[] result = new Class[count]; @@ -91,7 +67,7 @@ return result; } - private void tryIntrinsify(Invoke invoke) { + private boolean tryIntrinsify(Invoke invoke) { ResolvedJavaMethod target = invoke.methodCallTarget().targetMethod(); NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class); ResolvedJavaType declaringClass = target.getDeclaringClass(); @@ -104,6 +80,9 @@ // Prepare the arguments for the reflective constructor call on the node class. Object[] nodeConstructorArguments = prepareArguments(invoke, parameterTypes, target, false); + if (nodeConstructorArguments == null) { + return false; + } // Create the new node instance. Class c = getNodeClass(target, intrinsic); @@ -120,6 +99,9 @@ // Prepare the arguments for the reflective method call Object[] arguments = prepareArguments(invoke, parameterTypes, target, true); + if (arguments == null) { + return false; + } Object receiver = null; if (!invoke.methodCallTarget().isStatic()) { receiver = arguments[0]; @@ -142,6 +124,7 @@ invoke.intrinsify(null); } } + return true; } /** @@ -149,6 +132,8 @@ * to a reflective invocation of a Java constructor or method. * * @param folding specifies if the invocation is for handling a {@link Fold} annotation + * @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) { NodeInputList arguments = invoke.callTarget().arguments(); @@ -161,8 +146,7 @@ ValueNode argument = tryBoxingElimination(parameterIndex, target, arguments.get(i)); if (folding || MetaUtil.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex, target) != null) { if (!(argument instanceof ConstantNode)) { - throw new NonConstantParameterError("parameter " + parameterIndex + " must be a compile time constant for calling " + invoke.methodCallTarget().targetMethod() + " at " + - sourceLocation(invoke.node()) + ": " + argument); + return null; } ConstantNode constantNode = (ConstantNode) argument; Constant constant = constantNode.asConstant(); @@ -364,7 +348,7 @@ if (newInstance instanceof ValueNode && (((ValueNode) newInstance).kind() != Kind.Object || ((ValueNode) newInstance).stamp() == StampFactory.forNodeIntrinsic())) { StructuredGraph graph = (StructuredGraph) newInstance.graph(); for (CheckCastNode checkCastNode : newInstance.usages().filter(CheckCastNode.class).snapshot()) { - for (ValueProxyNode vpn : checkCastNode.usages().filter(ValueProxyNode.class).snapshot()) { + for (ProxyNode vpn : checkCastNode.usages().filter(ProxyNode.class).snapshot()) { graph.replaceFloating(vpn, checkCastNode); } for (Node checkCastUsage : checkCastNode.usages().snapshot()) { @@ -373,20 +357,25 @@ graph.removeFixed(valueAnchorNode); } else if (checkCastUsage instanceof MethodCallTargetNode) { MethodCallTargetNode checkCastCallTarget = (MethodCallTargetNode) checkCastUsage; - assert pool.isUnboxingMethod(checkCastCallTarget.targetMethod()) : "checkcast at " + sourceLocation(checkCastNode) + " not used by an unboxing method but by a call at " + - sourceLocation(checkCastCallTarget.usages().first()) + " to " + checkCastCallTarget.targetMethod(); - Invoke invokeNode = checkCastCallTarget.invoke(); - invokeNode.node().replaceAtUsages(newInstance); - if (invokeNode instanceof InvokeWithExceptionNode) { - // Destroy exception edge & clear stateAfter. - InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode; + 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()); + invokeWithExceptionNode.killExceptionEdge(); + graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next()); + } else { + graph.removeFixed((InvokeNode) invokeNode); + } + checkCastCallTarget.safeDelete(); } else { - graph.removeFixed((InvokeNode) invokeNode); + 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()); } - checkCastCallTarget.safeDelete(); } else if (checkCastUsage instanceof FrameState) { checkCastUsage.replaceFirstInput(checkCastNode, null); } else if (checkCastUsage instanceof ReturnNode && checkCastNode.object().stamp() == StampFactory.forNodeIntrinsic()) { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationVerificationPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationVerificationPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,61 @@ +/* + * 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.snippets; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.snippets.Snippet.Fold; + +/** + * Checks that a graph contains no calls to {@link NodeIntrinsic} or {@link Fold} methods. + */ +public class SnippetIntrinsificationVerificationPhase extends Phase { + + public static boolean verify(StructuredGraph graph) { + new SnippetIntrinsificationVerificationPhase().apply(graph); + return true; + } + + @Override + protected void run(StructuredGraph graph) { + for (Invoke i : graph.getInvokes()) { + if (i.callTarget() instanceof MethodCallTargetNode) { + checkInvoke(i); + } + } + } + + private static void checkInvoke(Invoke invoke) { + ResolvedJavaMethod target = invoke.methodCallTarget().targetMethod(); + NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class); + if (intrinsic != null) { + throw new GraalInternalError("Illegal call to node intrinsic in " + invoke.graph() + ": " + invoke); + } else if (target.getAnnotation(Fold.class) != null) { + throw new GraalInternalError("Illegal call to foldable method in " + invoke.graph() + ": " + invoke); + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetProvider.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetProvider.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetProvider.java Thu Mar 21 14:11:13 2013 +0100 @@ -23,8 +23,9 @@ package com.oracle.graal.snippets; import com.oracle.graal.api.code.*; +import com.oracle.graal.compiler.target.*; public interface SnippetProvider { - void installSnippets(SnippetInstaller installer, Assumptions assumptions); + void installSnippets(Backend backend, SnippetInstaller installer, Assumptions assumptions); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java Thu Mar 21 14:11:13 2013 +0100 @@ -36,6 +36,7 @@ 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.*; @@ -282,11 +283,12 @@ Debug.dump(snippetCopy, "Before specialization"); if (!replacements.isEmpty()) { // Do deferred intrinsification of node intrinsics - new SnippetIntrinsificationPhase(runtime, new BoxingMethodPool(runtime), false).apply(snippetCopy); + new SnippetIntrinsificationPhase(runtime, new BoxingMethodPool(runtime)).apply(snippetCopy); new WordTypeRewriterPhase(runtime, target.wordKind).apply(snippetCopy); - new CanonicalizerPhase(null, runtime, assumptions, 0, null).apply(snippetCopy); + new CanonicalizerPhase(runtime, assumptions, 0, null).apply(snippetCopy); } + assert SnippetIntrinsificationVerificationPhase.verify(snippetCopy); // Gather the template parameters parameters = new HashMap<>(); @@ -344,7 +346,7 @@ LoopEx loop = new LoopsData(snippetCopy).loop(loopBegin); int mark = snippetCopy.getMark(); LoopTransformations.fullUnroll(loop, runtime, null); - new CanonicalizerPhase(null, runtime, assumptions, mark, null).apply(snippetCopy); + new CanonicalizerPhase(runtime, assumptions, mark, null).apply(snippetCopy); } FixedNode explodeLoopNext = explodeLoop.next(); explodeLoop.clearSuccessors(); @@ -558,7 +560,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, FixedWithNextNode replacee, UsageReplacer replacer, SnippetTemplate.Arguments args) { + public Map instantiate(MetaAccessProvider runtime, FixedNode replacee, UsageReplacer replacer, SnippetTemplate.Arguments args) { // Inline the snippet nodes, replacing parameters with the given args in the process String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}"; @@ -573,8 +575,12 @@ // Re-wire the control flow graph around the replacee FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); replacee.replaceAtPredecessor(firstCFGNodeDuplicate); - FixedNode next = replacee.next(); - replacee.setNext(null); + FixedNode next = null; + if (replacee instanceof FixedWithNextNode) { + FixedWithNextNode fwn = (FixedWithNextNode) replacee; + next = fwn.next(); + fwn.setNext(null); + } if (replacee instanceof StateSplit) { for (StateSplit sideEffectNode : sideEffectNodes) { @@ -628,10 +634,9 @@ * @param runtime * @param replacee the node that will be replaced * @param replacer object that replaces the usages of {@code replacee} - * @param lastFixedNode the CFG of the snippet is inserted after this node * @param args the arguments to be bound to the flattened positional parameters of the snippet */ - public void instantiate(MetaAccessProvider runtime, FloatingNode replacee, UsageReplacer replacer, FixedWithNextNode lastFixedNode, SnippetTemplate.Arguments args) { + public void instantiate(MetaAccessProvider runtime, FloatingNode replacee, UsageReplacer replacer, LoweringTool tool, SnippetTemplate.Arguments args) { // Inline the snippet nodes, replacing parameters with the given args in the process String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}"; @@ -643,7 +648,8 @@ Map duplicates = replaceeGraph.addDuplicates(nodes, replacements); Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method()); - assert lastFixedNode != null : replaceeGraph; + FixedWithNextNode lastFixedNode = tool.lastFixedNode(); + assert lastFixedNode != null && lastFixedNode.isAlive() : replaceeGraph; FixedNode next = lastFixedNode.next(); lastFixedNode.setNext(null); FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); @@ -672,10 +678,14 @@ assert returnValue != null || replacee.usages().isEmpty(); replacer.replace(replacee, returnValue); + tool.setLastFixedNode(null); Node returnDuplicate = duplicates.get(returnNode); if (returnDuplicate.isAlive()) { returnDuplicate.clearInputs(); returnDuplicate.replaceAndDelete(next); + if (next != null && next.predecessor() instanceof FixedWithNextNode) { + tool.setLastFixedNode((FixedWithNextNode) next.predecessor()); + } } Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectObjectStoreNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectObjectStoreNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectObjectStoreNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -62,7 +62,7 @@ @Override public void lower(LoweringTool tool) { StructuredGraph graph = (StructuredGraph) this.graph(); - IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), displacement, offset, graph, false); + IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), displacement, offset, graph, 1); WriteNode write = graph.add(new WriteNode(object, value, location)); graph.replaceFixedWithFixed(this, write); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectReadNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectReadNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectReadNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,7 +22,6 @@ */ package com.oracle.graal.snippets.nodes; -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; @@ -46,7 +45,7 @@ @Override public void generate(LIRGeneratorTool gen) { - gen.setResult(this, gen.emitLoad(new Address(readKind, gen.operand(address)), false)); + gen.setResult(this, gen.emitLoad(readKind, gen.operand(address), 0, Value.ILLEGAL, 0, false)); } @NodeIntrinsic diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectStoreNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectStoreNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectStoreNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,7 +22,6 @@ */ package com.oracle.graal.snippets.nodes; -import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.extended.*; @@ -49,7 +48,7 @@ @Override public void generate(LIRGeneratorTool gen) { Value v = gen.operand(value); - gen.emitStore(new Address(kind, gen.operand(address)), v, false); + gen.emitStore(kind, gen.operand(address), 0, Value.ILLEGAL, 0, v, false); } /* diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/MacroNode.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/MacroNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/MacroNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -30,6 +30,7 @@ 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.common.*; public class MacroNode extends AbstractStateSplit implements Lowerable { @@ -47,14 +48,32 @@ this.returnType = invoke.methodCallTarget().returnType(); } + public int getBci() { + return bci; + } + + public ResolvedJavaMethod getTargetMethod() { + return targetMethod; + } + + @SuppressWarnings("unused") + protected StructuredGraph getSnippetGraph(LoweringTool tool) { + return null; + } + @Override public void lower(LoweringTool tool) { - replaceWithInvoke(); + StructuredGraph snippetGraph = getSnippetGraph(tool); + + InvokeNode invoke = replaceWithInvoke(); + + if (snippetGraph != null) { + InliningUtil.inline(invoke, snippetGraph, false); + } } - public InvokeNode replaceWithInvoke() { + private InvokeNode replaceWithInvoke() { InvokeNode invoke = createInvoke(); - ((StructuredGraph) graph()).replaceFixedWithFixed(this, invoke); return invoke; } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/ReadRegisterNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/ReadRegisterNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,95 @@ +/* + * 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 + * 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.snippets.nodes; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.gen.*; +import com.oracle.graal.compiler.target.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; + +/** + * Access the value of a specific register. + */ +@NodeInfo(nameTemplate = "ReadRegister %{p#register}") +public final class ReadRegisterNode extends FixedWithNextNode implements LIRGenLowerable { + + /** + * The fixed register to access. + */ + private final Register register; + + /** + * When true, subsequent uses of this node use the fixed register; when false, the value is + * moved into a new virtual register so that the fixed register is not seen by uses. + */ + private final boolean directUse; + + /** + * When true, this node is also an implicit definition of the value for the register allocator, + * i.e., the register is an implicit incoming value; when false, the register must be defined in + * the same method or must be an register excluded from register allocation. + */ + private final boolean incoming; + + public ReadRegisterNode(Register register, Kind kind, boolean directUse, boolean incoming) { + super(StampFactory.forKind(kind)); + this.register = register; + this.directUse = directUse; + this.incoming = incoming; + } + + /** + * Constructor to be used by node intrinsics where the stamp is inferred from the intrinsic + * definition. + */ + public ReadRegisterNode(Register register, boolean directUse, boolean incoming) { + super(StampFactory.forNodeIntrinsic()); + this.register = register; + this.directUse = directUse; + this.incoming = incoming; + } + + @Override + public void generate(LIRGenerator generator) { + Value result = register.asValue(kind()); + if (incoming) { + generator.emitIncomingValues(new Value[]{result}); + } + if (!directUse) { + result = generator.emitMove(result); + } + generator.setResult(this, result); + } + + @Override + public String toString(Verbosity verbosity) { + if (verbosity == Verbosity.Name) { + return super.toString(Verbosity.Name) + "%" + register; + } else { + return super.toString(verbosity); + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/WriteRegisterNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/WriteRegisterNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,68 @@ +/* + * 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.snippets.nodes; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * Changes the value of a specific register. + */ +@NodeInfo(nameTemplate = "WriteRegister %{p#register}") +public final class WriteRegisterNode extends FixedWithNextNode implements LIRLowerable { + + /** + * The fixed register to access. + */ + private final Register register; + + /** + * The new value assigned to the register. + */ + @Input private ValueNode value; + + public WriteRegisterNode(Register register, ValueNode value) { + super(StampFactory.forVoid()); + this.register = register; + this.value = value; + } + + @Override + public void generate(LIRGeneratorTool generator) { + Value val = generator.operand(value); + generator.emitMove(val, register.asValue(val.getKind())); + } + + @Override + public String toString(Verbosity verbosity) { + if (verbosity == Verbosity.Name) { + return super.toString(Verbosity.Name) + "%" + register; + } else { + return super.toString(verbosity); + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalLongUnitTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalLongUnitTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.test; + +import java.util.*; + +import org.junit.*; +import org.junit.runners.*; +import org.junit.runners.model.*; + +public class GraalLongUnitTest extends BlockJUnit4ClassRunner { + + public GraalLongUnitTest(Class klass) throws InitializationError { + super(klass); + } + + @Override + protected List computeTestMethods() { + List methods = new ArrayList<>(5); + methods.addAll(getTestClass().getAnnotatedMethods(Test.class)); + methods.addAll(getTestClass().getAnnotatedMethods(LongTest.class)); + return methods; + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java --- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -25,12 +25,14 @@ import java.lang.reflect.*; import org.junit.*; +import org.junit.runner.*; /** * Base class for Graal tests. *

* This contains common utility methods that are used in multiple test projects. */ +@RunWith(GraalLongUnitTest.class) public class GraalTest { protected Method getMethod(String methodName) { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.test/src/com/oracle/graal/test/LongTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/LongTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,43 @@ +/* + * 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.test; + +import java.lang.annotation.*; + +/* copy of org.junit.Test */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface LongTest { + + static final class None extends Throwable { + + private static final long serialVersionUID = 1L; + + private None() { + } + } + + Class expected() default None.class; + + long timeout() default 0L; +} diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/BlockState.java Thu Mar 21 14:11:13 2013 +0100 @@ -32,10 +32,9 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.Virtualizable.EscapeState; import com.oracle.graal.nodes.virtual.*; -import com.oracle.graal.phases.graph.ReentrantBlockIterator.MergeableBlockState; import com.oracle.graal.virtual.nodes.*; -class BlockState extends MergeableBlockState { +class BlockState { private final HashMap objectStates = new HashMap<>(); private final HashMap objectAliases = new HashMap<>(); @@ -70,7 +69,6 @@ return object == null ? null : getObjectState(object); } - @Override public BlockState cloneState() { return new BlockState(this); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -40,14 +40,12 @@ public class PartialEscapeAnalysisPhase extends Phase { - private final TargetDescription target; private final MetaAccessProvider runtime; private final Assumptions assumptions; private CustomCanonicalizer customCanonicalizer; private final boolean iterative; - public PartialEscapeAnalysisPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, boolean iterative) { - this.target = target; + public PartialEscapeAnalysisPhase(MetaAccessProvider runtime, Assumptions assumptions, boolean iterative) { this.runtime = runtime; this.assumptions = assumptions; this.iterative = iterative; @@ -114,7 +112,7 @@ return false; } if (GraalOptions.OptCanonicalizer) { - new CanonicalizerPhase(target, runtime, assumptions, null, customCanonicalizer).apply(graph); + new CanonicalizerPhase(runtime, assumptions, null, customCanonicalizer).apply(graph); } return true; } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Thu Mar 21 14:11:13 2013 +0100 @@ -457,9 +457,9 @@ } private void processLoopExit(LoopExitNode exitNode, BlockState initialState, BlockState exitState) { - HashMap proxies = new HashMap<>(); + HashMap proxies = new HashMap<>(); - for (ValueProxyNode proxy : exitNode.proxies()) { + for (ProxyNode proxy : exitNode.proxies()) { ObjectState obj = exitState.getObjectState(proxy.value()); if (obj != null) { proxies.put(obj.virtual, proxy); @@ -473,7 +473,7 @@ 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) { - ValueProxyNode proxy = new ValueProxyNode(value, exitNode, PhiType.Value); + ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value); obj.setEntry(i, proxy); effects.addFloatingNode(proxy); } @@ -481,9 +481,9 @@ } } else { if (initialObj == null || initialObj.isVirtual()) { - ValueProxyNode proxy = proxies.get(obj.virtual); + ProxyNode proxy = proxies.get(obj.virtual); if (proxy == null) { - proxy = new ValueProxyNode(obj.getMaterializedValue(), exitNode, PhiType.Value); + proxy = new ProxyNode(obj.getMaterializedValue(), exitNode, PhiType.Value); effects.addFloatingNode(proxy); } else { effects.replaceFirstInput(proxy, proxy.value(), obj.getMaterializedValue()); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.word; +import com.oracle.graal.nodes.extended.*; + public interface Pointer extends Unsigned { /** @@ -42,6 +44,438 @@ * knows that the highest-order bit of the unsigned value is never used). * * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + byte readByte(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + char readChar(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + short readShort(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + int readInt(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + long readLong(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + float readFloat(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + double readDouble(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + Word readWord(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + Object readObject(WordBase offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + byte readByte(int offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + char readChar(int offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + short readShort(int offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + int readInt(int offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + long readLong(int offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + float readFloat(int offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + double readDouble(int offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + Word readWord(int offset, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the read (see {@link LocationNode}) + * @return the result of the memory access + */ + Object readObject(int offset, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeByte(WordBase offset, byte val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeChar(WordBase offset, char val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeShort(WordBase offset, short val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeInt(WordBase offset, int val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeLong(WordBase offset, long val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeFloat(WordBase offset, float val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeDouble(WordBase offset, double val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeWord(WordBase offset, WordBase val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeObject(WordBase offset, Object val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeByte(int offset, byte val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeChar(int offset, char val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeShort(int offset, short val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeInt(int offset, int val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeLong(int offset, long val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeFloat(int offset, float val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeDouble(int offset, double val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeWord(int offset, WordBase val, Object locationIdentity); + + /** + * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void writeObject(int offset, Object val, Object locationIdentity); + + /** + * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in + * bytes. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access * @return the result of the memory access */ byte readByte(WordBase offset); @@ -232,150 +666,6 @@ Object readObject(int offset); /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - byte readFinalByte(WordBase offset); - - /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - char readFinalChar(WordBase offset); - - /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - short readFinalShort(WordBase offset); - - /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - int readFinalInt(WordBase offset); - - /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - long readFinalLong(WordBase offset); - - /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - float readFinalFloat(WordBase offset); - - /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - double readFinalDouble(WordBase offset); - - /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - Word readFinalWord(WordBase offset); - - /** - * Reads the constant memory at address {@code (this + offset)}. Both the base address and - * offset are in bytes. - *

- * The caller guarantees that the memory content is final, i.e., never changing. The compiler - * can therefore eliminate memory accesses more aggressively. - *

- * The offset is always treated as a {@link Signed} value. However, the static type is - * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller - * knows that the highest-order bit of the unsigned value is never used). - * - * @param offset the signed offset for the memory access - * @return the result of the memory access - */ - Object readFinalObject(WordBase offset); - - /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in * bytes. *

@@ -412,7 +702,7 @@ * @param offset the signed offset for the memory access * @param val the value to be written to memory */ - void writeShort(WordBase offset, Short val); + void writeShort(WordBase offset, short val); /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java Thu Mar 21 14:11:13 2013 +0100 @@ -58,7 +58,6 @@ COMPARISON, NOT, READ, - READ_FINAL, WRITE, ZERO, FROM_UNSIGNED, @@ -602,6 +601,218 @@ @Override @Operation(opcode = Opcode.READ) + public byte readByte(WordBase offset, Object locationIdentity) { + return unsafe.getByte(add((Word) offset).unbox()); + } + + @Override + @Operation(opcode = Opcode.READ) + public char readChar(WordBase offset, Object locationIdentity) { + return unsafe.getChar(add((Word) offset).unbox()); + } + + @Override + @Operation(opcode = Opcode.READ) + public short readShort(WordBase offset, Object locationIdentity) { + return unsafe.getShort(add((Word) offset).unbox()); + } + + @Override + @Operation(opcode = Opcode.READ) + public int readInt(WordBase offset, Object locationIdentity) { + return unsafe.getInt(add((Word) offset).unbox()); + } + + @Override + @Operation(opcode = Opcode.READ) + public long readLong(WordBase offset, Object locationIdentity) { + return unsafe.getLong(add((Word) offset).unbox()); + } + + @Override + @Operation(opcode = Opcode.READ) + public float readFloat(WordBase offset, Object locationIdentity) { + return unsafe.getFloat(add((Word) offset).unbox()); + } + + @Override + @Operation(opcode = Opcode.READ) + public double readDouble(WordBase offset, Object locationIdentity) { + return unsafe.getDouble(add((Word) offset).unbox()); + } + + @Override + @Operation(opcode = Opcode.READ) + public Word readWord(WordBase offset, Object locationIdentity) { + return box(unsafe.getAddress(add((Word) offset).unbox())); + } + + @Override + @Operation(opcode = Opcode.READ) + public native Object readObject(WordBase offset, Object locationIdentity); + + @Override + @Operation(opcode = Opcode.READ) + public byte readByte(int offset, Object locationIdentity) { + return readByte(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) + public char readChar(int offset, Object locationIdentity) { + return readChar(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) + public short readShort(int offset, Object locationIdentity) { + return readShort(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) + public int readInt(int offset, Object locationIdentity) { + return readInt(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) + public long readLong(int offset, Object locationIdentity) { + return readLong(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) + public float readFloat(int offset, Object locationIdentity) { + return readFloat(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) + public double readDouble(int offset, Object locationIdentity) { + return readDouble(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) + public Word readWord(int offset, Object locationIdentity) { + return readWord(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) + public Object readObject(int offset, Object locationIdentity) { + return readObject(signed(offset), locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeByte(WordBase offset, byte val, Object locationIdentity) { + unsafe.putByte(add((Word) offset).unbox(), val); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeChar(WordBase offset, char val, Object locationIdentity) { + unsafe.putChar(add((Word) offset).unbox(), val); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeShort(WordBase offset, short val, Object locationIdentity) { + unsafe.putShort(add((Word) offset).unbox(), val); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeInt(WordBase offset, int val, Object locationIdentity) { + unsafe.putInt(add((Word) offset).unbox(), val); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeLong(WordBase offset, long val, Object locationIdentity) { + unsafe.putLong(add((Word) offset).unbox(), val); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeFloat(WordBase offset, float val, Object locationIdentity) { + unsafe.putFloat(add((Word) offset).unbox(), val); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeDouble(WordBase offset, double val, Object locationIdentity) { + unsafe.putDouble(add((Word) offset).unbox(), val); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeWord(WordBase offset, WordBase val, Object locationIdentity) { + unsafe.putAddress(add((Word) offset).unbox(), ((Word) val).unbox()); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public native void writeObject(WordBase offset, Object val, Object locationIdentity); + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeByte(int offset, byte val, Object locationIdentity) { + writeByte(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeChar(int offset, char val, Object locationIdentity) { + writeChar(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeShort(int offset, short val, Object locationIdentity) { + writeShort(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeInt(int offset, int val, Object locationIdentity) { + writeInt(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeLong(int offset, long val, Object locationIdentity) { + writeLong(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeFloat(int offset, float val, Object locationIdentity) { + writeFloat(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeDouble(int offset, double val, Object locationIdentity) { + writeDouble(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeWord(int offset, WordBase val, Object locationIdentity) { + writeWord(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.WRITE) + public void writeObject(int offset, Object val, Object locationIdentity) { + writeObject(signed(offset), val, locationIdentity); + } + + @Override + @Operation(opcode = Opcode.READ) public byte readByte(WordBase offset) { return unsafe.getByte(add((Word) offset).unbox()); } @@ -707,60 +918,6 @@ } @Override - @Operation(opcode = Opcode.READ_FINAL) - public byte readFinalByte(WordBase offset) { - return readByte(offset); - } - - @Override - @Operation(opcode = Opcode.READ_FINAL) - public char readFinalChar(WordBase offset) { - return readChar(offset); - } - - @Override - @Operation(opcode = Opcode.READ_FINAL) - public short readFinalShort(WordBase offset) { - return readShort(offset); - } - - @Override - @Operation(opcode = Opcode.READ_FINAL) - public int readFinalInt(WordBase offset) { - return readInt(offset); - } - - @Override - @Operation(opcode = Opcode.READ_FINAL) - public long readFinalLong(WordBase offset) { - return readLong(offset); - } - - @Override - @Operation(opcode = Opcode.READ_FINAL) - public float readFinalFloat(WordBase offset) { - return readFloat(offset); - } - - @Override - @Operation(opcode = Opcode.READ_FINAL) - public double readFinalDouble(WordBase offset) { - return readDouble(offset); - } - - @Override - @Operation(opcode = Opcode.READ_FINAL) - public Word readFinalWord(WordBase offset) { - return readWord(offset); - } - - @Override - @Operation(opcode = Opcode.READ_FINAL) - public Object readFinalObject(WordBase offset) { - return readObject(offset); - } - - @Override @Operation(opcode = Opcode.WRITE) public void writeByte(WordBase offset, byte val) { unsafe.putByte(add((Word) offset).unbox(), val); @@ -774,7 +931,7 @@ @Override @Operation(opcode = Opcode.WRITE) - public void writeShort(WordBase offset, Short val) { + public void writeShort(WordBase offset, short val) { unsafe.putShort(add((Word) offset).unbox(), val); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Thu Mar 21 14:11:13 2013 +0100 @@ -138,21 +138,17 @@ break; case READ: - assert arguments.size() == 2; + assert arguments.size() == 2 || arguments.size() == 3; Kind readKind = asKind(callTargetNode.returnType()); - replace(invoke, readOp(graph, arguments.get(0), arguments.get(1), invoke, readKind, LocationNode.ANY_LOCATION)); - break; - - case READ_FINAL: - assert arguments.size() == 2; - Kind readFinalKind = asKind(callTargetNode.returnType()); - replace(invoke, readOp(graph, arguments.get(0), arguments.get(1), invoke, readFinalKind, LocationNode.ANY_LOCATION)); + Object readLocation = arguments.size() == 2 ? LocationNode.UNKNOWN_LOCATION : arguments.get(2).asConstant().asObject(); + replace(invoke, readOp(graph, arguments.get(0), arguments.get(1), invoke, readKind, readLocation)); break; case WRITE: - assert arguments.size() == 3; - Kind writeKind = asKind(targetMethod.getSignature().getParameterType(1, null)); - replace(invoke, writeOp(graph, arguments.get(0), arguments.get(1), arguments.get(2), invoke, writeKind, LocationNode.ANY_LOCATION)); + assert arguments.size() == 3 || arguments.size() == 4; + Kind writeKind = asKind(targetMethod.getSignature().getParameterType(1, targetMethod.getDeclaringClass())); + Object writeLocation = arguments.size() == 3 ? LocationNode.ANY_LOCATION : arguments.get(3).asConstant().asObject(); + replace(invoke, writeOp(graph, arguments.get(0), arguments.get(1), arguments.get(2), invoke, writeKind, writeLocation)); break; case ZERO: @@ -256,19 +252,21 @@ } else { comparison = new IntegerLessThanNode(a, b); } - ConditionalNode materialize = graph.unique(new ConditionalNode(graph.unique(comparison), ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph))); - ValueNode op; + ConstantNode trueValue = ConstantNode.forInt(1, graph); + ConstantNode falseValue = ConstantNode.forInt(0, graph); + if (condition.canonicalNegate()) { - op = (ValueNode) materialize.negate(); - } else { - op = materialize; + ConstantNode temp = trueValue; + trueValue = falseValue; + falseValue = temp; } - return op; + ConditionalNode materialize = graph.unique(new ConditionalNode(graph.unique(comparison), trueValue, falseValue)); + return materialize; } 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, false); + 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); // The read must not float outside its block otherwise it may float above an explicit zero @@ -278,8 +276,9 @@ } 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, false); + IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, writeKind, 0, offset, graph, 1); WriteNode write = graph.add(new WriteNode(base, value, location)); + write.setStateAfter(invoke.stateAfter()); graph.addBeforeFixed(invoke.node(), write); return write; } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryOperationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryOperationTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,76 @@ +/* + * 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.truffle.api.codegen.test; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode; + +public class BinaryOperationTest { + + static int convertInt(Object value) { + if (value instanceof Number) { + return ((Number) value).intValue(); + } else if (value instanceof String) { + return Integer.parseInt((String) value); + } + throw new RuntimeException("Invalid datatype"); + } + + @NodeClass(BinaryNode.class) + abstract static class BinaryNode extends ValueNode { + + @Child protected ValueNode leftNode; + @Child protected ValueNode rightNode; + + public BinaryNode(ValueNode left, ValueNode right) { + this.leftNode = left; + this.rightNode = right; + } + + public BinaryNode(BinaryNode prev) { + this(prev.leftNode, prev.rightNode); + } + + @Specialization + int add(int left, int right) { + return left + right; + } + + @Generic + int add(Object left, Object right) { + return convertInt(left) + convertInt(right); + } + + @Specialization + int sub(int left, int right) { + return left + right; + } + + @Generic + int sub(Object left, Object right) { + return convertInt(left) + convertInt(right); + } + + } + +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/RuntimeStringTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/RuntimeStringTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,159 @@ +/* + * 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.truffle.api.codegen.test; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode; + +public class RuntimeStringTest { + + @Test + public void testSubstr() { + assertExecute(new RuntimeString("es"), "substr", new RuntimeString("test"), 1, 3); + } + + @Test + public void testConcat() { + assertExecute(new RuntimeString("concatconcat"), "concat", new RuntimeString("concat"), new RuntimeString("concat")); + } + + @Test(expected = ArrayIndexOutOfBoundsException.class) + public void testConcatFail() { + assertExecute(new RuntimeString("concatconcat"), "concat", new RuntimeString("concat")); + } + + @Test + public void testFindMethodByMethodName() { + // TODO + } + + private static void assertExecute(Object expectedResult, String name, Object... argumentsArray) { + ArgNode[] args = new ArgNode[argumentsArray.length]; + for (int i = 0; i < args.length; i++) { + args[i] = new ArgNode(argumentsArray, i); + } + + BuiltinNode node = null; + for (NodeFactory nodeFactory : RuntimeStringTestFactory.getFactories()) { + GeneratedBy generated = nodeFactory.getClass().getAnnotation(GeneratedBy.class); + Assert.assertNotNull(generated); + Assert.assertNotSame("", generated.methodName()); + if (generated.methodName().equals(name)) { + node = nodeFactory.createNode((Object) args); + break; + } + } + Assert.assertNotNull("Node not found", node); + CallTarget target = Truffle.getRuntime().createCallTarget(new TestRootNode(node)); + Assert.assertEquals(expectedResult, target.call()); + } + + static class ArgNode extends ValueNode { + + final Object[] arguments; + final int index; + + ArgNode(Object[] args, int index) { + this.arguments = args; + this.index = index; + } + + @Override + Object execute() { + return arguments[index]; + } + + } + + abstract static class BuiltinNode extends ValueNode { + + @Children ArgNode[] parameters; + + BuiltinNode(ArgNode[] parameters) { + this.parameters = adoptChildren(parameters); + } + + BuiltinNode(BuiltinNode prev) { + this(prev.parameters); + } + + } + + @NodeClass(BuiltinNode.class) + static class RuntimeString { + + private final String internal; + + public RuntimeString(String internal) { + this.internal = internal; + } + + @Specialization + static RuntimeString concat(RuntimeString s1, RuntimeString s2) { + return new RuntimeString(s1.internal + s2.internal); + } + + @Specialization + RuntimeString substr(int beginIndex, int endIndex) { + return new RuntimeString(internal.substring(beginIndex, endIndex)); + } + + @Generic + RuntimeString substr(Object beginIndex, Object endIndex) { + return substr(convertInt(beginIndex), convertInt(endIndex)); + } + + static int convertInt(Object value) { + if (value instanceof Number) { + return ((Number) value).intValue(); + } else if (value instanceof String) { + return Integer.parseInt((String) value); + } + throw new RuntimeException("Invalid datatype"); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RuntimeString) { + return internal.equals(((RuntimeString) obj).internal); + } + return super.equals(obj); + } + + @Override + public int hashCode() { + return internal.hashCode(); + } + + @Override + public String toString() { + return internal; + } + + } + +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,71 @@ +/* + * 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.truffle.api.codegen.test; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.api.codegen.test.RuntimeStringTest.RuntimeString; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +public class TypeSystemTest { + + @TypeSystem({int.class, RuntimeString.class}) + static class SimpleTypes { + } + + @TypeSystemReference(SimpleTypes.class) + abstract static class ValueNode extends Node { + + int executeInt() throws UnexpectedResultException { + return SimpleTypesGen.SIMPLETYPES.expectInteger(execute()); + } + + RuntimeString executeString() { + return new RuntimeString(execute().toString()); + } + + @SuppressWarnings("static-method") + final long executeSpecial() { + return 42L; + } + + abstract Object execute(); + + } + + @TypeSystemReference(SimpleTypes.class) + static class TestRootNode extends RootNode { + + @Child private ValueNode node; + + public TestRootNode(ValueNode node) { + this.node = adoptChild(node); + } + + @Override + public Object execute(VirtualFrame frame) { + return node.execute(); + } + } + +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,50 @@ +/* + * 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. + */ +/** + *

This package contains basic tests of the Truffle-Source-Code-Generation (short Codegen) API and serves at the same + * time as an introduction to the Codegen API for language implementors. Every test gives an example on how to use the construct explained in the class description.

+ * + *

+ * This API relies heavily on the concepts described in com.oracle.truffle.api.test. We assume that the + * reader is already familiarized with those concepts. + *

+ * + *

+ * TODO general description + *

+ * + *

+ * This introduction to Codegen contains items in the following recommended order: + * + * Prerequisites: + * + * + *

    + *
  • What do I need to get started? {@link com.oracle.truffle.api.codegen.test.TypeSystemTest}
  • + *
  • How would you generate function nodes for runtime objects? {@link com.oracle.truffle.api.codegen.test.RuntimeStringTest}
  • + *
+ *

+ * + */ +package com.oracle.truffle.api.codegen.test; + diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GeneratedBy.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GeneratedBy.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GeneratedBy.java Thu Mar 21 14:11:13 2013 +0100 @@ -25,12 +25,14 @@ import java.lang.annotation.*; /** - * Marks a type to be generated by another class. + * Marks a type to be generated by another class or a method. */ -@Retention(RetentionPolicy.CLASS) +@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface GeneratedBy { Class value(); + String methodName() default ""; + } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GuardCheck.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GuardCheck.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +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.truffle.api.codegen; - -import java.lang.annotation.*; - -/** - * - * - * @see SpecializationGuard - */ -@Retention(RetentionPolicy.CLASS) -@Target({ElementType.METHOD}) -public @interface GuardCheck { - -} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeClass.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,35 @@ +/* + * 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.truffle.api.codegen; + +import java.lang.annotation.*; + +import com.oracle.truffle.api.nodes.*; + +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.TYPE}) +public @interface NodeClass { + + Class value(); + +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeFactory.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,74 @@ +/* + * 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.truffle.api.codegen; + +import java.util.*; + +import com.oracle.truffle.api.nodes.*; + +/** + * Enables the dynamic creation of generated nodes. It provides an convenient way to instantiate + * generated node classes without using reflection. + */ +public interface NodeFactory { + + /** + * Instantiates the node using the arguments array. The arguments length and types must suffice + * one of the returned signatures in {@link #getNodeSignatures()}. If the arguments array does + * not suffice one of the node signatures an {@link IllegalArgumentException} is thrown. + * + * @param arguments the argument values + * @return the instantiated node + * @throws IllegalArgumentException + */ + T createNode(Object... arguments); + + /** + * Instantiates a new specialized variant of the node. This is an optional method and throws an + * {@link UnsupportedOperationException} if not supported. + * + * @param thisNode the current node + * @param specializionClasses + * @return the specialized node + */ + T createNodeSpecialized(T thisNode, Class... specializionClasses); + + /** + * Returns the node class that will get created by {@link #createNode(Object...)}. The node + * class does not match exactly to the instantiated object but they are guaranteed to be + * assignable. + */ + Class getNodeClass(); + + /** + * Returns a list of signatures that can be used to invoke {@link #createNode(Object...)}. + */ + List>> getNodeSignatures(); + + /** + * Returns a list of children that will be executed by the created node. This is useful for base + * nodes that can execute a variable amount of nodes. + */ + List> getExecutionSignature(); + +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeId.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeId.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,33 @@ +/* + * 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.truffle.api.codegen; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.METHOD, ElementType.TYPE}) +public @interface NodeId { + + String value(); + +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Specialization.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Specialization.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Specialization.java Thu Mar 21 14:11:13 2013 +0100 @@ -32,8 +32,8 @@ int order() default DEFAULT_ORDER; - SpecializationThrows[] exceptions() default {}; + Class[] rewriteOn() default {}; - SpecializationGuard[] guards() default {}; + String[] guards() default {}; } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationGuard.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationGuard.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +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.truffle.api.codegen; - -import java.lang.annotation.*; - -/** - * Specifies the use of a guard for a specialization. - */ -@Retention(RetentionPolicy.CLASS) -@Target({ElementType.METHOD}) -public @interface SpecializationGuard { - - /** - * Specifies the name of the guard method annotated by {@link GuardCheck} specified as method in - * the {@link TypeSystem} class. - */ - String methodName(); - - /** - * Determines if a guard check is invoked on specialization. Defaults to true. - */ - boolean onSpecialization() default true; - - /** - * Determines if a guard check is invoked on execution. Defaults to true. - */ - boolean onExecution() default true; - -} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationThrows.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationThrows.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +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.truffle.api.codegen; - -import java.lang.annotation.*; - -@Retention(RetentionPolicy.CLASS) -@Target({ElementType.METHOD}) -public @interface SpecializationThrows { - - Class javaClass(); - - String transitionTo(); -} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystem.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystem.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystem.java Thu Mar 21 14:11:13 2013 +0100 @@ -28,8 +28,8 @@ *

* Annotates a type system class that represents type information for a node. Generates code for * converting and managing types. Methods contained in the type system may be annotated with - * {@link TypeCast}, {@link TypeCheck} or {@link GuardCheck}. These methods alter the default - * behavior of the type system. + * {@link TypeCast} or {@link TypeCheck}. These methods alter the default behavior of the type + * system. *

* * @@ -62,7 +62,6 @@ * * @see TypeCast * @see TypeCheck - * @see GuardCheck */ @Retention(RetentionPolicy.CLASS) @Target({ElementType.TYPE}) diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -38,7 +38,7 @@ * should be speculated on. When the speculation fails and the child node cannot return the * appropriate type of value, it can use an {@link UnexpectedResultException} to still pass the * result to the caller. In such a case, the caller must rewrite itself to a more general version in - * oder to avoid future failures of this kind. + * order to avoid future failures of this kind. *

*/ public class ReturnTypeSpecializationTest { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AbstractParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AbstractParser.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AbstractParser.java Thu Mar 21 14:11:13 2013 +0100 @@ -58,12 +58,22 @@ if (!context.getTruffleTypes().verify(context, element, mirror)) { return null; } - return parse(element, mirror); + M model = parse(element, mirror); + if (model == null) { + return null; + } + + model.emitMessages((TypeElement) element, log); + return filterErrorElements(model); } finally { this.roundEnv = null; } } + protected M filterErrorElements(M model) { + return model.hasErrors() ? null : model; + } + protected abstract M parse(Element element, AnnotationMirror mirror); public abstract Class getAnnotationType(); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Log.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Log.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Log.java Thu Mar 21 14:11:13 2013 +0100 @@ -41,30 +41,6 @@ this.processingEnv = env; } - public void warning(Element element, String format, Object... args) { - message(Kind.WARNING, element, null, null, format, args); - } - - public void warning(Element element, AnnotationMirror mirror, String format, Object... args) { - message(Kind.WARNING, element, mirror, null, format, args); - } - - public void error(Element element, String format, Object... args) { - message(Kind.ERROR, element, null, null, format, args); - } - - public void error(String format, Object... args) { - message(Kind.ERROR, null, null, null, format, args); - } - - public void error(Element element, AnnotationMirror mirror, String format, Object... args) { - message(Kind.ERROR, element, mirror, null, format, args); - } - - public void error(Element element, AnnotationMirror mirror, AnnotationValue value, String format, Object... args) { - message(Kind.ERROR, element, mirror, value, format, args); - } - public void message(Kind kind, Element element, AnnotationMirror mirror, AnnotationValue value, String format, Object... args) { AnnotationMirror usedMirror = mirror; Element usedElement = element; diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleProcessor.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleProcessor.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleProcessor.java Thu Mar 21 14:11:13 2013 +0100 @@ -28,6 +28,7 @@ import javax.annotation.processing.*; import javax.lang.model.*; import javax.lang.model.element.*; +import javax.tools.Diagnostic.*; import com.oracle.truffle.codegen.processor.ProcessorContext.ProcessCallback; import com.oracle.truffle.codegen.processor.node.*; @@ -95,7 +96,7 @@ private static void handleThrowable(AnnotationProcessor generator, Throwable t, Element e) { String message = "Uncaught error in " + generator.getClass().getSimpleName() + " while processing " + e; - generator.getContext().getLog().error(e, message + ": " + Utils.printException(t)); + generator.getContext().getLog().message(Kind.ERROR, e, null, null, message + ": " + Utils.printException(t)); } @SuppressWarnings("unchecked") diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java Thu Mar 21 14:11:13 2013 +0100 @@ -26,8 +26,10 @@ import javax.lang.model.element.*; import javax.lang.model.type.*; +import javax.tools.Diagnostic.*; import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.intrinsics.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.nodes.Node.Child; import com.oracle.truffle.api.nodes.Node.Children; @@ -44,6 +46,7 @@ private final TypeMirror stableAnnotation; private final TypeMirror contentStableAnnotation; private final TypeMirror typeConversion; + private final TypeMirror truffleIntrinsics; private final List errors = new ArrayList<>(); @@ -55,6 +58,7 @@ stableAnnotation = getRequired(context, Child.class); contentStableAnnotation = getRequired(context, Children.class); typeConversion = getRequired(context, TypeConversion.class); + truffleIntrinsics = getRequired(context, TruffleIntrinsics.class); } public boolean verify(ProcessorContext context, Element element, AnnotationMirror mirror) { @@ -63,7 +67,7 @@ } for (String error : errors) { - context.getLog().error(element, mirror, error); + context.getLog().message(Kind.ERROR, element, mirror, null, error); } return false; @@ -77,6 +81,10 @@ return type; } + public TypeMirror getTruffleIntrinsics() { + return truffleIntrinsics; + } + public TypeMirror getTypeConversion() { return typeConversion; } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java Thu Mar 21 14:11:13 2013 +0100 @@ -47,9 +47,25 @@ } } + public static TypeMirror boxType(ProcessorContext context, TypeMirror primitiveType) { + TypeMirror boxedType = primitiveType; + if (boxedType.getKind().isPrimitive()) { + boxedType = context.getEnvironment().getTypeUtils().boxedClass((PrimitiveType) boxedType).asType(); + } + return boxedType; + } + + public static List asTypeMirrors(List elements) { + List types = new ArrayList<>(elements.size()); + for (Element element : elements) { + types.add(element.asType()); + } + return types; + } + public static List collectAnnotations(ProcessorContext context, AnnotationMirror markerAnnotation, String elementName, Element element, Class annotationClass) { - List result = Utils.getAnnotationValueList(markerAnnotation, elementName); + List result = Utils.getAnnotationValueList(AnnotationMirror.class, markerAnnotation, elementName); AnnotationMirror explicit = Utils.findAnnotationMirror(context.getEnvironment(), element, annotationClass); if (explicit != null) { result.add(explicit); @@ -61,6 +77,42 @@ return result; } + public static TypeMirror getCommonSuperType(ProcessorContext context, TypeMirror[] types) { + if (types.length == 0) { + return context.getType(Object.class); + } + TypeMirror prev = types[0]; + for (int i = 1; i < types.length; i++) { + prev = getCommonSuperType(context, prev, types[i]); + } + return prev; + } + + public static TypeMirror getCommonSuperType(ProcessorContext context, TypeMirror type1, TypeMirror type2) { + if (typeEquals(type1, type2)) { + return type1; + } + TypeElement element1 = fromTypeMirror(type1); + TypeElement element2 = fromTypeMirror(type2); + if (element1 == null || element2 == null) { + return context.getType(Object.class); + } + + List element1Types = getDirectSuperTypes(element1); + element1Types.add(0, element1); + List element2Types = getDirectSuperTypes(element2); + element2Types.add(0, element2); + + for (TypeElement superType1 : element1Types) { + for (TypeElement superType2 : element2Types) { + if (typeEquals(superType1.asType(), superType2.asType())) { + return superType2.asType(); + } + } + } + return context.getType(Object.class); + } + public static String getReadableSignature(ExecutableElement method) { // TODO toString does not guarantee a good signature return method.toString(); @@ -123,6 +175,46 @@ return new LinkedHashSet<>(Arrays.asList(modifier)); } + public static String getTypeId(TypeMirror mirror) { + switch (mirror.getKind()) { + case BOOLEAN: + return "Boolean"; + case BYTE: + return "Byte"; + case CHAR: + return "Char"; + case DOUBLE: + return "Double"; + case FLOAT: + return "Float"; + case SHORT: + return "Short"; + case INT: + return "Int"; + case LONG: + return "Long"; + case DECLARED: + return ((DeclaredType) mirror).asElement().getSimpleName().toString(); + case ARRAY: + return getTypeId(((ArrayType) mirror).getComponentType()) + "Array"; + case VOID: + return "Void"; + case WILDCARD: + StringBuilder b = new StringBuilder(); + WildcardType type = (WildcardType) mirror; + if (type.getExtendsBound() != null) { + b.append("Extends").append(getTypeId(type.getExtendsBound())); + } else if (type.getSuperBound() != null) { + b.append("Super").append(getTypeId(type.getExtendsBound())); + } + return b.toString(); + case TYPEVAR: + return "Any"; + default: + throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror); + } + } + public static String getSimpleName(TypeElement element) { return getSimpleName(element.asType()); } @@ -146,31 +238,43 @@ case LONG: return "long"; case DECLARED: - return getGenericName(fromTypeMirror(mirror)); + return getDeclaredName((DeclaredType) mirror); case ARRAY: return getSimpleName(((ArrayType) mirror).getComponentType()) + "[]"; case VOID: return "void"; + case WILDCARD: + return getWildcardName((WildcardType) mirror); case TYPEVAR: - return ((TypeParameterElement) ((TypeVariable) mirror).asElement()).getSimpleName().toString(); + return "?"; default: throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror); } } - private static String getGenericName(TypeElement element) { - String simpleName = element.getSimpleName().toString(); + private static String getWildcardName(WildcardType type) { + StringBuilder b = new StringBuilder(); + if (type.getExtendsBound() != null) { + b.append("? extends ").append(getSimpleName(type.getExtendsBound())); + } else if (type.getSuperBound() != null) { + b.append("? super ").append(getSimpleName(type.getExtendsBound())); + } + return b.toString(); + } - if (element.getTypeParameters().size() == 0) { + private static String getDeclaredName(DeclaredType element) { + String simpleName = element.asElement().getSimpleName().toString(); + + if (element.getTypeArguments().size() == 0) { return simpleName; } StringBuilder b = new StringBuilder(simpleName); b.append("<"); - if (element.getTypeParameters().size() > 0) { - for (int i = 0; i < element.getTypeParameters().size(); i++) { - b.append("?"); - if (i < element.getTypeParameters().size() - 1) { + if (element.getTypeArguments().size() > 0) { + for (int i = 0; i < element.getTypeArguments().size(); i++) { + b.append(getSimpleName(element.getTypeArguments().get(i))); + if (i < element.getTypeArguments().size() - 1) { b.append(", "); } } @@ -282,6 +386,19 @@ return null; } + public static List getDirectSuperTypes(TypeElement element) { + List types = new ArrayList<>(); + if (element.getSuperclass() != null) { + TypeElement superElement = fromTypeMirror(element.getSuperclass()); + if (superElement != null) { + types.add(superElement); + types.addAll(getDirectSuperTypes(superElement)); + } + } + + return types; + } + public static List getSuperTypes(TypeElement element) { List types = new ArrayList<>(); List superTypes = null; @@ -359,29 +476,32 @@ } @SuppressWarnings("unchecked") - public static List getAnnotationValueList(AnnotationMirror mirror, String name) { + public static List getAnnotationValueList(Class expectedListType, AnnotationMirror mirror, String name) { + List values = getAnnotationValue(List.class, mirror, name); List result = new ArrayList<>(); - List values = (List) getAnnotationValue(mirror, name).getValue(); + for (AnnotationValue value : values) { - result.add((T) value.getValue()); + result.add(resolveAnnotationValue(expectedListType, value)); } return result; } - public static TypeMirror getAnnotationValueType(AnnotationMirror mirror, String name) { - return (TypeMirror) getAnnotationValue(mirror, name).getValue(); + public static T getAnnotationValue(Class expectedType, AnnotationMirror mirror, String name) { + return resolveAnnotationValue(expectedType, getAnnotationValue(mirror, name)); } - public static TypeMirror getAnnotationValueTypeMirror(AnnotationMirror mirror, String name) { - return (TypeMirror) getAnnotationValue(mirror, name).getValue(); - } - - public static String getAnnotationValueString(AnnotationMirror mirror, String name) { - return (String) getAnnotationValue(mirror, name).getValue(); - } - - public static int getAnnotationValueInt(AnnotationMirror mirror, String name) { - return (int) getAnnotationValue(mirror, name).getValue(); + @SuppressWarnings({"unchecked"}) + private static T resolveAnnotationValue(Class expectedType, AnnotationValue value) { + Object unboxedValue = value.accept(new AnnotationValueVisitorImpl(), null); + if (unboxedValue != null) { + if (expectedType == TypeMirror.class && unboxedValue instanceof String) { + return null; + } + if (!expectedType.isAssignableFrom(unboxedValue.getClass())) { + throw new ClassCastException(unboxedValue.getClass().getName() + " not assignable from " + expectedType.getName()); + } + } + return (T) unboxedValue; } public static AnnotationValue getAnnotationValue(AnnotationMirror mirror, String name) { @@ -401,9 +521,79 @@ if (value == null) { value = valueMethod.getDefaultValue(); } + return value; } + private static class AnnotationValueVisitorImpl extends AbstractAnnotationValueVisitor7 { + + @Override + public Object visitBoolean(boolean b, Void p) { + return Boolean.valueOf(b); + } + + @Override + public Object visitByte(byte b, Void p) { + return Byte.valueOf(b); + } + + @Override + public Object visitChar(char c, Void p) { + return c; + } + + @Override + public Object visitDouble(double d, Void p) { + return d; + } + + @Override + public Object visitFloat(float f, Void p) { + return f; + } + + @Override + public Object visitInt(int i, Void p) { + return i; + } + + @Override + public Object visitLong(long i, Void p) { + return i; + } + + @Override + public Object visitShort(short s, Void p) { + return s; + } + + @Override + public Object visitString(String s, Void p) { + return s; + } + + @Override + public Object visitType(TypeMirror t, Void p) { + return t; + } + + @Override + public Object visitEnumConstant(VariableElement c, Void p) { + return c.getConstantValue(); + } + + @Override + public Object visitAnnotation(AnnotationMirror a, Void p) { + return a; + } + + @Override + public Object visitArray(List vals, Void p) { + return vals; + } + + } + public static boolean getAnnotationValueBoolean(AnnotationMirror mirror, String name) { return (Boolean) getAnnotationValue(mirror, name).getValue(); } @@ -468,8 +658,10 @@ for (int i = 0; i < params.length; i++) { TypeMirror param1 = params[i]; TypeMirror param2 = method.getParameters().get(i).asType(); - if (!getQualifiedName(param1).equals(getQualifiedName(param2))) { - continue method; + if (param1.getKind() != TypeKind.TYPEVAR && param2.getKind() != TypeKind.TYPEVAR) { + if (!getQualifiedName(param1).equals(getQualifiedName(param2))) { + continue method; + } } } return method; @@ -520,6 +712,14 @@ } String qualified1 = getQualifiedName(type1); String qualified2 = getQualifiedName(type2); + + if (type1.getKind() == TypeKind.ARRAY || type2.getKind() == TypeKind.ARRAY) { + if (type1.getKind() == TypeKind.ARRAY && type2.getKind() == TypeKind.ARRAY) { + return typeEquals(((ArrayType) type1).getComponentType(), ((ArrayType) type2).getComponentType()); + } else { + return false; + } + } return qualified1.equals(qualified2); } @@ -548,7 +748,7 @@ return true; } - // search for any supertypes + // search for any super types TypeElement exceptionTypeElement = fromTypeMirror(exceptionType); List superTypes = getSuperTypes(exceptionTypeElement); for (TypeElement typeElement : superTypes) { @@ -577,7 +777,7 @@ Set typeSuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(type))); String typeName = getQualifiedName(type); if (!typeSuperSet.contains(Throwable.class.getCanonicalName()) && !typeName.equals(Throwable.class.getCanonicalName())) { - throw new IllegalArgumentException("Given does not extend Throwable."); + throw new IllegalArgumentException("Given type does not extend Throwable."); } return typeSuperSet.contains(RuntimeException.class.getCanonicalName()) || typeName.equals(RuntimeException.class.getCanonicalName()); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeElement.java Thu Mar 21 14:11:13 2013 +0100 @@ -103,6 +103,18 @@ return annotations; } + /* Support JDK8 langtools. */ + @SuppressWarnings("unused") + public A[] getAnnotationsByType(Class annotationType) { + throw new UnsupportedOperationException(); + } + + /* Support for some JDK8 builds. (remove after jdk8 is released) */ + @SuppressWarnings("unused") + public A[] getAnnotations(Class annotationType) { + throw new UnsupportedOperationException(); + } + @Override public A getAnnotation(Class annotationType) { throw new UnsupportedOperationException(); diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java Thu Mar 21 14:11:13 2013 +0100 @@ -59,6 +59,7 @@ } } + /* Support JDK8 langtools. */ public boolean isDefault() { return false; } @@ -113,7 +114,7 @@ } public CodeTreeBuilder createBuilder() { - CodeTreeBuilder builder = new CodeTreeBuilder(); + CodeTreeBuilder builder = new CodeTreeBuilder(null); this.bodyTree = builder.getTree(); this.bodyTree.setEnclosingElement(this); this.body = null; @@ -203,7 +204,7 @@ return v.visitExecutable(this, p); } - public static CodeExecutableElement clone(ProcessingEnvironment env, ExecutableElement method) { + public static CodeExecutableElement clone(@SuppressWarnings("unused") ProcessingEnvironment env, ExecutableElement method) { CodeExecutableElement copy = new CodeExecutableElement(method.getReturnType(), method.getSimpleName().toString()); for (TypeMirror thrownType : method.getThrownTypes()) { copy.addThrownType(thrownType); @@ -219,7 +220,6 @@ for (Element element : method.getEnclosedElements()) { copy.add(element); } - copy.setBody(Utils.getMethodBody(env, method)); copy.getModifiers().addAll(method.getModifiers()); return copy; } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java Thu Mar 21 14:11:13 2013 +0100 @@ -33,17 +33,25 @@ public class CodeTreeBuilder { + private final CodeTreeBuilder parent; + private BuilderCodeTree currentElement; private final BuilderCodeTree root; - public CodeTreeBuilder() { + private int treeCount; + + public CodeTreeBuilder(CodeTreeBuilder parent) { this.root = new BuilderCodeTree(GROUP, null, null); this.currentElement = root; + this.parent = parent; } - public CodeTreeBuilder(CodeTree tree) { - this.root = (BuilderCodeTree) tree; - this.currentElement = root; + public int getTreeCount() { + return treeCount; + } + + public boolean isEmpty() { + return treeCount == 0; } public CodeTreeBuilder statement(String statement) { @@ -55,11 +63,11 @@ } public static CodeTreeBuilder createBuilder() { - return new CodeTreeBuilder(); + return new CodeTreeBuilder(null); } public static CodeTree singleString(String s) { - return new CodeTreeBuilder().string(s).getTree(); + return new CodeTreeBuilder(null).string(s).getTree(); } private CodeTreeBuilder push(CodeTreeKind kind) { @@ -89,11 +97,14 @@ currentElement = tree; break; } + treeCount++; return this; } private void clearLast(CodeTreeKind kind) { - clearLastRec(kind, currentElement.getEnclosedElements()); + if (clearLastRec(kind, currentElement.getEnclosedElements())) { + treeCount--; + } } public CodeTreeBuilder startStatement() { @@ -193,6 +204,24 @@ return this; } + private CodeTreeBuilder startCurlyBracesCommaGroup() { + startGroup(); + string("{").startCommaGroup(); + registerCallBack(new EndCallback() { + + @Override + public void beforeEnd() { + } + + @Override + public void afterEnd() { + string("}"); + } + }); + endAfter(); + return this; + } + public CodeTreeBuilder startParantheses() { startGroup(); string("(").startGroup(); @@ -211,6 +240,10 @@ return this; } + public CodeTreeBuilder doubleQuote(String s) { + return startGroup().string("\"").string(s).string("\"").end(); + } + public CodeTreeBuilder startDoubleQuote() { startGroup().string("\""); registerCallBack(new EndCallback() { @@ -271,6 +304,15 @@ return startGroup().string("if ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter(); } + public boolean startIf(boolean elseIf) { + if (elseIf) { + startElseIf(); + } else { + startIf(); + } + return true; + } + public CodeTreeBuilder startElseIf() { clearLast(CodeTreeKind.NEW_LINE); return startGroup().string(" else if ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter(); @@ -346,6 +388,19 @@ return startStatement().string("assert "); } + public CodeTreeBuilder startNewArray(ArrayType arrayType, CodeTree size) { + startGroup().string("new ").type(arrayType.getComponentType()).string("["); + if (size != null) { + tree(size); + } + string("]"); + if (size == null) { + string(" "); + startCurlyBracesCommaGroup().endAfter(); + } + return this; + } + public CodeTreeBuilder startNew(TypeMirror uninializedNodeClass) { return startGroup().string("new ").type(uninializedNodeClass).startParanthesesCommaGroup().endAfter(); } @@ -358,6 +413,13 @@ return push(CodeTreeKind.INDENT); } + public CodeTreeBuilder end(int times) { + for (int i = 0; i < times; i++) { + end(); + } + return this; + } + public CodeTreeBuilder end() { BuilderCodeTree tree = currentElement; EndCallback callback = tree.getAtEndListener(); @@ -372,9 +434,9 @@ } private void toParent() { - Element parent = currentElement.getEnclosingElement(); + Element parentElement = currentElement.getEnclosingElement(); if (currentElement != root) { - this.currentElement = (BuilderCodeTree) parent; + this.currentElement = (BuilderCodeTree) parentElement; } else { this.currentElement = root; } @@ -433,7 +495,7 @@ } public CodeTreeBuilder create() { - return new CodeTreeBuilder(); + return new CodeTreeBuilder(this); } public CodeTreeBuilder type(TypeMirror type) { @@ -471,7 +533,7 @@ if (Utils.isVoid(type)) { tree(content); return this; - } else if (Utils.getQualifiedName(type).equals("java.lang.Object")) { + } else if (type.getKind() == TypeKind.DECLARED && Utils.getQualifiedName(type).equals("java.lang.Object")) { tree(content); return this; } else { @@ -496,7 +558,11 @@ while (element != null && (element.getKind() != ElementKind.METHOD)) { element = element.getEnclosingElement(); } - return element != null ? (ExecutableElement) element : null; + ExecutableElement found = element != null ? (ExecutableElement) element : null; + if (found == null && parent != null) { + found = parent.findMethod(); + } + return found; } public CodeTreeBuilder returnTrue() { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeVariableElement.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeVariableElement.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeVariableElement.java Thu Mar 21 14:11:13 2013 +0100 @@ -58,7 +58,7 @@ } public CodeTreeBuilder createInitBuilder() { - CodeTreeBuilder builder = new CodeTreeBuilder(); + CodeTreeBuilder builder = new CodeTreeBuilder(null); init = builder.getTree(); init.setEnclosingElement(this); return builder; diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java Thu Mar 21 14:11:13 2013 +0100 @@ -36,9 +36,16 @@ public abstract class AbstractCodeWriter extends CodeElementScanner { + private static final int LINE_LENGTH = 200; + private static final int LINE_WRAP_INDENTS = 3; + private static final String IDENT_STRING = " "; + private static final String LN = "\n"; /* unix style */ + protected Writer writer; private int indent; private boolean newLine; + private int lineLength; + private boolean lineWrapping = false; private OrganizedImports imports; @@ -56,8 +63,7 @@ Writer w = null; try { imports = OrganizedImports.organize(e); - - w = createWriter(e); + w = new TrimTrailingSpaceWriter(createWriter(e)); writer = w; writeRootClass(e); } catch (IOException ex) { @@ -117,6 +123,14 @@ writeClassImpl(e); } + private String useImport(TypeMirror type) { + if (imports != null) { + return imports.useImport(type); + } else { + return Utils.getSimpleName(type); + } + } + private void writeClassImpl(CodeTypeElement e) { for (AnnotationMirror annotation : e.getAnnotationMirrors()) { visitAnnotation(annotation); @@ -131,12 +145,12 @@ } write(e.getSimpleName()); if (e.getSuperclass() != null && !getQualifiedName(e.getSuperclass()).equals("java.lang.Object")) { - write(" extends ").write(typeSimpleName(e.getSuperclass())); + write(" extends ").write(useImport(e.getSuperclass())); } if (e.getImplements().size() > 0) { write(" implements "); for (int i = 0; i < e.getImplements().size(); i++) { - write(typeSimpleName(e.getImplements().get(i))); + write(useImport(e.getImplements().get(i))); if (i < e.getImplements().size() - 1) { write(", "); } @@ -145,7 +159,7 @@ write(" {").writeLn(); writeEmptyLn(); - indent(); + indent(1); List staticFields = getStaticFields(e); List instanceFields = getInstanceFields(e); @@ -191,7 +205,7 @@ clazz.accept(this, null); } - dedent(); + dedent(1); write("}"); writeEmptyLn(); } @@ -261,7 +275,15 @@ } } else { writeModifiers(f.getModifiers()); - write(typeSimpleName(f.asType())); + write(useImport(f.asType())); + + if (f.getEnclosingElement().getKind() == ElementKind.METHOD) { + ExecutableElement method = (ExecutableElement) f.getEnclosingElement(); + if (method.isVarArgs() && method.getParameters().indexOf(f) == method.getParameters().size() - 1) { + write("..."); + } + } + write(" "); write(f.getSimpleName()); if (init != null) { @@ -273,7 +295,7 @@ } public void visitAnnotation(AnnotationMirror e) { - write("@").write(typeSimpleName(e.getAnnotationType())); + write("@").write(useImport(e.getAnnotationType())); if (!e.getElementValues().isEmpty()) { write("("); @@ -381,14 +403,14 @@ @Override public Void visitType(TypeMirror t, Void p) { - write(typeSimpleName(t)); + write(useImport(t)); write(".class"); return null; } @Override public Void visitEnumConstant(VariableElement c, Void p) { - write(typeSimpleName(c.asType())); + write(useImport(c.asType())); write("."); write(c.getSimpleName().toString()); return null; @@ -444,7 +466,7 @@ writeModifiers(e.getModifiers()); if (e.getReturnType() != null) { - write(typeSimpleName(e.getReturnType())); + write(useImport(e.getReturnType())); write(" "); } write(e.getSimpleName()); @@ -463,7 +485,7 @@ if (throwables.size() > 0) { write(" throws "); for (int i = 0; i < throwables.size(); i++) { - write(typeSimpleName(throwables.get(i))); + write(useImport(throwables.get(i))); if (i < throwables.size() - 1) { write(", "); } @@ -474,9 +496,9 @@ writeLn(";"); } else if (e.getBodyTree() != null) { writeLn(" {"); - indent(); + indent(1); e.getBodyTree().acceptCodeElementScanner(this, p); - dedent(); + dedent(1); writeLn("}"); } else if (e.getBody() != null) { write(" {"); @@ -509,11 +531,11 @@ } break; case INDENT: - indent(); + indent(1); for (CodeTree tree : e.getEnclosedElements()) { tree.acceptCodeElementScanner(this, p); } - dedent(); + dedent(1); break; case NEW_LINE: writeLn(); @@ -540,7 +562,7 @@ } break; case TYPE: - write(imports.useImport(e.getType())); + write(useImport(e.getType())); break; default: assert false; @@ -548,10 +570,6 @@ } } - private static String typeSimpleName(TypeMirror type) { - return Utils.getSimpleName(type); - } - protected void writeHeader() { // default implementation does nothing } @@ -565,25 +583,28 @@ } } - private static final String LN = "\n"; - - protected void indent() { - indent++; + protected void indent(int count) { + indent += count; } - protected void dedent() { - indent--; + protected void dedent(int count) { + indent -= count; } protected void writeLn() { - write(LN); - newLine = true; + writeLn(""); } protected void writeLn(String text) { write(text); write(LN); + lineLength = 0; newLine = true; + if (lineWrapping) { + dedent(LINE_WRAP_INDENTS); + lineWrapping = false; + } + lineWrapping = false; } protected void writeEmptyLn() { @@ -596,10 +617,23 @@ private AbstractCodeWriter write(String m) { try { + lineLength += m.length(); if (newLine && m != LN) { writeIndent(); newLine = false; } + if (lineLength > LINE_LENGTH && m.length() > 0) { + char firstChar = m.charAt(0); + if (Character.isAlphabetic(firstChar)) { + if (!lineWrapping) { + indent(LINE_WRAP_INDENTS); + } + lineWrapping = true; + lineLength = 0; + write(LN); + writeIndent(); + } + } writer.write(m); } catch (IOException e) { throw new RuntimeException(e); @@ -609,7 +643,57 @@ private void writeIndent() throws IOException { for (int i = 0; i < indent; i++) { - writer.write(" "); + lineLength += IDENT_STRING.length(); + writer.write(IDENT_STRING); } } + + private static class TrimTrailingSpaceWriter extends Writer { + + private final Writer delegate; + private final StringBuilder buffer = new StringBuilder(); + + public TrimTrailingSpaceWriter(Writer delegate) { + this.delegate = delegate; + } + + @Override + public void close() throws IOException { + this.delegate.close(); + } + + @Override + public void flush() throws IOException { + this.delegate.flush(); + } + + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + buffer.append(cbuf, off, len); + int newLinePoint = buffer.indexOf(LN); + + if (newLinePoint != -1) { + String lhs = trimTrailing(buffer.substring(0, newLinePoint)); + delegate.write(lhs); + delegate.write(LN); + buffer.delete(0, newLinePoint + 1); + } + } + + private static String trimTrailing(String s) { + int cut = 0; + for (int i = s.length() - 1; i >= 0; i--) { + if (Character.isWhitespace(s.charAt(i))) { + cut++; + } else { + break; + } + } + if (cut > 0) { + return s.substring(0, s.length() - cut); + } + return s; + } + } + } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java Thu Mar 21 14:11:13 2013 +0100 @@ -63,19 +63,71 @@ } public String useImport(TypeMirror type) { - String simpleName = getSimpleName(type); - TypeMirror usedByType = simpleNamesUsed.get(type); + switch (type.getKind()) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case SHORT: + case INT: + case LONG: + case VOID: + return Utils.getSimpleName(type); + case DECLARED: + return createDeclaredTypeName((DeclaredType) type); + case ARRAY: + return useImport(((ArrayType) type).getComponentType()) + "[]"; + case WILDCARD: + return createWildcardName((WildcardType) type); + case TYPEVAR: + return "?"; + default: + throw new RuntimeException("Unknown type specified " + type.getKind() + " mirror: " + type); + } + } + + private String createWildcardName(WildcardType type) { + StringBuilder b = new StringBuilder(); + if (type.getExtendsBound() != null) { + b.append("? extends ").append(useImport(type.getExtendsBound())); + } else if (type.getSuperBound() != null) { + b.append("? super ").append(useImport(type.getExtendsBound())); + } + return b.toString(); + } + + private String createDeclaredTypeName(DeclaredType type) { + String name = type.asElement().getSimpleName().toString(); + + TypeMirror usedByType = simpleNamesUsed.get(name); if (usedByType == null) { - simpleNamesUsed.put(simpleName, type); + simpleNamesUsed.put(name, type); usedByType = type; - } else if (!typeEquals(type, usedByType)) { - // we need a qualified name - return getQualifiedName(type); } - // we can use the simple name - addUsage(type, importUsage); - return simpleName; + if (typeEquals(type, usedByType)) { + addUsage(type, importUsage); + } else { + name = getQualifiedName(type); + } + + if (type.getTypeArguments().size() == 0) { + return name; + } + + StringBuilder b = new StringBuilder(name); + b.append("<"); + if (type.getTypeArguments().size() > 0) { + for (int i = 0; i < type.getTypeArguments().size(); i++) { + b.append(useImport(type.getTypeArguments().get(i))); + if (i < type.getTypeArguments().size() - 1) { + b.append(", "); + } + } + } + b.append(">"); + return b.toString(); } public String useStaticFieldImport(TypeMirror type, String fieldName) { @@ -307,6 +359,100 @@ public void visitAnnotation(AnnotationMirror e) { addImport(e.getAnnotationType()); + if (!e.getElementValues().isEmpty()) { + Map values = e.getElementValues(); + Set methodsSet = values.keySet(); + List methodsList = new ArrayList<>(); + for (ExecutableElement method : methodsSet) { + if (values.get(method) == null) { + continue; + } + methodsList.add(method); + } + + for (int i = 0; i < methodsList.size(); i++) { + AnnotationValue value = values.get(methodsList.get(i)); + visitAnnotationValue(value); + } + } + } + + public void visitAnnotationValue(AnnotationValue e) { + e.accept(new AnnotationValueReferenceVisitor(), null); + } + + private class AnnotationValueReferenceVisitor extends AbstractAnnotationValueVisitor7 { + + @Override + public Void visitBoolean(boolean b, Void p) { + return null; + } + + @Override + public Void visitByte(byte b, Void p) { + return null; + } + + @Override + public Void visitChar(char c, Void p) { + return null; + } + + @Override + public Void visitDouble(double d, Void p) { + return null; + } + + @Override + public Void visitFloat(float f, Void p) { + return null; + } + + @Override + public Void visitInt(int i, Void p) { + return null; + } + + @Override + public Void visitLong(long i, Void p) { + return null; + } + + @Override + public Void visitShort(short s, Void p) { + return null; + } + + @Override + public Void visitString(String s, Void p) { + return null; + } + + @Override + public Void visitType(TypeMirror t, Void p) { + addImport(t); + return null; + } + + @Override + public Void visitEnumConstant(VariableElement c, Void p) { + addImport(c.asType()); + return null; + } + + @Override + public Void visitAnnotation(AnnotationMirror a, Void p) { + ReferenceCollector.this.visitAnnotation(a); + return null; + } + + @Override + public Void visitArray(List vals, Void p) { + for (int i = 0; i < vals.size(); i++) { + ReferenceCollector.this.visitAnnotationValue(vals.get(i)); + } + return null; + } } @Override diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/AbstractCompiler.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/AbstractCompiler.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/AbstractCompiler.java Thu Mar 21 14:11:13 2013 +0100 @@ -39,6 +39,9 @@ } protected static Object field(Object o, String fieldName) throws Exception { + if (o == null) { + return null; + } Field field = o.getClass().getField(fieldName); field.setAccessible(true); return field.get(o); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionParser.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionParser.java Thu Mar 21 14:11:13 2013 +0100 @@ -31,6 +31,7 @@ import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.api.*; import com.oracle.truffle.codegen.processor.api.element.*; +import com.oracle.truffle.codegen.processor.template.*; public class ExtensionParser { @@ -45,25 +46,25 @@ this.extensionContext = new ExtensionContextImpl(context.getEnvironment(), null, factory); } - public List parseAll(TypeElement typeElement, List elements) { + public List parseAll(Template template, List elements) { List generatedMethods = new ArrayList<>(); - parseElement(generatedMethods, typeElement); + parseElement(template, generatedMethods, template.getTemplateType()); List methods = ElementFilter.methodsIn(elements); for (ExecutableElement method : methods) { for (VariableElement var : method.getParameters()) { - parseElement(generatedMethods, var); + parseElement(template, generatedMethods, var); } - parseElement(generatedMethods, method); + parseElement(template, generatedMethods, method); } return generatedMethods; } - private void parseElement(List elements, Element element) { + private void parseElement(Template template, List elements, Element element) { List mirrors = element.getAnnotationMirrors(); for (AnnotationMirror mirror : mirrors) { - ExtensionProcessor processor = findProcessor(element, mirror); + ExtensionProcessor processor = findProcessor(template, mirror); if (processor != null) { try { factory.generatorAnnotationMirror = mirror; @@ -71,7 +72,7 @@ processor.process(extensionContext, mirror, element); elements.addAll(extensionContext.returnElements()); } catch (Throwable e) { - context.getLog().error(element, mirror, "Processor for '%s' failed with exception: \n\n%s.", Utils.getQualifiedName(mirror.getAnnotationType()), Utils.printException(e)); + template.addError("Processor for '%s' failed with exception: \n\n%s.", Utils.getQualifiedName(mirror.getAnnotationType()), Utils.printException(e)); } finally { factory.generatorAnnotationMirror = null; factory.generatorElement = null; @@ -80,7 +81,7 @@ } } - private ExtensionProcessor findProcessor(Element element, AnnotationMirror mirror) { + private ExtensionProcessor findProcessor(Template template, AnnotationMirror mirror) { String processorName = Utils.getQualifiedName(mirror.getAnnotationType()); ExtensionProcessor processor = null; if (extensions.containsKey(processorName)) { @@ -88,24 +89,24 @@ } else { AnnotationMirror foundExtension = Utils.findAnnotationMirror(context.getEnvironment(), mirror.getAnnotationType().asElement(), ExtensionAnnotation.class); if (foundExtension != null) { - String className = Utils.getAnnotationValueString(foundExtension, "processorClassName"); + String className = Utils.getAnnotationValue(String.class, foundExtension, "processorClassName"); Class processorClass; try { processorClass = Class.forName(className); } catch (ClassNotFoundException e) { - context.getLog().error(element, mirror, "Could not find processor class '%s' configured in '@%s'.", className, processorName); + template.addError("Could not find processor class '%s' configured in '@%s'.", className, processorName); return null; } try { processor = (ExtensionProcessor) processorClass.newInstance(); } catch (InstantiationException e) { - context.getLog().error(element, mirror, "Could not instantiate processor class '%s' configured in '@%s'.", className, processorName); + template.addError("Could not instantiate processor class '%s' configured in '@%s'.", className, processorName); return null; } catch (IllegalAccessException e) { - context.getLog().error(element, mirror, "Could not access processor class '%s' configured in '@%s'.", className, processorName); + template.addError("Could not access processor class '%s' configured in '@%s'.", className, processorName); return null; } catch (ClassCastException e) { - context.getLog().error(element, mirror, "Processor class '%s' configured in '@%s' does not implement '%s'.", className, processorName, ExtensionProcessor.class.getName()); + template.addError("Processor class '%s' configured in '@%s' does not implement '%s'.", className, processorName, ExtensionProcessor.class.getName()); return null; } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java Thu Mar 21 14:11:13 2013 +0100 @@ -44,14 +44,14 @@ @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { List types = new ArrayList<>(); - types.addAll(Arrays.asList(getNode().getTypeSystem().getPrimitiveTypeMirrors())); + types.addAll(getNode().getTypeSystem().getPrimitiveTypeMirrors()); types.add(getContext().getType(void.class)); - ParameterSpec returnTypeSpec = new ParameterSpec("executedValue", types.toArray(new TypeMirror[types.size()]), getNode().getTypeSystem().getGenericType(), false, Cardinality.ONE); + ParameterSpec returnTypeSpec = new ParameterSpec("executedValue", types, false, Cardinality.ONE); List parameters = new ArrayList<>(); parameters.add(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true)); - return new MethodSpec(returnTypeSpec, parameters); + return new MethodSpec(new ArrayList(), returnTypeSpec, parameters); } @Override @@ -63,9 +63,6 @@ @Override public ExecutableTypeData create(TemplateMethod method) { TypeData resolvedType = method.getReturnType().getActualTypeData(getNode().getTypeSystem()); - if (resolvedType == null) { - return null; - } return new ExecutableTypeData(method, getNode().getTypeSystem(), resolvedType); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java Thu Mar 21 14:11:13 2013 +0100 @@ -23,12 +23,15 @@ package com.oracle.truffle.codegen.processor.node; import java.lang.annotation.*; +import java.util.*; import javax.lang.model.element.*; +import javax.lang.model.type.*; import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.*; public class GenericParser extends MethodParser { @@ -38,17 +41,22 @@ @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - return createDefaultMethodSpec(null); + return createDefaultMethodSpec(method, mirror, null); } @Override - protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData) { - return new ParameterSpec(valueName, nodeData.findGenericExecutableType(getContext()).getType().getPrimitiveType(), false); + protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData, boolean optional) { + List execTypes = nodeData.findGenericExecutableTypes(getContext()); + List types = new ArrayList<>(); + for (ExecutableTypeData type : execTypes) { + types.add(type.getType().getPrimitiveType()); + } + return new ParameterSpec(valueName, types, false, Cardinality.ONE); } @Override protected ParameterSpec createReturnParameterSpec() { - return super.createValueParameterSpec("returnValue", getNode()); + return super.createValueParameterSpec("returnValue", getNode(), false); } @Override diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java Thu Mar 21 14:11:13 2013 +0100 @@ -25,9 +25,10 @@ import java.util.*; import javax.lang.model.element.*; +import javax.lang.model.type.*; import com.oracle.truffle.codegen.processor.*; -import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind; +import com.oracle.truffle.codegen.processor.node.NodeFieldData.*; import com.oracle.truffle.codegen.processor.template.*; import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; @@ -41,12 +42,12 @@ return template; } - protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData) { - return new ParameterSpec(valueName, nodeData, false, Cardinality.ONE); + protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData, boolean optional) { + return new ParameterSpec(valueName, nodeData, optional, Cardinality.ONE); } protected ParameterSpec createReturnParameterSpec() { - return createValueParameterSpec("operation", getNode()); + return createValueParameterSpec("operation", getNode(), false); } @Override @@ -54,10 +55,29 @@ return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null; } - protected final MethodSpec createDefaultMethodSpec(String shortCircuitName) { + @SuppressWarnings("unused") + protected final MethodSpec createDefaultMethodSpec(ExecutableElement method, AnnotationMirror mirror, String shortCircuitName) { List defaultParameters = new ArrayList<>(); - ParameterSpec frameSpec = new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true); - defaultParameters.add(frameSpec); + + if (getNode().supportsFrame()) { + defaultParameters.add(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true)); + } + + TypeMirror declaredType = Utils.findNearestEnclosingType(method).asType(); + + List prefixTypes = new ArrayList<>(); + + if (!method.getModifiers().contains(Modifier.STATIC) && !Utils.isAssignable(declaredType, template.getNodeType())) { + prefixTypes.add(getNode().getTemplateType().asType()); + } + + for (NodeFieldData field : getNode().getFields()) { + if (field.getKind() == FieldKind.FIELD) { + ParameterSpec spec = new ParameterSpec(field.getName(), field.getType(), true); + spec.setLocal(true); + defaultParameters.add(spec); + } + } for (NodeFieldData field : getNode().getFields()) { if (field.getExecutionKind() == ExecutionKind.IGNORE) { @@ -65,7 +85,12 @@ } if (field.getExecutionKind() == ExecutionKind.DEFAULT) { - defaultParameters.add(createValueParameterSpec(field.getName(), field.getNodeData())); + ParameterSpec spec = createValueParameterSpec(field.getName(), field.getNodeData(), false); + if (field.getKind() == FieldKind.CHILDREN) { + spec.setCardinality(Cardinality.MULTIPLE); + spec.setIndexed(true); + } + defaultParameters.add(spec); } else if (field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) { String valueName = field.getName(); if (shortCircuitName != null && valueName.equals(shortCircuitName)) { @@ -73,14 +98,13 @@ } defaultParameters.add(new ParameterSpec(shortCircuitValueName(valueName), getContext().getType(boolean.class), false)); - - defaultParameters.add(createValueParameterSpec(valueName, field.getNodeData())); + defaultParameters.add(createValueParameterSpec(valueName, field.getNodeData(), false)); } else { assert false; } } - return new MethodSpec(createReturnParameterSpec(), defaultParameters); + return new MethodSpec(prefixTypes, createReturnParameterSpec(), defaultParameters); } private static String shortCircuitValueName(String valueName) { diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Thu Mar 21 14:11:13 2013 +0100 @@ -31,9 +31,11 @@ import javax.lang.model.type.*; import javax.lang.model.util.*; +import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.ast.*; import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind; +import com.oracle.truffle.codegen.processor.node.NodeFieldData.FieldKind; import com.oracle.truffle.codegen.processor.template.*; import com.oracle.truffle.codegen.processor.typesystem.*; @@ -50,64 +52,49 @@ } private static String factoryClassName(NodeData node) { - return nodeClassName(node) + "Factory"; - } - - private static String nodeClassName(NodeData node) { - return Utils.getSimpleName(node.getTemplateType().asType()); + return node.getNodeId() + "Factory"; } - private static String nodeClassName(SpecializationData specialization) { - String name = specializationId(specialization); - name += nodeClassName(specialization.getNode()); - if (name.equals(Utils.getSimpleName(specialization.getNode().getNodeType())) || name.equals(Utils.getSimpleName(specialization.getNode().getTemplateType()))) { - name = name + "Impl"; + private static String nodeSpecializationClassName(SpecializationData specialization) { + String nodeid = specialization.getNode().getNodeId(); + if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { + nodeid = nodeid.substring(0, nodeid.length() - 4); } + String name = Utils.firstLetterUpperCase(nodeid); + name += Utils.firstLetterUpperCase(specialization.getId()); + name += "Node"; return name; } - private static String specializationId(SpecializationData specialization) { - String name = ""; - if (specialization.getNode().getSpecializations().length > 1) { - name = specialization.getMethodName(); - if (name.startsWith("do")) { - name = name.substring(2); - } - } - return name; + private static String valueName(ActualParameter param) { + return param.getLocalName(); } - private static String valueName(NodeFieldData field) { - return field.getName() + "Value"; + private static String castValueName(ActualParameter parameter) { + return valueName(parameter) + "Cast"; } - private static String valueName(TemplateMethod method, ActualParameter param) { - NodeData node = (NodeData) method.getTemplate(); - NodeFieldData field = node.findField(param.getSpecification().getName()); - if (field != null) { - return valueName(field); - } else { - return param.getSpecification().getName(); - } - } - - private void addValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame) { - if (forceFrame) { - method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frame")); + private void addInternalValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame) { + if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { + method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue")); } for (ActualParameter parameter : specialization.getParameters()) { ParameterSpec spec = parameter.getSpecification(); if (forceFrame && spec.getName().equals("frame")) { continue; } - method.addParameter(new CodeVariableElement(parameter.getActualType(), valueName(specialization, parameter))); + if (spec.isLocal()) { + continue; + } + + method.addParameter(new CodeVariableElement(parameter.getActualType(), valueName(parameter))); } } - private static void addValueParameterNames(CodeTreeBuilder builder, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame) { - if (forceFrame) { - builder.string("frame"); + private static void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, boolean includeImplicit) { + if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { + builder.string("frameValue"); } for (ActualParameter parameter : specialization.getParameters()) { ParameterSpec spec = parameter.getSpecification(); @@ -115,57 +102,137 @@ continue; } - if (unexpectedValueName != null && spec.getName().equals(unexpectedValueName)) { - builder.string("ex.getResult()"); + if (!includeImplicit && (parameter.isImplicit())) { + continue; + } + if (parameter.getSpecification().isLocal()) { + continue; + } + + if (unexpectedValueName != null && parameter.getLocalName().equals(unexpectedValueName)) { + builder.cast(parameter.getActualType(), CodeTreeBuilder.singleString("ex.getResult()")); } else { - builder.string(valueName(specialization, parameter)); + builder.string(valueName(parameter)); } } } - private static void addValueParameterNamesWithCasts(ProcessorContext context, CodeTreeBuilder body, SpecializationData specialization) { - for (ActualParameter param : specialization.getParameters()) { - TypeData typeData = param.getActualTypeData(specialization.getNode().getTypeSystem()); - if (typeData == null || typeData.isGeneric()) { - body.string(valueName(specialization, param)); + private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, TemplateMethod target, TemplateMethod sourceMethod, TemplateMethod castMethod, String unexpectedValueName) { + CodeTreeBuilder builder = parent.create(); + + boolean castedValues = sourceMethod != castMethod; + + builder.startGroup(); + ExecutableElement method = target.getMethod(); + if (method == null) { + throw new IllegalStateException("Cannot call synthtetic operation methods."); + } + TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement()); + NodeData node = (NodeData) castMethod.getTemplate(); + TypeSystemData typeSystem = node.getTypeSystem(); + + boolean accessible = target.canBeAccessedByInstanceOf(node.getNodeType()); + if (accessible) { + if (builder.findMethod().getModifiers().contains(STATIC)) { + builder.string(THIS_NODE_LOCAL_VAR_NAME); + } else { + builder.string("super"); + } + } else { + if (method.getModifiers().contains(STATIC)) { + builder.type(targetClass.asType()); } else { - String methodName = TypeSystemCodeGenerator.asTypeMethodName(typeData); - startCallTypeSystemMethod(context, body, specialization.getNode(), methodName); - body.string(valueName(specialization, param)); - body.end().end(); + ActualParameter parameter = null; + for (ActualParameter searchParameter : target.getParameters()) { + if (!searchParameter.getSpecification().isOptional()) { + parameter = searchParameter; + break; + } + } + assert parameter != null; + + if (castedValues) { + NodeFieldData field = node.findField(parameter.getSpecification().getName()); + if (field == null) { + builder.string(valueName(parameter)); + } else { + NodeData fieldNode = field.getNodeData(); + ExecutableTypeData execType = fieldNode.findExecutableType(parameter.getActualTypeData(node.getTypeSystem())); + if (execType.hasUnexpectedValue(getContext())) { + builder.string(castValueName(parameter)); + } else { + builder.string(valueName(parameter)); + } + } + } else { + builder.string(valueName(parameter)); + } } } + builder.string("."); + builder.startCall(method.getSimpleName().toString()); + + for (ActualParameter targetParameter : castMethod.getParameters()) { + ActualParameter valueParameter = sourceMethod.findParameter(targetParameter.getLocalName()); + if (valueParameter == null) { + continue; + } + TypeData targetType = targetParameter.getActualTypeData(typeSystem); + + if (targetParameter.isImplicit() || valueParameter.isImplicit()) { + continue; + } + + TypeData valueType = null; + if (valueParameter != null) { + valueType = valueParameter.getActualTypeData(typeSystem); + } + + if (targetParameter.getSpecification().isLocal()) { + builder.startGroup(); + if (builder.findMethod().getModifiers().contains(Modifier.STATIC)) { + builder.string(THIS_NODE_LOCAL_VAR_NAME).string("."); + } else { + builder.string("this."); + } + builder.string(targetParameter.getSpecification().getName()); + builder.end(); + } else if (unexpectedValueName != null && targetParameter.getLocalName().equals(unexpectedValueName)) { + builder.string("ex.getResult()"); + } else if (targetType == null || targetType.isGeneric() || (valueType != null && valueType.equalsType(targetType))) { + builder.string(valueName(targetParameter)); + } else { + builder.string(castValueName(targetParameter)); + } + } + + builder.end().end(); + + return builder.getRoot(); } private static String genClassName(Template operation) { return getSimpleName(operation.getTemplateType()) + "Gen"; } - private static void startCallOperationMethod(CodeTreeBuilder body, TemplateMethod method) { - body.startGroup(); - if (body.findMethod().getModifiers().contains(STATIC)) { - body.string(THIS_NODE_LOCAL_VAR_NAME); - } else { - body.string("super"); - } - body.string("."); - body.startCall(method.getMethodName()); - } - - private static String generatedGenericMethodName(SpecializationData specialization) { + private String generatedGenericMethodName(SpecializationData specialization) { final String prefix = "generic"; if (specialization == null) { return prefix; } + if (!specialization.getNode().needsRewrites(context)) { + return prefix; + } + SpecializationData prev = null; for (SpecializationData current : specialization.getNode().getSpecializations()) { if (specialization == current) { if (prev == null || prev.isUninitialized()) { return prefix; } else { - return prefix + specializationId(current); + return prefix + current.getId(); } } prev = current; @@ -173,6 +240,14 @@ return prefix; } + private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, String value) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + startCallTypeSystemMethod(context, builder, node, methodName); + builder.string(value); + builder.end().end(); + return builder.getRoot(); + } + private static void startCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder body, NodeData node, String methodName) { VariableElement singleton = TypeSystemCodeGenerator.findSingleton(context, node.getTypeSystem()); assert singleton != null; @@ -182,42 +257,205 @@ body.string(".").startCall(methodName); } - private static void emitGuards(ProcessorContext context, CodeTreeBuilder body, String prefix, SpecializationData specialization, boolean onSpecialization, boolean needsCast) { - TypeSystemData typeSystem = specialization.getNode().getTypeSystem(); - // Implict guards based on method signature - String andOperator = prefix; - for (NodeFieldData field : specialization.getNode().getFields()) { - ActualParameter param = specialization.findParameter(field.getName()); - TypeData type = param.getActualTypeData(typeSystem); - if (type == null || type.isGeneric()) { - continue; - } + private CodeTree createGuardAndCast(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, boolean onSpecialization, + CodeTree guardedStatements, CodeTree elseStatements) { + + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + CodeTree implicitGuards = createImplicitGuards(parent, conditionPrefix, valueSpecialization, guardedSpecialization); + CodeTree explicitGuards = createExplicitGuards(parent, implicitGuards == null ? conditionPrefix : null, valueSpecialization, guardedSpecialization, onSpecialization); + + int ifCount = 0; - body.string(andOperator); - startCallTypeSystemMethod(context, body, specialization.getNode(), TypeSystemCodeGenerator.isTypeMethodName(type)); - body.string(valueName(specialization, param)); - body.end().end(); // call - andOperator = " && "; + if (implicitGuards != null) { + builder.startIf(); + builder.tree(implicitGuards); + builder.end(); + builder.startBlock(); + ifCount++; + } + + if (explicitGuards != null || !onSpecialization) { + builder.tree(createCasts(parent, valueSpecialization, guardedSpecialization)); } - if (specialization.getGuards().length > 0) { - // Explicitly specified guards - for (SpecializationGuardData guard : specialization.getGuards()) { - if ((guard.isOnSpecialization() && onSpecialization) || (guard.isOnExecution() && !onSpecialization)) { - body.string(andOperator); + if (explicitGuards != null) { + builder.startIf(); + builder.tree(explicitGuards); + builder.end(); + builder.startBlock(); + ifCount++; + } + + if (implicitGuards == null && explicitGuards == null && conditionPrefix != null && !conditionPrefix.isEmpty()) { + builder.startIf(); + builder.string(conditionPrefix); + builder.end().startBlock(); + ifCount++; + } + + builder.tree(guardedStatements); - startCallOperationMethod(body, guard.getGuardDeclaration()); + builder.end(ifCount); + if (elseStatements != null && ifCount > 0) { + builder.tree(elseStatements); + } + return builder.getRoot(); + } - if (needsCast) { - addValueParameterNamesWithCasts(context, body, specialization); - } else { - addValueParameterNames(body, specialization, null, false); - } - body.end().end(); // call + private CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, boolean onSpecialization) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; + if (guardedSpecialization.getGuards().size() > 0) { + // Explicitly specified guards + for (SpecializationGuardData guard : guardedSpecialization.getGuards()) { + if ((guard.isOnSpecialization() && onSpecialization) || (guard.isOnExecution() && !onSpecialization)) { + builder.string(andOperator); + builder.tree(createTemplateMethodCall(parent, guard.getGuardDeclaration(), valueSpecialization, guardedSpecialization, null)); andOperator = " && "; } } } + + return builder.isEmpty() ? null : builder.getRoot(); + } + + private CodeTree createCasts(CodeTreeBuilder parent, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + // Implict guards based on method signature + for (ActualParameter guardedParam : guardedSpecialization.getParameters()) { + NodeFieldData field = guardedSpecialization.getNode().findField(guardedParam.getSpecification().getName()); + if (field == null || field.getKind() == FieldKind.FIELD) { + continue; + } + ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName()); + + CodeTree cast = createCast(parent, field, valueParam, guardedParam); + if (cast == null) { + continue; + } + builder.tree(cast); + } + + return builder.getRoot(); + } + + private CodeTree createImplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + // Implict guards based on method signature + String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; + for (ActualParameter guardedParam : guardedSpecialization.getParameters()) { + NodeFieldData field = guardedSpecialization.getNode().findField(guardedParam.getSpecification().getName()); + if (field == null || field.getKind() == FieldKind.FIELD) { + continue; + } + ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName()); + + CodeTree implicitGuard = createImplicitGuard(builder, field, valueParam, guardedParam); + if (implicitGuard == null) { + continue; + } + + builder.string(andOperator); + builder.tree(implicitGuard); + andOperator = " && "; + } + + return builder.isEmpty() ? null : builder.getRoot(); + } + + private CodeTree createImplicitGuard(CodeTreeBuilder parent, NodeFieldData field, ActualParameter source, ActualParameter target) { + NodeData node = field.getNodeData(); + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + + TypeData targetType = target.getActualTypeData(node.getTypeSystem()); + TypeData sourceType = source.getActualTypeData(node.getTypeSystem()); + + if (targetType.equalsType(sourceType) || targetType.isGeneric()) { + return null; + } + + builder.startGroup(); + + if (field.isShortCircuit()) { + ActualParameter shortCircuit = target.getPreviousParameter(); + assert shortCircuit != null; + builder.string("("); + builder.string("!").string(valueName(shortCircuit)); + builder.string(" || "); + } + + startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(target.getActualTypeData(node.getTypeSystem()))); + builder.string(valueName(source)); + builder.end().end(); // call + + if (field.isShortCircuit()) { + builder.string(")"); + } + + builder.end(); // group + + return builder.getRoot(); + } + + private CodeTree createCast(CodeTreeBuilder parent, NodeFieldData field, ActualParameter source, ActualParameter target) { + NodeData node = field.getNodeData(); + TypeSystemData typeSystem = node.getTypeSystem(); + + TypeData sourceType = source.getActualTypeData(typeSystem); + TypeData targetType = target.getActualTypeData(typeSystem); + + if (targetType.equalsType(sourceType) || targetType.isGeneric()) { + return null; + } + + CodeTree condition = null; + if (field.isShortCircuit()) { + ActualParameter shortCircuit = target.getPreviousParameter(); + assert shortCircuit != null; + condition = CodeTreeBuilder.singleString(valueName(shortCircuit)); + } + + CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), valueName(target)); + + return createLazyAssignment(parent, castValueName(target), target.getActualType(), condition, value); + } + + /** + *
+     * variant1 $condition != null
+     * 
+     * $type $name = defaultValue($type);
+     * if ($condition) {
+     *     $name = $value;
+     * }
+     * 
+     * variant2 $condition != null
+     * $type $name = $value;
+     * 
+ * + * . + */ + private static CodeTree createLazyAssignment(CodeTreeBuilder parent, String name, TypeMirror type, CodeTree condition, CodeTree value) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + if (condition == null) { + builder.declaration(type, name, value); + } else { + builder.declaration(type, name, new CodeTreeBuilder(parent).defaultValue(type).getRoot()); + + builder.startIf().tree(condition).end(); + builder.startBlock(); + builder.startStatement(); + builder.string(name); + builder.string(" = "); + builder.tree(value); + builder.end(); // statement + builder.end(); // block + } + return builder.getRoot(); + } + + private void emitEncounteredSynthetic(CodeTreeBuilder builder) { + builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end(); } @Override @@ -235,11 +473,7 @@ add(factory, node); } - if (node.getSpecializations() == null) { - return; - } - - if (node.needsFactory() || childTypes.size() > 0) { + if (node.needsFactory() || node.getNodeChildren().size() > 0) { add(new NodeFactoryFactory(context, childTypes), node); } } @@ -308,13 +542,15 @@ if (node.needsFactory()) { createFactoryMethods(node, clazz, createVisibility); - if (node.getSpecializations().length > 1) { + if (node.getSpecializations().size() > 1) { clazz.add(createCreateSpecializedMethod(node, createVisibility)); } - if (node.needsRewrites(getContext())) { + if (node.needsRewrites(context)) { clazz.add(createSpecializeMethod(node)); + } + if (node.getGenericSpecialization() != null) { List genericMethods = createGeneratedGenericMethod(node); for (CodeExecutableElement method : genericMethods) { clazz.add(method); @@ -324,6 +560,16 @@ for (SpecializationData specialization : node.getSpecializations()) { add(new SpecializedNodeFactory(context), specialization); } + + TypeMirror nodeFactory = getContext().getEnvironment().getTypeUtils().getDeclaredType(Utils.fromTypeMirror(getContext().getType(NodeFactory.class)), node.getNodeType()); + clazz.getImplements().add(nodeFactory); + clazz.add(createCreateNodeMethod(node)); + clazz.add(createCreateNodeSpecializedMethod(node)); + clazz.add(createGetNodeClassMethod(node)); + clazz.add(createGetNodeSignaturesMethod(node)); + clazz.add(createGetChildrenSignatureMethod(node)); + clazz.add(createGetInstanceMethod(node, createVisibility)); + clazz.add(createInstanceConstant(node, clazz.asType())); } for (NodeData childNode : childTypes.keySet()) { @@ -344,9 +590,283 @@ clazz.add(type); } } + + List children = node.getNodeChildren(); + if (node.getParent() == null && children.size() > 0) { + clazz.add(createGetFactories(node)); + } + + } + + private CodeExecutableElement createGetNodeClassMethod(NodeData node) { + Types types = getContext().getEnvironment().getTypeUtils(); + TypeMirror returnType = types.getDeclaredType(Utils.fromTypeMirror(getContext().getType(Class.class)), node.getNodeType()); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getNodeClass"); + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn().typeLiteral(node.getNodeType()).end(); + return method; + } + + private CodeExecutableElement createGetNodeSignaturesMethod(NodeData node) { + Types types = getContext().getEnvironment().getTypeUtils(); + TypeElement listType = Utils.fromTypeMirror(getContext().getType(List.class)); + TypeMirror classType = getContext().getType(Class.class); + TypeMirror returnType = types.getDeclaredType(listType, types.getDeclaredType(listType, classType)); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getNodeSignatures"); + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn(); + builder.startStaticCall(getContext().getType(Arrays.class), "asList"); + List constructors = findUserConstructors(node); + for (ExecutableElement constructor : constructors) { + builder.tree(createAsList(builder, Utils.asTypeMirrors(constructor.getParameters()), classType)); + } + builder.end(); + builder.end(); + return method; + } + + private CodeExecutableElement createGetChildrenSignatureMethod(NodeData node) { + Types types = getContext().getEnvironment().getTypeUtils(); + TypeElement listType = Utils.fromTypeMirror(getContext().getType(List.class)); + TypeMirror classType = getContext().getType(Class.class); + TypeMirror nodeType = getContext().getTruffleTypes().getNode(); + TypeMirror wildcardNodeType = types.getWildcardType(nodeType, null); + classType = types.getDeclaredType(Utils.fromTypeMirror(classType), wildcardNodeType); + TypeMirror returnType = types.getDeclaredType(listType, classType); + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getExecutionSignature"); + CodeTreeBuilder builder = method.createBuilder(); + + List signatureTypes = new ArrayList<>(); + assert !node.getSpecializations().isEmpty(); + SpecializationData data = node.getSpecializations().get(0); + for (ActualParameter parameter : data.getParameters()) { + ParameterSpec spec = parameter.getSpecification(); + NodeFieldData field = node.findField(spec.getName()); + if (field == null || field.getKind() == FieldKind.FIELD) { + continue; + } + + TypeMirror type; + if (field.getKind() == FieldKind.CHILDREN && field.getType().getKind() == TypeKind.ARRAY) { + type = ((ArrayType) field.getType()).getComponentType(); + } else { + type = field.getType(); + } + + signatureTypes.add(type); + } + + builder.startReturn().tree(createAsList(builder, signatureTypes, classType)).end(); + return method; + } + + private CodeTree createAsList(CodeTreeBuilder parent, List types, TypeMirror elementClass) { + CodeTreeBuilder builder = parent.create(); + builder.startGroup(); + builder.type(getContext().getType(Arrays.class)); + builder.string(".<").type(elementClass).string(">"); + builder.startCall("asList"); + for (TypeMirror typeMirror : types) { + builder.typeLiteral(typeMirror); + } + builder.end().end(); + return builder.getRoot(); + } + + private CodeExecutableElement createCreateNodeMethod(NodeData node) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNode"); + CodeVariableElement arguments = new CodeVariableElement(getContext().getType(Object.class), "arguments"); + method.setVarArgs(true); + method.addParameter(arguments); + + CodeTreeBuilder builder = method.createBuilder(); + List signatures = findUserConstructors(node); + boolean ifStarted = false; + + for (ExecutableElement element : signatures) { + ifStarted = builder.startIf(ifStarted); + builder.string("arguments.length == " + element.getParameters().size()); + + int index = 0; + for (VariableElement param : element.getParameters()) { + builder.string(" && "); + if (!param.asType().getKind().isPrimitive()) { + builder.string("(arguments[" + index + "] == null || "); + } + builder.string("arguments[" + index + "] instanceof "); + builder.type(Utils.boxType(getContext(), param.asType())); + if (!param.asType().getKind().isPrimitive()) { + builder.string(")"); + } + index++; + } + builder.end(); + builder.startBlock(); + + builder.startReturn().startCall("create"); + index = 0; + for (VariableElement param : element.getParameters()) { + builder.startGroup(); + builder.string("(").type(param.asType()).string(") "); + builder.string("arguments[").string(String.valueOf(index)).string("]"); + builder.end(); + index++; + } + builder.end().end(); + + builder.end(); // block + } + + builder.startElseBlock(); + builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)); + builder.doubleQuote("Invalid create signature."); + builder.end().end(); + builder.end(); // else block + return method; + } + + private CodeExecutableElement createCreateNodeSpecializedMethod(NodeData node) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNodeSpecialized"); + CodeVariableElement nodeParam = new CodeVariableElement(node.getNodeType(), "thisNode"); + CodeVariableElement arguments = new CodeVariableElement(getContext().getType(Class.class), "types"); + method.addParameter(nodeParam); + method.addParameter(arguments); + method.setVarArgs(true); + + CodeTreeBuilder builder = method.createBuilder(); + if (!node.needsRewrites(getContext())) { + builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end(); + } else { + builder.startIf(); + builder.string("types.length == 1"); + builder.end(); + builder.startBlock(); + + builder.startReturn().startCall("createSpecialized"); + builder.string("thisNode"); + builder.string("types[0]"); + builder.end().end(); + + builder.end(); + builder.startElseBlock(); + builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)); + builder.doubleQuote("Invalid createSpecialized signature."); + builder.end().end(); + builder.end(); + } + + return method; + } + + private ExecutableElement createGetInstanceMethod(NodeData node, Modifier visibility) { + Types types = getContext().getEnvironment().getTypeUtils(); + TypeElement nodeFactoryType = Utils.fromTypeMirror(getContext().getType(NodeFactory.class)); + TypeMirror returnType = types.getDeclaredType(nodeFactoryType, node.getNodeType()); + + CodeExecutableElement method = new CodeExecutableElement(modifiers(), returnType, "getInstance"); + if (visibility != null) { + method.getModifiers().add(visibility); + } + method.getModifiers().add(Modifier.STATIC); + + String varName = instanceVarName(node); + + CodeTreeBuilder builder = method.createBuilder(); + builder.startIf(); + builder.string(varName).string(" == null"); + builder.end().startBlock(); + + builder.startStatement(); + builder.string(varName); + builder.string(" = "); + builder.startNew(factoryClassName(node)).end(); + builder.end(); + + builder.end(); + builder.startReturn().string(varName).end(); + return method; + } + + private String instanceVarName(NodeData node) { + if (node.getParent() != null) { + return Utils.firstLetterLowerCase(factoryClassName(node)) + "Instance"; + } else { + return "instance"; + } + } + + private CodeVariableElement createInstanceConstant(NodeData node, TypeMirror factoryType) { + String varName = instanceVarName(node); + CodeVariableElement var = new CodeVariableElement(modifiers(), factoryType, varName); + var.getModifiers().add(Modifier.PRIVATE); + var.getModifiers().add(Modifier.STATIC); + return var; + } + + private ExecutableElement createGetFactories(NodeData node) { + List children = node.getNodeChildren(); + if (node.needsFactory()) { + children.add(node); + } + + List nodeTypesList = new ArrayList<>(); + TypeMirror prev = null; + boolean allSame = true; + for (NodeData child : children) { + nodeTypesList.add(child.getNodeType()); + if (prev != null && !Utils.typeEquals(child.getNodeType(), prev)) { + allSame = false; + } + prev = child.getNodeType(); + } + TypeMirror commonNodeSuperType = Utils.getCommonSuperType(getContext(), nodeTypesList.toArray(new TypeMirror[nodeTypesList.size()])); + + Types types = getContext().getEnvironment().getTypeUtils(); + TypeMirror factoryType = getContext().getType(NodeFactory.class); + TypeMirror baseType; + if (allSame) { + baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), commonNodeSuperType); + } else { + baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null)); + } + TypeMirror listType = types.getDeclaredType(Utils.fromTypeMirror(getContext().getType(List.class)), baseType); + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), listType, "getFactories"); + + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn(); + builder.startStaticCall(getContext().getType(Arrays.class), "asList"); + + for (NodeData child : children) { + builder.startGroup(); + NodeData childNode = child; + List factories = new ArrayList<>(); + while (childNode.getParent() != null) { + factories.add(childNode); + childNode = childNode.getParent(); + } + Collections.reverse(factories); + for (NodeData nodeData : factories) { + builder.string(factoryClassName(nodeData)).string("."); + } + builder.string("getInstance()"); + builder.end(); + } + builder.end(); + builder.end(); + return method; } private void createFactoryMethods(NodeData node, CodeTypeElement clazz, Modifier createVisibility) { + List constructors = findUserConstructors(node); + for (ExecutableElement constructor : constructors) { + clazz.add(createCreateMethod(node, createVisibility, constructor)); + } + } + + private List findUserConstructors(NodeData node) { + List constructors = new ArrayList<>(); for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(node.getNodeType()).getEnclosedElements())) { if (constructor.getModifiers().contains(PRIVATE)) { continue; @@ -356,9 +876,9 @@ if (constructor.getParameters().size() == 1 && typeEquals(constructor.getParameters().get(0).asType(), node.getNodeType())) { continue; } - - clazz.add(createCreateMethod(node, createVisibility, constructor)); + constructors.add(constructor); } + return constructors; } private CodeExecutableElement createCreateMethod(NodeData node, Modifier visibility, ExecutableElement constructor) { @@ -373,10 +893,10 @@ CodeTreeBuilder body = method.createBuilder(); body.startReturn(); - if (node.getSpecializations().length == 0) { + if (node.getSpecializations().isEmpty()) { body.null_(); } else { - body.startNew(nodeClassName(node.getSpecializations()[0])); + body.startNew(nodeSpecializationClassName(node.getSpecializations().get(0))); for (VariableElement var : method.getParameters()) { body.string(var.getSimpleName().toString()); } @@ -408,14 +928,14 @@ body.startElseIf(); } body.string("specializationClass == ").type(type.getBoxedType()).string(".class").end().startBlock(); - body.startReturn().startNew(nodeClassName(specialization)); + body.startReturn().startNew(nodeSpecializationClassName(specialization)); body.string(THIS_NODE_LOCAL_VAR_NAME); body.end().end(); // new, return body.end(); // if } } - body.startReturn().startNew(nodeClassName(node.getGenericSpecialization())); + body.startReturn().startNew(nodeSpecializationClassName(node.getGenericSpecialization())); body.string(THIS_NODE_LOCAL_VAR_NAME); body.end().end(); return method; @@ -425,26 +945,21 @@ CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), node.getNodeType(), "specialize"); method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); - addValueParameters(method, node.getGenericSpecialization(), false); + addInternalValueParameters(method, node.getGenericSpecialization(), false); CodeTreeBuilder body = method.createBuilder(); - body.startStatement().string("boolean allowed = (minimumState == ").string(nodeClassName(node.getSpecializations()[0])).string(".class)").end(); + body.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end(); - for (int i = 1; i < node.getSpecializations().length; i++) { - SpecializationData specialization = node.getSpecializations()[i]; - body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeClassName(specialization)).string(".class)").end(); + for (int i = 1; i < node.getSpecializations().size(); i++) { + SpecializationData specialization = node.getSpecializations().get(i); + body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(specialization)).string(".class)").end(); - if (specialization.isGeneric()) { - body.startIf().string("allowed").end().startBlock(); - } else { - body.startIf().string("allowed"); - emitGuards(getContext(), body, " && ", specialization, true, true); - body.end().startBlock(); - } - body.startReturn().startNew(nodeClassName(specialization)); - body.string(THIS_NODE_LOCAL_VAR_NAME); - body.end().end(); - body.end(); // block + CodeTreeBuilder guarded = new CodeTreeBuilder(body); + guarded.startReturn().startNew(nodeSpecializationClassName(specialization)); + guarded.string(THIS_NODE_LOCAL_VAR_NAME); + guarded.end().end(); + + body.tree(createGuardAndCast(body, "allowed", node.getGenericSpecialization(), specialization, true, guarded.getRoot(), null)); } body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end(); @@ -453,14 +968,14 @@ private List createGeneratedGenericMethod(NodeData node) { TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getActualType(); - if (node.getGenericSpecialization().isUseSpecializationsForGeneric()) { + if (node.needsRewrites(context)) { List methods = new ArrayList<>(); - SpecializationData[] specializations = node.getSpecializations(); + List specializations = node.getSpecializations(); SpecializationData prev = null; - for (int i = 0; i < specializations.length; i++) { - SpecializationData current = specializations[i]; - SpecializationData next = i + 1 < specializations.length ? specializations[i + 1] : null; + for (int i = 0; i < specializations.size(); i++) { + SpecializationData current = specializations.get(i); + SpecializationData next = i + 1 < specializations.size() ? specializations.get(i + 1) : null; if (prev == null || current.isUninitialized()) { prev = current; continue; @@ -468,7 +983,7 @@ String methodName = generatedGenericMethodName(current); CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, methodName); method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); - addValueParameters(method, node.getGenericSpecialization(), true); + addInternalValueParameters(method, node.getGenericSpecialization(), true); emitGeneratedGenericSpecialization(method.createBuilder(), current, next); @@ -481,57 +996,61 @@ } else { CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, generatedGenericMethodName(null)); method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); - addValueParameters(method, node.getGenericSpecialization(), true); + addInternalValueParameters(method, node.getGenericSpecialization(), true); emitInvokeDoMethod(method.createBuilder(), node.getGenericSpecialization(), 0); return Arrays.asList(method); } } private void emitGeneratedGenericSpecialization(CodeTreeBuilder builder, SpecializationData current, SpecializationData next) { - if (next != null) { - builder.startIf(); - emitGuards(context, builder, "", current, false, true); - builder.end().startBlock(); - } - - emitInvokeDoMethod(builder, current, 0); + CodeTreeBuilder invokeMethodBuilder = new CodeTreeBuilder(builder); + emitInvokeDoMethod(invokeMethodBuilder, current, 0); + CodeTree invokeMethod = invokeMethodBuilder.getRoot(); if (next != null) { - builder.end(); - builder.startElseBlock(); + CodeTreeBuilder nextBuilder = builder.create(); + + nextBuilder.startReturn().startCall(generatedGenericMethodName(next)); + nextBuilder.string(THIS_NODE_LOCAL_VAR_NAME); + addInternalValueParameterNames(nextBuilder, next, null, true, true); + nextBuilder.end().end(); - builder.startReturn().startCall(generatedGenericMethodName(next)); - builder.string(THIS_NODE_LOCAL_VAR_NAME); - addValueParameterNames(builder, next, null, true); - builder.end().end(); + invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, false, invokeMethod, nextBuilder.getRoot()); + } + builder.tree(invokeMethod); + + if (next != null) { builder.end(); } } private void emitInvokeDoMethod(CodeTreeBuilder builder, SpecializationData specialization, int level) { - if (specialization.getExceptions().length > 0) { + if (!specialization.getExceptions().isEmpty()) { builder.startTryBlock(); } - builder.startReturn(); - startCallOperationMethod(builder, specialization); - addValueParameterNamesWithCasts(context, builder, specialization); - builder.end().end(); // start call operation - builder.end(); // return + if (specialization.getMethod() == null) { + emitEncounteredSynthetic(builder); + } else { + builder.startReturn(); + builder.tree(createTemplateMethodCall(builder, specialization, specialization.getNode().getGenericSpecialization(), specialization, null)); + builder.end(); // return + } - if (specialization.getExceptions().length > 0) { + if (!specialization.getExceptions().isEmpty()) { for (SpecializationThrowsData exception : specialization.getExceptions()) { builder.end().startCatchBlock(exception.getJavaClass(), "ex" + level); builder.startReturn().startCall(generatedGenericMethodName(exception.getTransitionTo())); builder.string(THIS_NODE_LOCAL_VAR_NAME); - addValueParameterNames(builder, exception.getTransitionTo(), null, true); + addInternalValueParameterNames(builder, exception.getTransitionTo(), null, true, true); builder.end().end(); } builder.end(); } } + } private class SpecializedNodeFactory extends ClassElementFactory { @@ -543,7 +1062,7 @@ @Override public CodeTypeElement create(SpecializationData specialization) { NodeData node = specialization.getNode(); - CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeClassName(specialization), node.getNodeType(), false); + CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), node.getNodeType(), false); return clazz; } @@ -567,7 +1086,7 @@ CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod()); if (method.getParameters().size() == 1) { CodeVariableElement var = CodeVariableElement.clone(method.getParameters().get(0)); - var.setName("frame"); + var.setName("frameValue"); method.getParameters().set(0, var); } method.getModifiers().remove(Modifier.ABSTRACT); @@ -582,7 +1101,7 @@ } if (node.needsRewrites(getContext()) && !specialization.isGeneric() && !specialization.isUninitialized()) { - buildSpecializeStateMethod(clazz, specialization); + buildSpecializeAndExecute(clazz, specialization); } } @@ -600,7 +1119,7 @@ CodeTree primaryExecuteCall = null; CodeTreeBuilder executeBuilder = CodeTreeBuilder.createBuilder(); - buildExecute(executeBuilder, null, execType); + buildExecute(executeBuilder, null, null, execType); primaryExecuteCall = executeBuilder.getRoot(); if (needsTry) { @@ -623,14 +1142,14 @@ builder.string("// ignore").newLine(); } else { builder.startReturn(); - builder.tree(castPrimaryExecute(node, castedType, CodeTreeBuilder.singleString("ex.getResult()"))); + builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("ex.getResult()"))); builder.end(); } builder.end(); if (!returnVoid) { builder.startReturn(); - builder.tree(castPrimaryExecute(node, castedType, CodeTreeBuilder.singleString("value"))); + builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("value"))); builder.end(); } } else { @@ -638,137 +1157,195 @@ builder.statement(primaryExecuteCall); } else { builder.startReturn(); - builder.tree(castPrimaryExecute(node, castedType, primaryExecuteCall)); + builder.tree(createExpectType(node, castedType, primaryExecuteCall)); builder.end(); } } } - private CodeTree castPrimaryExecute(NodeData node, ExecutableTypeData castedType, CodeTree value) { - if (castedType.getType().isVoid()) { + private CodeTree createExpectType(NodeData node, ExecutableTypeData castedType, CodeTree value) { + if (castedType == null) { return value; - } - if (castedType.getType().isGeneric()) { + } else if (castedType.getType().isVoid()) { + return value; + } else if (castedType.getType().isGeneric()) { return value; } CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + String targetMethodName; if (castedType.hasUnexpectedValue(getContext())) { - startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.expectTypeMethodName(castedType.getType())); + targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(castedType.getType()); } else { - startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.asTypeMethodName(castedType.getType())); + targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(castedType.getType()); } + startCallTypeSystemMethod(getContext(), builder, node, targetMethodName); + builder.tree(value); builder.end().end(); return builder.getRoot(); } private void buildFunctionalExecuteMethod(CodeTreeBuilder builder, SpecializationData specialization) { - NodeData node = specialization.getNode(); - TypeSystemData typeSystem = node.getTypeSystem(); - - for (NodeFieldData field : node.getFields()) { - if (field.getExecutionKind() == ExecutionKind.IGNORE) { - continue; - } - - ActualParameter parameterType = specialization.findParameter(field.getName()); - - if (parameterType.getActualTypeData(typeSystem).isGeneric()) { - buildGenericValueExecute(builder, specialization, field, null); - } else { - buildSpecializedValueExecute(builder, specialization, field); - } + if (specialization.isUninitialized()) { + builder.tree(createDeoptimize(builder)); } - if (specialization.hasDynamicGuards()) { - builder.startIf(); - emitGuards(getContext(), builder, "", specialization, false, false); - builder.end().startBlock(); + builder.tree(createExecuteChildren(builder, specialization)); + + CodeTree executeNode; + if (specialization.isUninitialized()) { + builder.tree(createSpecializeCall(builder, specialization)); + } + executeNode = createExecute(builder, specialization); + + SpecializationData next = specialization.findNextSpecialization(); + CodeTree returnSpecialized = null; + if (next != null) { + returnSpecialized = createReturnSpecializeAndExecute(builder, next, null); } - if (specialization.getExceptions().length > 0) { + builder.tree(createGuardAndCast(builder, null, specialization, specialization, false, executeNode, returnSpecialized)); + } + + private CodeTree createDeoptimize(CodeTreeBuilder parent) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + builder.startStatement(); + builder.startStaticCall(getContext().getTruffleTypes().getTruffleIntrinsics(), "deoptimize").end(); + builder.end(); + return builder.getRoot(); + } + + private CodeTree createSpecializeCall(CodeTreeBuilder parent, SpecializationData specialization) { + NodeData node = specialization.getNode(); + + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + emitSpecializationListeners(builder, node); + + builder.startStatement(); + builder.startCall("replace"); + if (node.needsRewrites(getContext())) { + builder.startCall(factoryClassName(node), "specialize"); + builder.string("this"); + builder.typeLiteral(builder.findMethod().getEnclosingElement().asType()); + addInternalValueParameterNames(builder, specialization, null, false, true); + builder.end(); // call replace, call specialize + } else { + builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end(); + } + builder.end().end(); + return builder.getRoot(); + } + + private CodeTree createExecute(CodeTreeBuilder parent, SpecializationData specialization) { + NodeData node = specialization.getNode(); + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + if (!specialization.getExceptions().isEmpty()) { builder.startTryBlock(); } if (specialization.isUninitialized()) { - for (TemplateMethod listener : node.getSpecializationListeners()) { - builder.startStatement(); - startCallOperationMethod(builder, listener); - addValueParameterNames(builder, listener, null, false); - builder.end().end(); - builder.end(); // statement + String genericMethodName = generatedGenericMethodName(null); + builder.startReturn().startCall(factoryClassName(node), genericMethodName); + builder.string("this"); + addInternalValueParameterNames(builder, specialization, null, true, true); + builder.end().end(); + } else if (specialization.getMethod() == null && !node.needsRewrites(context)) { + emitEncounteredSynthetic(builder); + } else if (specialization.isGeneric()) { + String genericMethodName; + if (!specialization.isUseSpecializationsForGeneric()) { + genericMethodName = generatedGenericMethodName(specialization); + } else { + genericMethodName = generatedGenericMethodName(null); } - builder.startStatement(); - builder.startCall("replace"); - if (node.needsRewrites(getContext())) { - builder.startCall(factoryClassName(node), "specialize"); - builder.string("this"); - builder.typeLiteral(builder.getRoot().getEnclosingClass().asType()); - addValueParameterNames(builder, specialization, null, false); - builder.end(); // call replace, call specialize - } else { - builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end(); - } - builder.end().end(); - } - - if ((specialization.isUninitialized() || specialization.isGeneric()) && node.needsRewrites(getContext())) { - builder.startReturn().startCall(factoryClassName(node), generatedGenericMethodName(null)); + builder.startReturn().startCall(factoryClassName(node), genericMethodName); builder.string("this"); - addValueParameterNames(builder, specialization, null, true); + addInternalValueParameterNames(builder, specialization, null, true, true); builder.end().end(); } else { builder.startReturn(); - - if (specialization.isUninitialized()) { - startCallOperationMethod(builder, specialization.getNode().getGenericSpecialization()); - } else { - startCallOperationMethod(builder, specialization); - } - addValueParameterNames(builder, specialization, null, false); - builder.end().end(); // operation call + builder.tree(createTemplateMethodCall(builder, specialization, specialization, specialization, null)); builder.end(); // return } - if (specialization.getExceptions().length > 0) { + if (!specialization.getExceptions().isEmpty()) { for (SpecializationThrowsData exception : specialization.getExceptions()) { builder.end().startCatchBlock(exception.getJavaClass(), "ex"); - buildThrowSpecialize(builder, specialization, exception.getTransitionTo(), null); + builder.tree(createReturnSpecializeAndExecute(parent, exception.getTransitionTo(), null)); } builder.end(); } - if (specialization.hasDynamicGuards()) { - builder.end().startElseBlock(); - buildThrowSpecialize(builder, specialization, specialization.findNextSpecialization(), null); - builder.end(); + return builder.getRoot(); + } + + private CodeTree createExecuteChildren(CodeTreeBuilder parent, SpecializationData specialization) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + + for (ActualParameter parameter : specialization.getParameters()) { + NodeFieldData field = specialization.getNode().findField(parameter.getSpecification().getName()); + if (field == null || field.getKind() == FieldKind.FIELD) { + continue; + } + + buildFieldExecute(builder, specialization, parameter, field, null); + } + return builder.getRoot(); + } + + private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) { + for (TemplateMethod listener : node.getSpecializationListeners()) { + builder.startStatement(); + builder.tree(createTemplateMethodCall(builder, listener, listener, listener, null)); + builder.end(); // statement } } - private void buildGenericValueExecute(CodeTreeBuilder builder, SpecializationData specialization, NodeFieldData field, NodeFieldData exceptionSpec) { - ActualParameter specParameter = specialization.findParameter(field.getName()); - - boolean shortCircuit = startShortCircuit(builder, specialization, field, exceptionSpec); + private void buildFieldExecute(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter param, NodeFieldData field, ActualParameter exceptionParam) { + boolean shortCircuit = startShortCircuit(builder, specialization, param, exceptionParam); + ExecutableTypeData execType = field.getNodeData().findExecutableType(param.getActualTypeData(field.getNodeData().getTypeSystem())); + boolean unexpected = execType.hasUnexpectedValue(getContext()); - builder.startStatement(); - if (!shortCircuit) { - builder.type(specialization.getNode().getTypeSystem().getGenericType()); - builder.string(" "); + if (!shortCircuit && unexpected) { + builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).end(); + } + + if (unexpected) { + builder.startTryBlock(); } - builder.string(valueName(specialization, specParameter)); - builder.string(" = "); - ExecutableTypeData genericExecutableType = field.getNodeData().findGenericExecutableType(getContext()); - if (genericExecutableType == null) { - throw new AssertionError("Must have generic executable type. Parser validation most likely failed. " + Arrays.toString(field.getNodeData().getExecutableTypes())); + if (!shortCircuit && !unexpected) { + builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).string(" = "); + } else { + builder.startStatement().string(valueName(param)).string(" = "); } - buildExecute(builder, field, genericExecutableType); + buildExecute(builder, param, field, execType); builder.end(); + if (unexpected) { + builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); + SpecializationData generic = specialization.getNode().getGenericSpecialization(); + boolean execute = false; + for (ActualParameter exParam : generic.getParameters()) { + NodeFieldData exField = generic.getNode().findField(exParam.getSpecification().getName()); + if (exField == null || field.getKind() == FieldKind.FIELD) { + continue; + } + if (execute) { + buildFieldExecute(builder, specialization.getNode().getGenericSpecialization(), exParam, exField, param); + } else if (exParam.getLocalName().equals(param.getLocalName())) { + execute = true; + } + } + builder.tree(createReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), param)); + builder.end(); // catch block + } + endShortCircuit(builder, shortCircuit); + builder.newLine(); } - private void buildExecute(CodeTreeBuilder builder, NodeFieldData field, ExecutableTypeData execType) { + private void buildExecute(CodeTreeBuilder builder, ActualParameter parameter, NodeFieldData field, ExecutableTypeData execType) { if (field != null) { Element accessElement = field.getAccessElement(); if (accessElement.getKind() == ElementKind.METHOD) { @@ -778,60 +1355,28 @@ } else { throw new AssertionError(); } + if (parameter.getSpecification().isIndexed()) { + builder.string("[" + parameter.getIndex() + "]"); + } builder.string("."); } builder.startCall(execType.getMethodName()); - if (execType.getParameters().length == 1) { - builder.string("frame"); + if (execType.getParameters().size() == 1) { + builder.string("frameValue"); } builder.end(); } - private void buildSpecializedValueExecute(CodeTreeBuilder builder, SpecializationData specialization, NodeFieldData field) { - ActualParameter param = specialization.findParameter(field.getName()); - boolean shortCircuit = startShortCircuit(builder, specialization, field, null); - - if (!shortCircuit) { - builder.startStatement().type(param.getActualType()).string(" ").string(valueName(specialization, param)).end(); - } - - ExecutableTypeData execType = field.getNodeData().findExecutableType(param.getActualTypeData(field.getNodeData().getTypeSystem())); - - if (execType.hasUnexpectedValue(getContext())) { - builder.startTryBlock(); + private boolean startShortCircuit(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter parameter, ActualParameter exceptionParam) { + NodeFieldData forField = specialization.getNode().findField(parameter.getSpecification().getName()); + if (forField == null) { + return false; } - builder.startStatement().string(valueName(field)).string(" = "); - buildExecute(builder, field, execType); - builder.end(); - - if (execType.hasUnexpectedValue(getContext())) { - builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); - boolean execute = false; - for (NodeFieldData exField : specialization.getNode().getFields()) { - if (exField.getExecutionKind() == ExecutionKind.IGNORE) { - continue; - } - if (execute) { - buildGenericValueExecute(builder, specialization.getNode().getGenericSpecialization(), exField, field); - } else if (exField == field) { - execute = true; - } - } - buildThrowSpecialize(builder, specialization, specialization.findNextSpecialization(), param.getSpecification()); - builder.end(); // catch block - } - - endShortCircuit(builder, shortCircuit); - builder.newLine(); - } - - private boolean startShortCircuit(CodeTreeBuilder builder, SpecializationData specialization, NodeFieldData forField, NodeFieldData exceptionField) { if (forField.getExecutionKind() != ExecutionKind.SHORT_CIRCUIT) { return false; } - ActualParameter parameter = specialization.findParameter(forField.getName()); ActualParameter shortCircuitParam = specialization.getPreviousParam(parameter); int shortCircuitIndex = 0; @@ -844,17 +1389,15 @@ } } - builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(specialization, shortCircuitParam)).string(" = "); - ShortCircuitData shortCircuitData = specialization.getShortCircuits()[shortCircuitIndex]; + builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(shortCircuitParam)).string(" = "); + ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(shortCircuitIndex); - startCallOperationMethod(builder, shortCircuitData); - addValueParameterNames(builder, shortCircuitData, exceptionField != null ? exceptionField.getName() : null, false); - builder.end().end(); // call operation + builder.tree(createTemplateMethodCall(builder, shortCircuitData, shortCircuitData, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null)); builder.end(); // statement - builder.declaration(parameter.getActualType(), valueName(specialization, parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getActualType())); - builder.startIf().string(shortCircuitParam.getSpecification().getName()).end(); + builder.declaration(parameter.getActualType(), valueName(parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getActualType())); + builder.startIf().string(shortCircuitParam.getLocalName()).end(); builder.startBlock(); return true; @@ -866,74 +1409,66 @@ } } - private void buildThrowSpecialize(CodeTreeBuilder builder, SpecializationData currentSpecialization, SpecializationData nextSpecialization, ParameterSpec exceptionSpec) { - boolean canThrowUnexpected = Utils.canThrowType(builder.findMethod().getThrownTypes(), getContext().getTruffleTypes().getUnexpectedValueException()); - - CodeTreeBuilder specializeCall = CodeTreeBuilder.createBuilder(); - specializeCall.startCall("specialize"); - specializeCall.string(nodeClassName(nextSpecialization) + ".class"); - addValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionSpec != null ? exceptionSpec.getName() : null, true); + private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, SpecializationData nextSpecialization, ActualParameter exceptionParam) { + CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent); + specializeCall.startCall("specializeAndExecute"); + specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class"); + addInternalValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, true); specializeCall.end().end(); - TypeData expectedType = currentSpecialization.getReturnType().getActualTypeData(currentSpecialization.getNode().getTypeSystem()); - if (canThrowUnexpected) { - builder.startReturn(); - startCallTypeSystemMethod(context, builder, currentSpecialization.getNode(), TypeSystemCodeGenerator.expectTypeMethodName(expectedType)); - builder.tree(specializeCall.getRoot()); - builder.end().end(); - builder.end(); // return - } else { - builder.startReturn(); - if (!expectedType.isVoid() && !expectedType.isGeneric()) { - startCallTypeSystemMethod(context, builder, currentSpecialization.getNode(), TypeSystemCodeGenerator.asTypeMethodName(expectedType)); - builder.tree(specializeCall.getRoot()); - builder.end().end(); - } else { - builder.tree(specializeCall.getRoot()); - } - builder.end(); - } - + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + builder.startReturn(); + builder.tree(specializeCall.getRoot()); + builder.end(); + return builder.getRoot(); } - private void buildSpecializeStateMethod(CodeTypeElement clazz, SpecializationData specialization) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), specialization.getNode().getTypeSystem().getGenericType(), "specialize"); + private void buildSpecializeAndExecute(CodeTypeElement clazz, SpecializationData specialization) { + NodeData node = specialization.getNode(); + TypeData returnType = specialization.getReturnType().getActualTypeData(node.getTypeSystem()); + ExecutableTypeData returnExecutableType = node.findExecutableType(returnType); + boolean canThrowUnexpected = returnExecutableType == null ? true : returnExecutableType.hasUnexpectedValue(getContext()); + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), returnType.getPrimitiveType(), "specializeAndExecute"); method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); - addValueParameters(method, specialization.getNode().getGenericSpecialization(), true); + if (canThrowUnexpected) { + method.addThrownType(getUnexpectedValueException()); + } + addInternalValueParameters(method, specialization.getNode().getGenericSpecialization(), true); clazz.add(method); CodeTreeBuilder builder = method.createBuilder(); - for (TemplateMethod listener : specialization.getNode().getSpecializationListeners()) { - builder.startStatement(); - startCallOperationMethod(builder, listener); - addValueParameterNames(builder, listener, null, false); - builder.end().end(); // call operation - builder.end(); // statement - } + + builder.tree(createDeoptimize(builder)); + emitSpecializationListeners(builder, specialization.getNode()); builder.startStatement(); builder.startCall("replace"); builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState"); - addValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, false); + addInternalValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, false, true); builder.end(); builder.end(); // call replace builder.end(); // statement String generatedMethodName = generatedGenericMethodName(specialization.findNextSpecialization()); - ExecutableElement generatedGeneric = clazz.getEnclosingClass().getMethod(generatedMethodName); - CodeTreeBuilder genericBuilder = CodeTreeBuilder.createBuilder(); - genericBuilder.startCall(factoryClassName(specialization.getNode()), generatedMethodName); - genericBuilder.string("this"); - addValueParameterNames(genericBuilder, specialization.getNode().getGenericSpecialization(), null, true); - genericBuilder.end(); // call generated generic + CodeTreeBuilder genericExecute = CodeTreeBuilder.createBuilder(); + genericExecute.startCall(factoryClassName(specialization.getNode()), generatedMethodName); + genericExecute.string("this"); + addInternalValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), null, true, true); + genericExecute.end(); // call generated generic + + CodeTree genericInvocation = createExpectType(node, returnExecutableType, genericExecute.getRoot()); if (generatedGeneric != null && Utils.isVoid(generatedGeneric.getReturnType())) { - builder.declaration(generatedGeneric.getReturnType(), "genericResult", genericBuilder.getRoot()); - builder.startReturn().string("null").end(); + builder.statement(genericInvocation); + + if (!Utils.isVoid(builder.findMethod().asType())) { + builder.startReturn().defaultValue(returnType.getPrimitiveType()).end(); + } } else { - builder.startReturn().tree(genericBuilder.getRoot()).end(); + builder.startReturn().tree(genericInvocation).end(); } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Thu Mar 21 14:11:13 2013 +0100 @@ -35,22 +35,89 @@ public class NodeData extends Template { - private NodeData parent; - private List declaredChildren; + private final String nodeId; + private NodeData declaringNode; + private List declaredChildren = new ArrayList<>(); + + private TypeSystemData typeSystem; + private List fields; + private TypeMirror nodeType; + private ParameterSpec instanceParameterSpec; + + private List specializations; + private List specializationListeners; + private List guards; + private List executableTypes; + private List shortCircuits; - private final TypeSystemData typeSystem; + public NodeData(TypeElement type, String id) { + super(type, null, null); + this.nodeId = id; + } + + public NodeData(NodeData splitSource, String templateMethodName, String nodeId) { + super(splitSource.getTemplateType(), templateMethodName, null); + this.nodeId = nodeId; + this.declaringNode = splitSource.declaringNode; + this.declaredChildren = splitSource.declaredChildren; + this.typeSystem = splitSource.typeSystem; + this.nodeType = splitSource.nodeType; + this.specializations = splitSource.specializations; + this.specializationListeners = splitSource.specializationListeners; + this.guards = splitSource.guards; + this.executableTypes = splitSource.executableTypes; + this.shortCircuits = splitSource.shortCircuits; + this.fields = splitSource.fields; + } + + void setTypeSystem(TypeSystemData typeSystem) { + this.typeSystem = typeSystem; + } - private NodeFieldData[] fields; - private SpecializationData[] specializations; - private TemplateMethod[] specializationListeners; - private GuardData[] guards; - private ExecutableTypeData[] executableTypes; + @Override + protected List findChildContainers() { + List children = new ArrayList<>(); + if (declaredChildren != null) { + children.addAll(declaredChildren); + } + if (typeSystem != null) { + children.add(typeSystem); + } + if (specializations != null) { + for (MessageContainer specialization : specializations) { + if (specialization.getMessageElement() != null) { + children.add(specialization); + } + } + } + if (specializationListeners != null) { + children.addAll(specializationListeners); + } + if (guards != null) { + children.addAll(guards); + } + if (executableTypes != null) { + children.addAll(executableTypes); + } + if (shortCircuits != null) { + children.addAll(shortCircuits); + } + if (fields != null) { + children.addAll(fields); + } + return children; + } - private TypeMirror nodeType; + public ParameterSpec getInstanceParameterSpec() { + return instanceParameterSpec; + } - public NodeData(TypeElement type, TypeSystemData typeSystem) { - super(type, null); - this.typeSystem = typeSystem; + public void setInstanceParameterSpec(ParameterSpec instanceParameter) { + this.instanceParameterSpec = instanceParameter; + } + + public String getNodeId() { + return nodeId; } public TypeMirror getNodeType() { @@ -71,16 +138,36 @@ return !noSpecialization; } + public boolean supportsFrame() { + for (ExecutableTypeData execType : executableTypes) { + if (execType.findParameter("frameValue") == null) { + return false; + } + } + return true; + } + + public List getNodeChildren() { + List children = new ArrayList<>(); + for (NodeData child : getDeclaredChildren()) { + if (child.needsFactory()) { + children.add(child); + } + children.addAll(child.getNodeChildren()); + } + return children; + } + void setDeclaredChildren(List declaredChildren) { this.declaredChildren = declaredChildren; for (NodeData child : declaredChildren) { - child.parent = this; + child.declaringNode = this; } } public NodeData getParent() { - return parent; + return declaringNode; } public List getDeclaredChildren() { @@ -96,22 +183,16 @@ for (SpecializationData specialization : getSpecializations()) { methods.add(specialization); - if (specialization.getShortCircuits() != null) { - methods.addAll(Arrays.asList(specialization.getShortCircuits())); - } } - methods.addAll(Arrays.asList(getSpecializationListeners())); - methods.addAll(Arrays.asList(getExecutableTypes())); - methods.addAll(Arrays.asList(getGuards())); + methods.addAll(getSpecializationListeners()); + methods.addAll(getExecutableTypes()); + methods.addAll(getGuards()); + methods.addAll(getShortCircuits()); return methods; } - public TemplateMethod[] getSpecializationListeners() { - return specializationListeners; - } - public List findGuards(String name) { List foundGuards = new ArrayList<>(); for (GuardData guardData : getGuards()) { @@ -122,38 +203,33 @@ return foundGuards; } - public ExecutableTypeData[] getExecutableTypes() { - return executableTypes; + public ExecutableTypeData findGenericExecutableType(ProcessorContext context, TypeData type) { + List types = findGenericExecutableTypes(context); + for (ExecutableTypeData availableType : types) { + if (Utils.typeEquals(availableType.getType().getBoxedType(), type.getBoxedType())) { + return availableType; + } + } + return null; } - public ExecutableTypeData findGenericExecutableType(ProcessorContext context) { + public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context) { List types = findGenericExecutableTypes(context); - if (types.isEmpty()) { - return null; - } else if (types.size() == 1) { - return types.get(0); - } else if (types.size() == 2) { - if (types.get(0).getType().isVoid()) { - return types.get(1); - } else if (types.get(1).getType().isVoid()) { - return types.get(0); + for (ExecutableTypeData type : types) { + if (type.getType().isGeneric()) { + return type; } } - ExecutableTypeData execType = null; for (ExecutableTypeData type : types) { - TypeData returnType = type.getReturnType().getActualTypeData(getTypeSystem()); - if (returnType.isGeneric()) { - if (execType != null) { - return null; - } - execType = type; + if (!type.getType().isVoid()) { + return type; } } - return execType; + return null; } - private List findGenericExecutableTypes(ProcessorContext context) { + public List findGenericExecutableTypes(ProcessorContext context) { List types = new ArrayList<>(); for (ExecutableTypeData type : executableTypes) { if (!type.hasUnexpectedValue(context)) { @@ -186,47 +262,20 @@ return result; } - public TypeMirror[] getExecutablePrimitiveTypeMirrors() { - TypeMirror[] typeMirrors = new TypeMirror[executableTypes.length]; - for (int i = 0; i < executableTypes.length; i++) { - typeMirrors[i] = executableTypes[i].getType().getPrimitiveType(); + public List getExecutablePrimitiveTypeMirrors() { + List typeMirrors = new ArrayList<>(); + for (ExecutableTypeData executableType : executableTypes) { + typeMirrors.add(executableType.getType().getPrimitiveType()); } return typeMirrors; } - void setExecutableTypes(ExecutableTypeData[] declaredExecuableTypes) { - this.executableTypes = declaredExecuableTypes; - } - - void setFields(NodeFieldData[] fields) { - this.fields = fields; - } - - void setSpecializations(SpecializationData[] specializations) { - this.specializations = specializations; - } - - void setSpecializationListeners(TemplateMethod[] specializationListeners) { - this.specializationListeners = specializationListeners; - } - - void setGuards(GuardData[] guards) { - this.guards = guards; - } - - public GuardData[] getGuards() { - return guards; - } - public NodeFieldData[] filterFields(FieldKind fieldKind, ExecutionKind usage) { List filteredFields = new ArrayList<>(); - NodeFieldData[] resolvedFields = getFields(); - if (fields != null) { - for (NodeFieldData field : resolvedFields) { - if (usage == null || field.getExecutionKind() == usage) { - if (fieldKind == null || field.getKind() == fieldKind) { - filteredFields.add(field); - } + for (NodeFieldData field : getFields()) { + if (usage == null || field.getExecutionKind() == usage) { + if (fieldKind == null || field.getKind() == fieldKind) { + filteredFields.add(field); } } } @@ -244,18 +293,13 @@ public boolean needsRewrites(ProcessorContext context) { boolean needsRewrites = false; - for (NodeFieldData field : getFields()) { - if (field.getExecutionKind() == ExecutionKind.DEFAULT || field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) { - if (!field.getNodeData().hasUnexpectedExecutableTypes(context)) { - continue; - } + for (SpecializationData specialization : getSpecializations()) { + if (specialization.hasRewrite(context)) { needsRewrites = true; break; } } - - needsRewrites &= specializations.length >= 2; return needsRewrites; } @@ -269,37 +313,65 @@ } public TypeSystemData getTypeSystem() { - if (typeSystem != null) { - return typeSystem; + return typeSystem; + } + + public String dump() { + return dump(0); + } + + private String dump(int level) { + String indent = ""; + for (int i = 0; i < level; i++) { + indent += " "; + } + StringBuilder builder = new StringBuilder(); + + builder.append(String.format("%s%s {", indent, toString())); + + dumpProperty(builder, indent, "templateClass", Utils.getQualifiedName(getTemplateType())); + dumpProperty(builder, indent, "typeSystem", getTypeSystem()); + dumpProperty(builder, indent, "fields", getFields()); + dumpProperty(builder, indent, "executableTypes", getExecutableTypes()); + dumpProperty(builder, indent, "specializations", getSpecializations()); + dumpProperty(builder, indent, "guards", getGuards()); + dumpProperty(builder, indent, "messages", collectMessages()); + if (getDeclaredChildren().size() > 0) { + builder.append(String.format("\n%s children = [", indent)); + for (NodeData node : getDeclaredChildren()) { + builder.append("\n"); + builder.append(node.dump(level + 1)); + } + builder.append(String.format("\n%s ]", indent)); + } + builder.append(String.format("%s}", indent)); + return builder.toString(); + } + + private static void dumpProperty(StringBuilder b, String indent, String propertyName, Object value) { + if (value instanceof List) { + List list = (List) value; + if (!list.isEmpty()) { + b.append(String.format("\n%s %s = %s", indent, propertyName, dumpList((List) value))); + } } else { - return null; + if (value != null) { + b.append(String.format("\n%s %s = %s", indent, propertyName, value)); + } } } - public NodeFieldData[] getFields() { - return fields; - } - - public NodeFieldData[] getDeclaredFields() { - return fields; - } - - public SpecializationData[] getSpecializations() { - return specializations; - } - - public String dump() { - StringBuilder b = new StringBuilder(); - b.append(String.format("[name = %s\n" + " typeSystem = %s\n" + " fields = %s\n" + " types = %s\n" + " specializations = %s\n" + " guards = %s\n" + "]", - Utils.getQualifiedName(getTemplateType()), getTypeSystem(), dumpList(fields), dumpList(getExecutableTypes()), dumpList(getSpecializations()), dumpList(guards))); - return b.toString(); - } - - private static String dumpList(Object[] array) { + private static String dumpList(List array) { if (array == null) { return "null"; } + if (array.isEmpty()) { + return "[]"; + } else if (array.size() == 1) { + return "[" + array.get(0).toString() + "]"; + } + StringBuilder b = new StringBuilder(); b.append("["); for (Object object : array) { @@ -321,4 +393,76 @@ return null; } + public List getFields() { + return fields; + } + + void setFields(List fields) { + this.fields = fields; + } + + public List getSpecializations() { + return getSpecializations(false); + } + + public List getSpecializations(boolean userDefinedOnly) { + if (userDefinedOnly) { + List specs = new ArrayList<>(); + for (SpecializationData spec : specializations) { + if (spec.getMethod() != null) { + specs.add(spec); + } + } + return specs; + } else { + return specializations; + } + } + + public List getSpecializationListeners() { + return specializationListeners; + } + + public List getGuards() { + return guards; + } + + public List getExecutableTypes() { + return executableTypes; + } + + public List getShortCircuits() { + return shortCircuits; + } + + void setSpecializations(List specializations) { + this.specializations = specializations; + if (this.specializations != null) { + for (SpecializationData specialization : specializations) { + specialization.setNode(this); + } + } + } + + void setSpecializationListeners(List specializationListeners) { + this.specializationListeners = specializationListeners; + } + + void setGuards(List guards) { + this.guards = guards; + } + + void setExecutableTypes(List executableTypes) { + this.executableTypes = executableTypes; + } + + void setShortCircuits(List shortCircuits) { + this.shortCircuits = shortCircuits; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + getNodeId() + "]"; + } + } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java Thu Mar 21 14:11:13 2013 +0100 @@ -25,10 +25,12 @@ import javax.lang.model.element.*; import javax.lang.model.type.*; -public class NodeFieldData { +import com.oracle.truffle.codegen.processor.template.*; + +public class NodeFieldData extends MessageContainer { public enum FieldKind { - FIELD, CHILD, CHILDREN + CHILD, CHILDREN, FIELD } public enum ExecutionKind { @@ -41,17 +43,39 @@ private final FieldKind fieldKind; private final ExecutionKind executionKind; - private final NodeData nodeData; + private NodeData nodeData; - public NodeFieldData(NodeData typeNodeData, VariableElement fieldElement, Element accessElement, AnnotationMirror childAnnotationMirror, FieldKind fieldKind, ExecutionKind executionKind) { + public NodeFieldData(VariableElement fieldElement, Element accessElement, AnnotationMirror childAnnotationMirror, FieldKind fieldKind, ExecutionKind executionKind) { this.fieldElement = fieldElement; this.accessElement = accessElement; this.childAnnotationMirror = childAnnotationMirror; - this.nodeData = typeNodeData; this.fieldKind = fieldKind; this.executionKind = executionKind; } + NodeFieldData(NodeFieldData field) { + this.fieldElement = field.fieldElement; + this.accessElement = field.accessElement; + this.childAnnotationMirror = field.childAnnotationMirror; + this.fieldKind = field.fieldKind; + this.executionKind = field.executionKind; + this.nodeData = field.nodeData; + } + + @Override + public Element getMessageElement() { + return fieldElement; + } + + public boolean isShortCircuit() { + return executionKind == ExecutionKind.SHORT_CIRCUIT; + } + + void setNode(NodeData nodeData) { + this.nodeData = nodeData; + getMessages().addAll(nodeData.collectMessages()); + } + public VariableElement getFieldElement() { return fieldElement; } @@ -86,7 +110,7 @@ @Override public String toString() { - return "NodeFieldData[name=" + getName() + ", kind=" + fieldKind + ", execution=" + executionKind + "]"; + return "NodeFieldData[name=" + getName() + ", kind=" + fieldKind + ", execution=" + executionKind + ", node=" + getNodeData() + "]"; } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Thu Mar 21 14:11:13 2013 +0100 @@ -28,12 +28,12 @@ import javax.lang.model.element.*; import javax.lang.model.type.*; import javax.lang.model.util.*; +import javax.tools.Diagnostic.Kind; import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.api.nodes.Node.Child; import com.oracle.truffle.api.nodes.Node.Children; import com.oracle.truffle.codegen.processor.*; -import com.oracle.truffle.codegen.processor.ast.*; import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind; import com.oracle.truffle.codegen.processor.node.NodeFieldData.FieldKind; import com.oracle.truffle.codegen.processor.template.*; @@ -41,11 +41,10 @@ public class NodeParser extends TemplateParser { - public static final List> ANNOTATIONS = Arrays.asList(Generic.class, GuardCheck.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, - SpecializationGuard.class, SpecializationListener.class, SpecializationThrows.class); + public static final List> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, SpecializationListener.class, + ExecuteChildren.class, NodeClass.class, NodeId.class); private Map parsedNodes; - private TypeElement originalType; public NodeParser(ProcessorContext c) { super(c); @@ -54,23 +53,37 @@ @Override protected NodeData parse(Element element, AnnotationMirror mirror) { assert element instanceof TypeElement; + NodeData node = null; try { parsedNodes = new HashMap<>(); - originalType = (TypeElement) element; - - return parseInnerClassHierarchy((TypeElement) element); - } finally { + node = resolveNode((TypeElement) element); if (Log.DEBUG) { - NodeData parsed = parsedNodes.get(Utils.getQualifiedName(originalType)); - if (parsed != null) { + NodeData parsed = parsedNodes.get(Utils.getQualifiedName((TypeElement) element)); + if (node != null) { String dump = parsed.dump(); - log.error("Node parsed: %s", dump); - System.out.println("Parsed: " + dump); + log.message(Kind.ERROR, null, null, null, dump); + System.out.println(dump); } } + } finally { parsedNodes = null; - originalType = null; } + + return node; + } + + @Override + protected NodeData filterErrorElements(NodeData model) { + for (Iterator iterator = model.getDeclaredChildren().iterator(); iterator.hasNext();) { + NodeData node = filterErrorElements(iterator.next()); + if (node == null) { + iterator.remove(); + } + } + if (model.hasErrors()) { + return null; + } + return model; } @Override @@ -78,178 +91,474 @@ return true; } - private NodeData parseInnerClassHierarchy(TypeElement rootType) { + private NodeData resolveNode(TypeElement rootType) { + String typeName = Utils.getQualifiedName(rootType); + if (parsedNodes.containsKey(typeName)) { + return parsedNodes.get(typeName); + } + List types = ElementFilter.typesIn(rootType.getEnclosedElements()); + List children = new ArrayList<>(); for (TypeElement childElement : types) { - NodeData childNode = parseInnerClassHierarchy(childElement); + NodeData childNode = resolveNode(childElement); if (childNode != null) { children.add(childNode); } } - NodeData rootNode = resolveNode(rootType); - if (rootNode == null && children.size() > 0) { - rootNode = new NodeData(rootType, null); + + NodeData rootNode = parseNode(rootType); + boolean hasErrors = rootNode != null ? rootNode.hasErrors() : false; + if ((rootNode == null || hasErrors) && children.size() > 0) { + rootNode = new NodeData(rootType, rootType.getSimpleName().toString()); } + + parsedNodes.put(typeName, rootNode); + if (rootNode != null) { + children.addAll(rootNode.getDeclaredChildren()); rootNode.setDeclaredChildren(children); } + return rootNode; } - private NodeData resolveNode(TypeElement currentType) { - String typeName = Utils.getQualifiedName(currentType); - if (!parsedNodes.containsKey(typeName)) { - NodeData node = parseNode(currentType); - if (node != null) { - parsedNodes.put(typeName, node); - } - return node; - } - return parsedNodes.get(typeName); - } - private NodeData parseNode(TypeElement type) { if (Utils.findAnnotationMirror(processingEnv, type, GeneratedBy.class) != null) { - // generated nodes get called again. + // generated nodes should not get called again. return null; } - if (!Utils.isAssignable(type.asType(), context.getTruffleTypes().getNode())) { + + AnnotationMirror methodNodes = Utils.findAnnotationMirror(processingEnv, type, NodeClass.class); + + if (methodNodes == null && !Utils.isAssignable(type.asType(), context.getTruffleTypes().getNode())) { return null; // not a node } + if (type.getModifiers().contains(Modifier.PRIVATE)) { + // TODO error message here!? + return null; // not visible, not a node + } + + TypeElement nodeType; + boolean needsSplit; + if (methodNodes != null) { + needsSplit = methodNodes != null; + nodeType = Utils.fromTypeMirror(Utils.getAnnotationValue(TypeMirror.class, methodNodes, "value")); + } else { + needsSplit = false; + nodeType = type; + } + + NodeData nodeData = parseNodeData(type, nodeType); + + 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();) { + NodeFieldData field = iterator.next(); + if (field.getKind() == FieldKind.FIELD) { + iterator.remove(); + } + } + } + + if (nodeData.hasErrors()) { + return nodeData; // error sync point + } + List elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type)); - List typeHierarchy = findSuperClasses(new ArrayList(), type); - Collections.reverse(typeHierarchy); - - AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); - if (typeSystemMirror == null) { - log.error(originalType, "No @%s annotation found in type hierarchy.", TypeSystemReference.class.getSimpleName()); - return null; - } - - TypeMirror typeSytemType = Utils.getAnnotationValueType(typeSystemMirror, "value"); - final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true); - if (typeSystem == null) { - log.error(originalType, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType)); - return null; - } - - NodeData nodeData = new NodeData(type, typeSystem); - - nodeData.setExtensionElements(getExtensionParser().parseAll(type, elements)); + nodeData.setExtensionElements(getExtensionParser().parseAll(nodeData, elements)); if (nodeData.getExtensionElements() != null) { elements.addAll(nodeData.getExtensionElements()); } + parseMethods(nodeData, elements); - List executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements)); - - nodeData.setExecutableTypes(executableTypes.toArray(new ExecutableTypeData[executableTypes.size()])); + if (nodeData.hasErrors()) { + return nodeData; + } - parsedNodes.put(Utils.getQualifiedName(type), nodeData); // node fields will resolve node -// types, to avoid endless loops + List nodes; + if (needsSplit) { + nodes = splitNodeData(nodeData); + } else { + nodes = new ArrayList<>(); + nodes.add(nodeData); + } - NodeFieldData[] fields = parseFields(nodeData, elements, typeHierarchy); - if (fields == null) { - return null; + for (NodeData splittedNode : nodes) { + finalizeSpecializations(splittedNode); + verifyNode(splittedNode); + } + + if (needsSplit) { + nodeData.setDeclaredChildren(nodes); + nodeData.setSpecializationListeners(new ArrayList()); + nodeData.setSpecializations(new ArrayList()); + return nodeData; + } else { + return nodeData; } - nodeData.setFields(fields); + } + + private static List splitNodeData(NodeData node) { + SortedMap> groupedSpecializations = groupByNodeId(node.getSpecializations()); + SortedMap> groupedListeners = groupByNodeId(node.getSpecializationListeners()); + + Set ids = new TreeSet<>(); + ids.addAll(groupedSpecializations.keySet()); + ids.addAll(groupedListeners.keySet()); + + List splitted = new ArrayList<>(); + for (String id : ids) { + List specializations = groupedSpecializations.get(id); + List listeners = groupedListeners.get(id); + + if (specializations == null) { + specializations = new ArrayList<>(); + } - List genericSpecializations = new GenericParser(context, nodeData).parse(elements); - List guards = new GuardParser(context, nodeData, nodeData.getTypeSystem()).parse(elements); - nodeData.setGuards(guards.toArray(new GuardData[guards.size()])); + if (listeners == null) { + listeners = new ArrayList<>(); + } + + String nodeId = node.getNodeId(); + if (nodeId.endsWith("Node") && !nodeId.equals("Node")) { + nodeId = nodeId.substring(0, nodeId.length() - 4); + } + String newNodeId = nodeId + Utils.firstLetterUpperCase(id); + NodeData copy = new NodeData(node, id, newNodeId); + + copy.setSpecializations(specializations); + copy.setSpecializationListeners(listeners); + + splitted.add(copy); + } + + node.setSpecializations(new ArrayList()); + node.setSpecializationListeners(new ArrayList()); + + return splitted; + } - SpecializationMethodParser specializationParser = new SpecializationMethodParser(context, nodeData); - List specializations = specializationParser.parse(elements); - List shortCircuits = new ShortCircuitParser(context, nodeData).parse(elements); - List listeners = new SpecializationListenerParser(context, nodeData).parse(elements); + private static SortedMap> groupByNodeId(List methods) { + SortedMap> grouped = new TreeMap<>(); + for (M m : methods) { + List list = grouped.get(m.getId()); + if (list == null) { + list = new ArrayList<>(); + grouped.put(m.getId(), list); + } + list.add(m); + } + return grouped; + } + + private void parseMethods(final NodeData node, List elements) { + node.setGuards(new GuardParser(context, node, node.getTypeSystem()).parse(elements)); + node.setShortCircuits(new ShortCircuitParser(context, node).parse(elements)); + node.setSpecializationListeners(new SpecializationListenerParser(context, node).parse(elements)); + List generics = new GenericParser(context, node).parse(elements); + List specializations = new SpecializationMethodParser(context, node).parse(elements); - if (specializations == null || genericSpecializations == null || shortCircuits == null || listeners == null || guards == null) { - return null; + List allSpecializations = new ArrayList<>(); + allSpecializations.addAll(generics); + allSpecializations.addAll(specializations); + + node.setSpecializations(allSpecializations); + } + + private void finalizeSpecializations(final NodeData node) { + List specializations = new ArrayList<>(node.getSpecializations()); + + if (specializations.isEmpty()) { + return; + } + + List generics = new ArrayList<>(); + for (SpecializationData spec : specializations) { + if (spec.isGeneric()) { + generics.add(spec); + } + } + + if (generics.size() == 1 && specializations.size() == 1) { + for (SpecializationData generic : generics) { + generic.addError("@%s defined but no @%s.", Generic.class.getSimpleName(), Specialization.class.getSimpleName()); + } } SpecializationData genericSpecialization = null; - if (genericSpecializations.size() > 1) { - for (SpecializationData generic : genericSpecializations) { - log.error(generic.getMethod(), "Only one method with @%s is allowed per operation.", Generic.class.getSimpleName()); + if (generics.size() > 1) { + for (SpecializationData generic : generics) { + generic.addError("Only @%s is allowed per operation.", Generic.class.getSimpleName()); } - return null; - } else if (genericSpecializations.size() == 1) { - genericSpecialization = genericSpecializations.get(0); + return; + } else if (generics.size() == 1) { + genericSpecialization = generics.get(0); + } else if (node.needsRewrites(context)) { + SpecializationData specialization = specializations.get(0); + GenericParser parser = new GenericParser(context, node); + MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, null); + + ExecutableTypeData anyGenericReturnType = node.findAnyGenericExecutableType(context); + assert anyGenericReturnType != null; + + ActualParameter returnType = new ActualParameter(specification.getReturnType(), anyGenericReturnType.getType().getPrimitiveType(), 0, false); + List parameters = new ArrayList<>(); + for (ActualParameter specializationParameter : specialization.getParameters()) { + ParameterSpec parameterSpec = specification.findParameterSpec(specializationParameter.getSpecification().getName()); + NodeFieldData field = node.findField(parameterSpec.getName()); + TypeMirror actualType; + if (field == null || field.getKind() == FieldKind.FIELD) { + actualType = specializationParameter.getActualType(); + } else { + ExecutableTypeData paramType = field.getNodeData().findAnyGenericExecutableType(context); + assert paramType != null; + actualType = paramType.getType().getPrimitiveType(); + } + parameters.add(new ActualParameter(parameterSpec, actualType, specializationParameter.getIndex(), specializationParameter.isImplicit())); + } + TemplateMethod genericMethod = new TemplateMethod("Generic", node, specification, null, null, returnType, parameters); + genericSpecialization = new SpecializationData(genericMethod, true, false); + + specializations.add(genericSpecialization); } - if (specializations.size() > 1 && genericSpecialization == null) { - log.error(originalType, "Need a @%s method.", Generic.class.getSimpleName()); - return null; + if (genericSpecialization != null) { + TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", node, genericSpecialization.getSpecification(), null, null, genericSpecialization.getReturnType(), + genericSpecialization.getParameters()); + // should not use messages from generic specialization + uninializedMethod.getMessages().clear(); + specializations.add(new SpecializationData(uninializedMethod, false, true)); } Collections.sort(specializations, new Comparator() { @Override public int compare(SpecializationData o1, SpecializationData o2) { - return compareSpecialization(typeSystem, o1, o2); + return compareSpecialization(node.getTypeSystem(), o1, o2); } }); - List allSpecializations = new ArrayList<>(specializations); - if (genericSpecialization != null) { - allSpecializations.add(genericSpecialization); - CodeExecutableElement uninitializedMethod = new CodeExecutableElement(Utils.modifiers(Modifier.PUBLIC), context.getType(void.class), "doUninitialized"); - TemplateMethod uninializedMethod = new TemplateMethod(nodeData, genericSpecialization.getSpecification(), uninitializedMethod, genericSpecialization.getMarkerAnnotation(), - genericSpecialization.getReturnType(), genericSpecialization.getParameters()); - allSpecializations.add(0, new SpecializationData(uninializedMethod, false, true)); + node.setSpecializations(specializations); + + List needsId = new ArrayList<>(); + for (SpecializationData specialization : specializations) { + if (specialization.isGeneric()) { + specialization.setId("Generic"); + } else if (specialization.isUninitialized()) { + specialization.setId("Uninitialized"); + } else { + needsId.add(specialization); + } + } + List ids = calculateSpecializationIds(needsId); + for (int i = 0; i < ids.size(); i++) { + needsId.get(i).setId(ids.get(i)); + } + } + + private static List calculateSpecializationIds(List specializations) { + int lastSize = -1; + List> signatureChunks = new ArrayList<>(); + for (SpecializationData other : specializations) { + if (other.isUninitialized() || other.isGeneric()) { + continue; + } + List paramIds = new LinkedList<>(); + paramIds.add(Utils.getTypeId(other.getReturnType().getActualType())); + for (ActualParameter param : other.getParameters()) { + if (other.getNode().findField(param.getSpecification().getName()) == null) { + continue; + } + paramIds.add(Utils.getTypeId(param.getActualType())); + } + assert lastSize == -1 || lastSize == paramIds.size(); + if (lastSize != -1 && lastSize != paramIds.size()) { + throw new AssertionError(); + } + signatureChunks.add(paramIds); + lastSize = paramIds.size(); } - for (SpecializationData specialization : allSpecializations) { - specialization.setNode(nodeData); + // reduce id vertically + for (int i = 0; i < lastSize; i++) { + String prev = null; + boolean allSame = true; + for (List signature : signatureChunks) { + String arg = signature.get(i); + if (prev == null) { + prev = arg; + continue; + } else if (!prev.equals(arg)) { + allSame = false; + break; + } + prev = arg; + } + + if (allSame) { + for (List signature : signatureChunks) { + signature.remove(i); + } + lastSize--; + } } - // verify order is not ambiguous - if (!verifySpecializationOrder(typeSystem, specializations)) { - return null; + // reduce id horizontally + for (List signature : signatureChunks) { + if (signature.isEmpty()) { + continue; + } + String prev = null; + boolean allSame = true; + for (String arg : signature) { + if (prev == null) { + prev = arg; + continue; + } else if (!prev.equals(arg)) { + allSame = false; + break; + } + prev = arg; + } + + if (allSame) { + signature.clear(); + signature.add(prev); + } } - nodeData.setSpecializations(allSpecializations.toArray(new SpecializationData[allSpecializations.size()])); - nodeData.setSpecializationListeners(listeners.toArray(new TemplateMethod[listeners.size()])); - - if (!verifyMissingAbstractMethods(nodeData, elements)) { - return null; + // create signatures + List signatures = new ArrayList<>(); + for (List signatureChunk : signatureChunks) { + StringBuilder b = new StringBuilder(); + if (signatureChunk.isEmpty()) { + b.append("Default"); + } else { + for (String s : signatureChunk) { + b.append(s); + } + } + signatures.add(b.toString()); } - if (!assignShortCircuitsToSpecializations(nodeData, allSpecializations, shortCircuits)) { - return null; + Map counts = new HashMap<>(); + for (String s1 : signatures) { + Integer count = counts.get(s1); + if (count == null) { + count = 0; + } + count++; + counts.put(s1, count); } - if (!verifyConstructors(nodeData)) { - return null; + for (String s : counts.keySet()) { + int count = counts.get(s); + if (count > 1) { + int number = 0; + for (ListIterator iterator = signatures.listIterator(); iterator.hasNext();) { + String s2 = iterator.next(); + if (s.equals(s2)) { + iterator.set(s2 + number); + number++; + } + } + } } - if (!verifyNamingConvention(specializations, "do")) { - return null; - } + return signatures; + } + + private void verifyNode(NodeData nodeData) { + // verify specialization parameter length + verifySpecializationParameters(nodeData); + + // verify order is not ambiguous + verifySpecializationOrder(nodeData); + + verifyMissingAbstractMethods(nodeData); + + assignShortCircuitsToSpecializations(nodeData); + + verifyConstructors(nodeData); - if (!verifyNamesUnique(specializations)) { - return null; +// if (!verifyNamingConvention(specializations, "do")) { +// return null; +// } +// +// if (!verifyNamesUnique(specializations)) { +// return null; +// } + + verifyNamingConvention(nodeData.getShortCircuits(), "needs"); + + verifySpecializationThrows(nodeData); + } + + private NodeData parseNodeData(TypeElement templateType, TypeElement nodeType) { + List elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeType)); + List typeHierarchy = findSuperClasses(new ArrayList(), nodeType); + Collections.reverse(typeHierarchy); + NodeData nodeData = new NodeData(templateType, templateType.getSimpleName().toString()); + + AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); + if (typeSystemMirror == null) { + nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), nodeType.getQualifiedName().toString()); + return nodeData; } - if (!verifyNamingConvention(shortCircuits, "needs")) { - return null; + TypeMirror typeSytemType = Utils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value"); + final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true); + if (typeSystem == null) { + nodeData.addError("The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType)); + return nodeData; } - if (!verifySpecializationThrows(typeSystem, specializations)) { - return null; - } + nodeData.setNodeType(nodeType.asType()); + nodeData.setTypeSystem(typeSystem); + + List executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements)); + nodeData.setExecutableTypes(executableTypes); + parsedNodes.put(Utils.getQualifiedName(templateType), nodeData); + + nodeData.setFields(parseFields(elements, typeHierarchy)); return nodeData; } - private boolean verifyMissingAbstractMethods(NodeData nodeData, List elements) { - if (nodeData.needsFactory()) { + private static void verifySpecializationParameters(NodeData nodeData) { + boolean valid = true; + int args = -1; + for (SpecializationData specializationData : nodeData.getSpecializations()) { + int specializationArgs = 0; + for (ActualParameter param : specializationData.getParameters()) { + if (!param.getSpecification().isOptional()) { + specializationArgs++; + } + } + if (args != -1 && args != specializationArgs) { + valid = false; + break; + } + args = specializationArgs; + } + if (!valid) { + for (SpecializationData specialization : nodeData.getSpecializations()) { + specialization.addError("All specializations must have the same number of arguments."); + } + } + } + + private void verifyMissingAbstractMethods(NodeData nodeData) { + if (!nodeData.needsFactory()) { // missing abstract methods only needs to be implemented // if we need go generate factory for it. - return true; + return; } + List elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeData.getTemplateType())); + Set unusedElements = new HashSet<>(elements); for (TemplateMethod method : nodeData.getAllTemplateMethods()) { unusedElements.remove(method.getMethod()); @@ -258,24 +567,20 @@ unusedElements.removeAll(nodeData.getExtensionElements()); } - boolean valid = true; for (ExecutableElement unusedMethod : ElementFilter.methodsIn(unusedElements)) { if (unusedMethod.getModifiers().contains(Modifier.ABSTRACT)) { - context.getLog().error(nodeData.getTemplateType(), "The type %s must implement the inherited abstract method %s.", Utils.getSimpleName(nodeData.getTemplateType()), - Utils.getReadableSignature(unusedMethod)); - valid = false; + nodeData.addError("The type %s must implement the inherited abstract method %s.", Utils.getSimpleName(nodeData.getTemplateType()), Utils.getReadableSignature(unusedMethod)); } } + } + + private void verifyConstructors(NodeData nodeData) { + if (!nodeData.needsRewrites(context)) { + // no specialization constructor is needed if the node never rewrites. + return; + } - return valid; - } - - private boolean verifyConstructors(NodeData nodeData) { TypeElement type = Utils.fromTypeMirror(nodeData.getNodeType()); - if (!nodeData.needsRewrites(context)) { - // no specialization constructor is needed if the node never rewrites. - return true; - } List constructors = ElementFilter.constructorsIn(type.getEnclosedElements()); for (ExecutableElement e : constructors) { @@ -283,20 +588,17 @@ TypeMirror firstArg = e.getParameters().get(0).asType(); if (Utils.typeEquals(firstArg, nodeData.getNodeType())) { if (e.getModifiers().contains(Modifier.PRIVATE)) { - context.getLog().error(e, "The specialization constructor must not be private."); - return false; + nodeData.addError("The specialization constructor must not be private."); } else if (constructors.size() <= 1) { - context.getLog().error(e, "The specialization constructor must not be the only constructor. The definition of an alternative constructor is required."); - return false; + nodeData.addError("The specialization constructor must not be the only constructor. The definition of an alternative constructor is required."); } - return true; + return; } } } // not found - context.getLog().error(type, "Specialization constructor '%s(%s previousNode) { this(...); }' is required.", Utils.getSimpleName(type), Utils.getSimpleName(type)); - return false; + nodeData.addError("Specialization constructor '%s(%s previousNode) { this(...); }' is required.", Utils.getSimpleName(type), Utils.getSimpleName(type)); } private static List filterExecutableTypes(List executableTypes) { @@ -343,13 +645,13 @@ return null; } - private NodeFieldData[] parseFields(NodeData nodeData, List elements, final List typeHierarchy) { + private List parseFields(List elements, final List typeHierarchy) { AnnotationMirror executionOrderMirror = findFirstAnnotation(typeHierarchy, ExecuteChildren.class); List executionDefinition = null; if (executionOrderMirror != null) { executionDefinition = new ArrayList<>(); - for (Object object : Utils.getAnnotationValueList(executionOrderMirror, "value")) { - executionDefinition.add((String) object); + for (String object : Utils.getAnnotationValueList(String.class, executionOrderMirror, "value")) { + executionDefinition.add(object); } } @@ -357,12 +659,10 @@ for (ExecutableElement method : ElementFilter.methodsIn(elements)) { AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class); if (mirror != null) { - shortCircuits.add(Utils.getAnnotationValueString(mirror, "value")); + shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value")); } } - boolean valid = true; - List fields = new ArrayList<>(); for (VariableElement var : ElementFilter.fieldsIn(elements)) { if (var.getModifiers().contains(Modifier.STATIC)) { @@ -375,27 +675,16 @@ } } - NodeFieldData field = parseField(nodeData, var, shortCircuits); + NodeFieldData field = parseField(var, shortCircuits); if (field != null) { - if (field.getExecutionKind() != ExecutionKind.IGNORE) { - fields.add(field); - } - } else { - valid = false; + fields.add(field); } } - - // TODO parse getters - if (!valid) { - return null; - } - - NodeFieldData[] fieldArray = fields.toArray(new NodeFieldData[fields.size()]); - sortByExecutionOrder(fieldArray, executionDefinition == null ? Collections. emptyList() : executionDefinition, typeHierarchy); - return fieldArray; + sortByExecutionOrder(fields, executionDefinition == null ? Collections. emptyList() : executionDefinition, typeHierarchy); + return fields; } - private NodeFieldData parseField(NodeData parentNodeData, VariableElement var, Set foundShortCircuits) { + private NodeFieldData parseField(VariableElement var, Set foundShortCircuits) { AnnotationMirror childMirror = Utils.findAnnotationMirror(processingEnv, var, Child.class); AnnotationMirror childrenMirror = Utils.findAnnotationMirror(processingEnv, var, Children.class); @@ -409,45 +698,40 @@ } AnnotationMirror mirror; - TypeMirror nodeType; + TypeMirror type; if (childMirror != null) { mirror = childMirror; - nodeType = var.asType(); + type = var.asType(); kind = FieldKind.CHILD; } else if (childrenMirror != null) { mirror = childrenMirror; - nodeType = getComponentType(var.asType()); + type = getComponentType(var.asType()); kind = FieldKind.CHILDREN; } else { + execution = ExecutionKind.IGNORE; + type = var.asType(); mirror = null; - nodeType = null; kind = FieldKind.FIELD; - execution = ExecutionKind.IGNORE; } - NodeData fieldNodeData = null; - if (nodeType != null) { - fieldNodeData = resolveNode(Utils.fromTypeMirror(nodeType)); - Element errorElement = Utils.typeEquals(parentNodeData.getTemplateType().asType(), var.getEnclosingElement().asType()) ? var : parentNodeData.getTemplateType(); + NodeFieldData fieldData = new NodeFieldData(var, findAccessElement(var), mirror, kind, execution); + if (type != null && mirror != null) { + NodeData fieldNodeData = resolveNode(Utils.fromTypeMirror(type)); + fieldData.setNode(fieldNodeData); if (fieldNodeData == null) { - // TODO redirect errors from resolve. - context.getLog().error(errorElement, "Node type '%s' is invalid.", Utils.getQualifiedName(nodeType)); - return null; - } else if (fieldNodeData.findGenericExecutableType(context) == null) { - // TODO better error handling for (no or multiple?) - context.getLog().error(errorElement, "No or multiple executable generic types found for node '%s'.", Utils.getQualifiedName(nodeType)); - return null; + fieldData.addError("Node type '%s' is invalid.", Utils.getQualifiedName(type)); + } else if (fieldNodeData.findGenericExecutableTypes(context).isEmpty()) { + fieldData.addError("No executable generic types found for node '%s'.", Utils.getQualifiedName(type)); } } - // TODO correct handling of access elements - if (var.getModifiers().contains(Modifier.PRIVATE) && Utils.typeEquals(var.getEnclosingElement().asType(), parentNodeData.getTemplateType().asType())) { - execution = ExecutionKind.IGNORE; + if (fieldData.getAccessElement().getModifiers().contains(Modifier.PRIVATE)) { + return null; } - return new NodeFieldData(fieldNodeData, var, findAccessElement(var), mirror, kind, execution); + return fieldData; } private Element findAccessElement(VariableElement variableElement) { @@ -470,16 +754,15 @@ break; } } - - if (getter != null) { + if (getter != null && !getter.getModifiers().contains(Modifier.PRIVATE)) { return getter; } else { return variableElement; } } - private static void sortByExecutionOrder(NodeFieldData[] fields, final List executionOrder, final List typeHierarchy) { - Arrays.sort(fields, new Comparator() { + private static void sortByExecutionOrder(List fields, final List executionOrder, final List typeHierarchy) { + Collections.sort(fields, new Comparator() { @Override public int compare(NodeFieldData o1, NodeFieldData o2) { @@ -501,18 +784,16 @@ }); } - private boolean assignShortCircuitsToSpecializations(NodeData nodeData, List specializations, List shortCircuits) { - - Map> groupedShortCircuits = groupShortCircuits(shortCircuits); + private void assignShortCircuitsToSpecializations(NodeData node) { + Map> groupedShortCircuits = groupShortCircuits(node.getShortCircuits()); boolean valid = true; - - for (NodeFieldData field : nodeData.filterFields(null, ExecutionKind.SHORT_CIRCUIT)) { + for (NodeFieldData field : node.filterFields(null, ExecutionKind.SHORT_CIRCUIT)) { String valueName = field.getName(); List availableCircuits = groupedShortCircuits.get(valueName); if (availableCircuits == null || availableCircuits.isEmpty()) { - log.error(nodeData.getTemplateType(), "@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName); + node.addError("@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName); valid = false; continue; } @@ -527,7 +808,7 @@ if (!sameMethodName) { for (ShortCircuitData circuit : availableCircuits) { - log.error(circuit.getMethod(), circuit.getMarkerAnnotation(), "All short circuits for short cut value '%s' must have the same method name.", valueName); + circuit.addError("All short circuits for short cut value '%s' must have the same method name.", valueName); } valid = false; continue; @@ -535,14 +816,14 @@ ShortCircuitData genericCircuit = null; for (ShortCircuitData circuit : availableCircuits) { - if (isGenericShortCutMethod(nodeData, circuit)) { + if (isGenericShortCutMethod(node, circuit)) { genericCircuit = circuit; break; } } if (genericCircuit == null) { - log.error(nodeData.getTemplateType(), "No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName); + node.addError("No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName); valid = false; continue; } @@ -555,70 +836,59 @@ } if (!valid) { - return valid; + return; } - NodeFieldData[] fields = nodeData.filterFields(null, ExecutionKind.SHORT_CIRCUIT); - for (SpecializationData specialization : specializations) { - ShortCircuitData[] assignedShortCuts = new ShortCircuitData[fields.length]; + NodeFieldData[] fields = node.filterFields(null, ExecutionKind.SHORT_CIRCUIT); + for (SpecializationData specialization : node.getSpecializations()) { + List assignedShortCuts = new ArrayList<>(fields.length); for (int i = 0; i < fields.length; i++) { List availableShortCuts = groupedShortCircuits.get(fields[i].getName()); ShortCircuitData genericShortCircuit = null; + ShortCircuitData compatibleShortCircuit = null; for (ShortCircuitData circuit : availableShortCuts) { if (circuit.isGeneric()) { genericShortCircuit = circuit; } else if (circuit.isCompatibleTo(specialization)) { - assignedShortCuts[i] = circuit; + compatibleShortCircuit = circuit; } } - if (assignedShortCuts[i] == null) { - assignedShortCuts[i] = genericShortCircuit; + if (compatibleShortCircuit == null) { + compatibleShortCircuit = genericShortCircuit; } + assignedShortCuts.add(compatibleShortCircuit); } specialization.setShortCircuits(assignedShortCuts); } - return true; } - private boolean verifyNamingConvention(List methods, String prefix) { - boolean valid = true; + private static void verifyNamingConvention(List methods, String prefix) { for (int i = 0; i < methods.size(); i++) { TemplateMethod m1 = methods.get(i); if (m1.getMethodName().length() < 3 || !m1.getMethodName().startsWith(prefix)) { - log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Naming convention: method name must start with '%s'.", prefix); - valid = false; + m1.addError("Naming convention: method name must start with '%s'.", prefix); } } - return valid; } - private boolean verifyNamesUnique(List methods) { - boolean valid = true; - for (int i = 0; i < methods.size(); i++) { - TemplateMethod m1 = methods.get(i); - for (int j = i + 1; j < methods.size(); j++) { - TemplateMethod m2 = methods.get(j); - - if (m1.getMethodName().equalsIgnoreCase(m2.getMethodName())) { - log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Method name '%s' used multiple times", m1.getMethodName()); - log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Method name '%s' used multiple times", m1.getMethodName()); - return false; + private boolean isGenericShortCutMethod(NodeData node, TemplateMethod method) { + for (ActualParameter parameter : method.getParameters()) { + NodeFieldData field = node.findField(parameter.getSpecification().getName()); + if (field == null || field.getKind() == FieldKind.FIELD) { + continue; + } + ExecutableTypeData found = null; + List executableElements = field.getNodeData().findGenericExecutableTypes(context); + for (ExecutableTypeData executable : executableElements) { + if (executable.getType().equalsType(parameter.getActualTypeData(node.getTypeSystem()))) { + found = executable; + break; } } - } - return valid; - } - - private static boolean isGenericShortCutMethod(NodeData node, TemplateMethod method) { - for (NodeFieldData field : node.getFields()) { - ActualParameter parameter = method.findParameter(field.getName()); - if (parameter == null) { - continue; - } - if (!Utils.typeEquals(node.getTypeSystem().getGenericType(), parameter.getActualType())) { + if (found == null) { return false; } } @@ -656,7 +926,10 @@ return collection; } - private boolean verifySpecializationOrder(TypeSystemData typeSystem, List specializations) { + private static void verifySpecializationOrder(NodeData node) { + TypeSystemData typeSystem = node.getTypeSystem(); + List specializations = node.getSpecializations(); + for (int i = 0; i < specializations.size(); i++) { SpecializationData m1 = specializations.get(i); for (int j = i + 1; j < specializations.size(); j++) { @@ -666,56 +939,39 @@ if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) { int specOrder = m1.getOrder() - m2.getOrder(); if (specOrder == 0) { - log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Order value %d used multiple times", m1.getOrder()); - log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Order value %d used multiple times", m1.getOrder()); - return false; + m1.addError("Order value %d used multiple times", m1.getOrder()); + m2.addError("Order value %d used multiple times", m1.getOrder()); + return; } else if ((specOrder < 0 && inferredOrder > 0) || (specOrder > 0 && inferredOrder < 0)) { - log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); - log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); - return false; + m1.addError("Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); + m2.addError("Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); + return; } } else if (inferredOrder == 0) { SpecializationData m = (m1.getOrder() == Specialization.DEFAULT_ORDER ? m1 : m2); - log.error(m.getMethod(), m.getMarkerAnnotation(), "Cannot calculate a consistent order for this specialization. Define the order attribute to resolve this."); - return false; + m.addError("Cannot calculate a consistent order for this specialization. Define the order attribute to resolve this."); + return; } } } - return true; } - private boolean verifySpecializationThrows(TypeSystemData typeSystem, List specializations) { + private static void verifySpecializationThrows(NodeData node) { Map specializationMap = new HashMap<>(); - for (SpecializationData spec : specializations) { + for (SpecializationData spec : node.getSpecializations()) { specializationMap.put(spec.getMethodName(), spec); } - boolean valid = true; - for (SpecializationData sourceSpecialization : specializations) { + for (SpecializationData sourceSpecialization : node.getSpecializations()) { if (sourceSpecialization.getExceptions() != null) { for (SpecializationThrowsData throwsData : sourceSpecialization.getExceptions()) { - SpecializationData targetSpecialization = specializationMap.get(throwsData.getTransitionToName()); - AnnotationValue value = Utils.getAnnotationValue(throwsData.getAnnotationMirror(), "transitionTo"); - - if (targetSpecialization == null) { - log.error(throwsData.getSpecialization().getMethod(), throwsData.getAnnotationMirror(), value, "Specialization with name '%s' not found.", throwsData.getTransitionToName()); - valid = false; - } else if (compareSpecialization(typeSystem, sourceSpecialization, targetSpecialization) >= 0) { - log.error(throwsData.getSpecialization().getMethod(), throwsData.getAnnotationMirror(), value, - "The order of the target specializalization must be higher than the source specialization.", throwsData.getTransitionToName()); - valid = false; - } - for (SpecializationThrowsData otherThrowsData : sourceSpecialization.getExceptions()) { if (otherThrowsData != throwsData && Utils.typeEquals(otherThrowsData.getJavaClass(), throwsData.getJavaClass())) { - AnnotationValue javaClassValue = Utils.getAnnotationValue(throwsData.getAnnotationMirror(), "javaClass"); - log.error(throwsData.getSpecialization().getMethod(), throwsData.getAnnotationMirror(), javaClassValue, "Duplicate exception type.", throwsData.getTransitionToName()); - valid = false; + throwsData.addError("Duplicate exception type."); } } } } } - return valid; } private static int compareSpecialization(TypeSystemData typeSystem, SpecializationData m1, SpecializationData m2) { @@ -732,15 +988,34 @@ } private static int compareSpecializationWithoutOrder(TypeSystemData typeSystem, SpecializationData m1, SpecializationData m2) { - if (m1.getSpecification() != m2.getSpecification()) { - throw new UnsupportedOperationException("Cannot compare two specializations with different specifications."); + if (m1 == m2) { + return 0; + } + + if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) { + return m1.getOrder() - m2.getOrder(); + } else if (m1.isUninitialized() && !m2.isUninitialized()) { + return -1; + } else if (!m1.isUninitialized() && m2.isUninitialized()) { + return 1; + } else if (m1.isGeneric() && !m2.isGeneric()) { + return 1; + } else if (!m1.isGeneric() && m2.isGeneric()) { + return -1; + } + + if (m1.getTemplate() != m2.getTemplate()) { + throw new UnsupportedOperationException("Cannot compare two specializations with different templates."); } int result = compareActualParameter(typeSystem, m1.getReturnType(), m2.getReturnType()); - for (ParameterSpec spec : m1.getSpecification().getParameters()) { - ActualParameter p1 = m1.findParameter(spec); - ActualParameter p2 = m2.findParameter(spec); + for (ActualParameter p1 : m1.getParameters()) { + NodeFieldData field = m1.getNode().findField(p1.getSpecification().getName()); + if (field == null) { + continue; + } + ActualParameter p2 = m2.findParameter(p1.getLocalName()); if (p1 != null && p2 != null && !Utils.typeEquals(p1.getActualType(), p2.getActualType())) { int typeResult = compareActualParameter(typeSystem, p1, p2); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitData.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitData.java Thu Mar 21 14:11:13 2013 +0100 @@ -61,8 +61,7 @@ } for (ActualParameter param : getParameters()) { - ParameterSpec paramSpec = param.getSpecification(); - ActualParameter specializationParam = specialization.findParameter(paramSpec.getName()); + ActualParameter specializationParam = specialization.findParameter(param.getLocalName()); if (!Utils.typeEquals(param.getActualType(), specializationParam.getActualType())) { return false; } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java Thu Mar 21 14:11:13 2013 +0100 @@ -48,14 +48,8 @@ @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - String shortCircuitValue = Utils.getAnnotationValueString(mirror, "value"); - - if (!shortCircuitValues.contains(shortCircuitValue)) { - getContext().getLog().error(method, mirror, "Invalid short circuit value %s.", shortCircuitValue); - return null; - } - - return createDefaultMethodSpec(shortCircuitValue); + String shortCircuitValue = Utils.getAnnotationValue(String.class, mirror, "value"); + return createDefaultMethodSpec(method, mirror, shortCircuitValue); } @Override @@ -65,9 +59,12 @@ @Override public ShortCircuitData create(TemplateMethod method) { - String shortCircuitValue = Utils.getAnnotationValueString(method.getMarkerAnnotation(), "value"); - assert shortCircuitValue != null; - assert shortCircuitValues.contains(shortCircuitValue); + String shortCircuitValue = Utils.getAnnotationValue(String.class, method.getMarkerAnnotation(), "value"); + + if (!shortCircuitValues.contains(shortCircuitValue)) { + method.addError("Invalid short circuit value %s.", shortCircuitValue); + } + return new ShortCircuitData(method, shortCircuitValue); } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,7 +22,11 @@ */ package com.oracle.truffle.codegen.processor.node; +import java.util.*; + import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.node.NodeFieldData.*; import com.oracle.truffle.codegen.processor.template.*; public class SpecializationData extends TemplateMethod { @@ -30,13 +34,13 @@ private final int order; private final boolean generic; private final boolean uninitialized; - private final SpecializationThrowsData[] exceptions; - private SpecializationGuardData[] guards; - private ShortCircuitData[] shortCircuits; + private final List exceptions; + private List guards; + private List shortCircuits; private boolean useSpecializationsForGeneric = true; private NodeData node; - public SpecializationData(TemplateMethod template, int order, SpecializationThrowsData[] exceptions) { + public SpecializationData(TemplateMethod template, int order, List exceptions) { super(template); this.order = order; this.generic = false; @@ -53,8 +57,40 @@ this.order = Specialization.DEFAULT_ORDER; this.generic = generic; this.uninitialized = uninitialized; - this.exceptions = new SpecializationThrowsData[0]; - this.guards = new SpecializationGuardData[0]; + this.exceptions = Collections.emptyList(); + this.guards = new ArrayList<>(); + } + + @Override + protected List findChildContainers() { + List sinks = new ArrayList<>(); + if (exceptions != null) { + sinks.addAll(exceptions); + } + if (guards != null) { + sinks.addAll(guards); + } + return sinks; + } + + public boolean hasRewrite(ProcessorContext context) { + if (!getExceptions().isEmpty()) { + return true; + } + if (!getGuards().isEmpty()) { + return true; + } + for (ActualParameter parameter : getParameters()) { + NodeFieldData field = getNode().findField(parameter.getSpecification().getName()); + if (field == null || field.getKind() == FieldKind.FIELD) { + continue; + } + ExecutableTypeData type = field.getNodeData().findExecutableType(parameter.getActualTypeData(field.getNodeData().getTypeSystem())); + if (type.hasUnexpectedValue(context)) { + return true; + } + } + return false; } public NodeData getNode() { @@ -65,7 +101,7 @@ this.node = node; } - public void setGuards(SpecializationGuardData[] guards) { + public void setGuards(List guards) { this.guards = guards; } @@ -81,19 +117,19 @@ return uninitialized; } - public SpecializationThrowsData[] getExceptions() { + public List getExceptions() { return exceptions; } - public SpecializationGuardData[] getGuards() { + public List getGuards() { return guards; } - public void setShortCircuits(ShortCircuitData[] shortCircuits) { + public void setShortCircuits(List shortCircuits) { this.shortCircuits = shortCircuits; } - public ShortCircuitData[] getShortCircuits() { + public List getShortCircuits() { return shortCircuits; } @@ -106,10 +142,10 @@ } public SpecializationData findNextSpecialization() { - SpecializationData[] specializations = node.getSpecializations(); - for (int i = 0; i < specializations.length - 1; i++) { - if (specializations[i] == this) { - return specializations[i + 1]; + List specializations = node.getSpecializations(); + for (int i = 0; i < specializations.size() - 1; i++) { + if (specializations.get(i) == this) { + return specializations.get(i + 1); } } return null; @@ -124,15 +160,4 @@ return false; } - public ActualParameter getPreviousParam(ActualParameter searchParam) { - ActualParameter prev = null; - for (ActualParameter param : getParameters()) { - if (param == searchParam) { - return prev; - } - prev = param; - } - return prev; - } - } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationGuardData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationGuardData.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationGuardData.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,20 +22,42 @@ */ package com.oracle.truffle.codegen.processor.node; +import javax.lang.model.element.*; + +import com.oracle.truffle.codegen.processor.template.*; import com.oracle.truffle.codegen.processor.typesystem.*; -public class SpecializationGuardData { +public class SpecializationGuardData extends MessageContainer { + private final SpecializationData specialization; + private final AnnotationValue value; private final String guardMethod; private final boolean onSpecialization; private final boolean onExecution; private GuardData guardDeclaration; - public SpecializationGuardData(String guardMethod, boolean onSpecialization, boolean onExecution) { + public SpecializationGuardData(SpecializationData specialization, AnnotationValue value, String guardMethod, boolean onSpecialization, boolean onExecution) { + this.specialization = specialization; this.guardMethod = guardMethod; this.onSpecialization = onSpecialization; this.onExecution = onExecution; + this.value = value; + } + + @Override + public Element getMessageElement() { + return specialization.getMessageElement(); + } + + @Override + public AnnotationMirror getMessageAnnotation() { + return specialization.getMessageAnnotation(); + } + + @Override + public AnnotationValue getMessageAnnotationValue() { + return value; } public String getGuardMethod() { diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerData.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,33 @@ +/* + * 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.truffle.codegen.processor.node; + +import com.oracle.truffle.codegen.processor.template.*; + +public class SpecializationListenerData extends TemplateMethod { + + public SpecializationListenerData(TemplateMethod method) { + super(method); + } + +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java Thu Mar 21 14:11:13 2013 +0100 @@ -30,18 +30,15 @@ import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; -public class SpecializationListenerParser extends MethodParser { - - private final MethodSpec specification; +public class SpecializationListenerParser extends MethodParser { public SpecializationListenerParser(ProcessorContext context, NodeData node) { super(context, node); - this.specification = createDefaultMethodSpec(null); } @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - return specification; + return createDefaultMethodSpec(method, mirror, null); } @Override @@ -50,8 +47,8 @@ } @Override - public TemplateMethod create(TemplateMethod method) { - return method; + public SpecializationListenerData create(TemplateMethod method) { + return new SpecializationListenerData(method); } @Override diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java Thu Mar 21 14:11:13 2013 +0100 @@ -35,20 +35,13 @@ public class SpecializationMethodParser extends MethodParser { - private final MethodSpec specification; - public SpecializationMethodParser(ProcessorContext context, NodeData operation) { super(context, operation); - this.specification = createDefaultMethodSpec(null); } @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - return specification; - } - - public MethodSpec getSpecification() { - return specification; + return createDefaultMethodSpec(method, mirror, null); } @Override @@ -62,27 +55,24 @@ } private SpecializationData parseSpecialization(TemplateMethod method) { - int order = Utils.getAnnotationValueInt(method.getMarkerAnnotation(), "order"); + int order = Utils.getAnnotationValue(Integer.class, method.getMarkerAnnotation(), "order"); if (order < 0 && order != Specialization.DEFAULT_ORDER) { - getContext().getLog().error(method.getMethod(), method.getMarkerAnnotation(), "Invalid order attribute %d. The value must be >= 0 or the default value."); + method.addError("Invalid order attribute %d. The value must be >= 0 or the default value."); return null; } - List exceptionDefs = Utils.collectAnnotations(getContext(), method.getMarkerAnnotation(), "exceptions", method.getMethod(), SpecializationThrows.class); - SpecializationThrowsData[] exceptionData = new SpecializationThrowsData[exceptionDefs.size()]; - for (int i = 0; i < exceptionData.length; i++) { - AnnotationMirror mirror = exceptionDefs.get(i); - TypeMirror javaClass = Utils.getAnnotationValueType(mirror, "javaClass"); - String transitionTo = Utils.getAnnotationValueString(mirror, "transitionTo"); - exceptionData[i] = new SpecializationThrowsData(mirror, javaClass, transitionTo); - - if (!Utils.canThrowType(method.getMethod().getThrownTypes(), javaClass)) { - getContext().getLog().error(method.getMethod(), "Method must specify a throws clause with the exception type '%s'.", Utils.getQualifiedName(javaClass)); - return null; + AnnotationValue rewriteValue = Utils.getAnnotationValue(method.getMarkerAnnotation(), "rewriteOn"); + List exceptionTypes = Utils.getAnnotationValueList(TypeMirror.class, method.getMarkerAnnotation(), "rewriteOn"); + List exceptionData = new ArrayList<>(); + for (TypeMirror exceptionType : exceptionTypes) { + SpecializationThrowsData throwsData = new SpecializationThrowsData(method.getMarkerAnnotation(), rewriteValue, exceptionType); + if (!Utils.canThrowType(method.getMethod().getThrownTypes(), exceptionType)) { + throwsData.addError("Method must specify a throws clause with the exception type '%s'.", Utils.getQualifiedName(exceptionType)); } + exceptionData.add(throwsData); } - Arrays.sort(exceptionData, new Comparator() { + Collections.sort(exceptionData, new Comparator() { @Override public int compare(SpecializationThrowsData o1, SpecializationThrowsData o2) { @@ -90,42 +80,28 @@ } }); SpecializationData specialization = new SpecializationData(method, order, exceptionData); - boolean valid = true; - List guardDefs = Utils.collectAnnotations(getContext(), method.getMarkerAnnotation(), "guards", method.getMethod(), SpecializationGuard.class); - SpecializationGuardData[] guardData = new SpecializationGuardData[guardDefs.size()]; - for (int i = 0; i < guardData.length; i++) { - AnnotationMirror guardMirror = guardDefs.get(i); - String guardMethod = Utils.getAnnotationValueString(guardMirror, "methodName"); - boolean onSpecialization = Utils.getAnnotationValueBoolean(guardMirror, "onSpecialization"); - boolean onExecution = Utils.getAnnotationValueBoolean(guardMirror, "onExecution"); + AnnotationValue guardsValue = Utils.getAnnotationValue(method.getMarkerAnnotation(), "guards"); + List guardDefs = Utils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards"); + List guardData = new ArrayList<>(guardDefs.size()); + for (int i = 0; i < guardDefs.size(); i++) { + String guardMethod = guardDefs.get(i); - if (!onSpecialization && !onExecution) { - String message = "Either onSpecialization, onExecution or both must be enabled."; - getContext().getLog().error(method.getMethod(), guardMirror, message); - valid = false; - continue; - } + SpecializationGuardData assignedGuard = new SpecializationGuardData(specialization, guardsValue, guardMethod, true, true); - guardData[i] = new SpecializationGuardData(guardMethod, onSpecialization, onExecution); + guardData.add(assignedGuard); - GuardData compatibleGuard = matchSpecializationGuard(guardMirror, specialization, guardData[i]); + GuardData compatibleGuard = matchSpecializationGuard(specialization, assignedGuard); if (compatibleGuard != null) { - guardData[i].setGuardDeclaration(compatibleGuard); - } else { - valid = false; + assignedGuard.setGuardDeclaration(compatibleGuard); } } - if (!valid) { - return null; - } - specialization.setGuards(guardData); return specialization; } - private GuardData matchSpecializationGuard(AnnotationMirror mirror, SpecializationData specialization, SpecializationGuardData specializationGuard) { + private GuardData matchSpecializationGuard(SpecializationData specialization, SpecializationGuardData specializationGuard) { List foundGuards = getNode().findGuards(specializationGuard.getGuardMethod()); GuardData compatibleGuard = null; @@ -146,28 +122,33 @@ } List typeDefs = createTypeDefinitions(returnTypeSpec, expectedParameterSpecs); String expectedSignature = TemplateMethodParser.createExpectedSignature(specializationGuard.getGuardMethod(), returnTypeSpec, expectedParameterSpecs, typeDefs); - AnnotationValue value = Utils.getAnnotationValue(mirror, "methodName"); - getContext().getLog().error(specialization.getMethod(), mirror, value, "No guard with signature '%s' found in type system.", expectedSignature); - return null; + specializationGuard.addError("No guard with signature '%s' found in type system.", expectedSignature); } return compatibleGuard; } private static boolean isGuardCompatible(SpecializationData specialization, GuardData guard) { - Iterator guardParameters = Arrays.asList(guard.getParameters()).iterator(); + Iterator guardParameters = guard.getParameters().iterator(); for (ActualParameter param : specialization.getParameters()) { + if (param.getSpecification().isOptional()) { + continue; + } if (!guardParameters.hasNext()) { return false; } ActualParameter guardParam = guardParameters.next(); - if (!Utils.typeEquals(guardParam.getActualType(), param.getActualType())) { + if (!Utils.typeEquals(guardParam.getActualType(), param.getActualType()) && !guardParam.getSpecification().isOptional()) { return false; } } - if (guardParameters.hasNext()) { - return false; + while (guardParameters.hasNext()) { + ActualParameter param = guardParameters.next(); + if (!param.getSpecification().isOptional()) { + return false; + } } + return true; } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationThrowsData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationThrowsData.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationThrowsData.java Thu Mar 21 14:11:13 2013 +0100 @@ -25,23 +25,40 @@ import javax.lang.model.element.*; import javax.lang.model.type.*; -public class SpecializationThrowsData { +import com.oracle.truffle.codegen.processor.template.*; +public class SpecializationThrowsData extends MessageContainer { + + private final AnnotationValue annotationValue; private final AnnotationMirror annotationMirror; private final TypeMirror javaClass; - private final String transitionTo; private SpecializationData specialization; - public SpecializationThrowsData(AnnotationMirror annotationMirror, TypeMirror javaClass, String transitionTo) { + public SpecializationThrowsData(AnnotationMirror annotationMirror, AnnotationValue value, TypeMirror javaClass) { this.annotationMirror = annotationMirror; + this.annotationValue = value; this.javaClass = javaClass; - this.transitionTo = transitionTo; } void setSpecialization(SpecializationData specialization) { this.specialization = specialization; } + @Override + public Element getMessageElement() { + return specialization.getMessageElement(); + } + + @Override + public AnnotationMirror getMessageAnnotation() { + return annotationMirror; + } + + @Override + public AnnotationValue getMessageAnnotationValue() { + return annotationValue; + } + public TypeMirror getJavaClass() { return javaClass; } @@ -54,16 +71,7 @@ return annotationMirror; } - public String getTransitionToName() { - return transitionTo; - } - public SpecializationData getTransitionTo() { - for (SpecializationData s : specialization.getNode().getSpecializations()) { - if (s.getMethodName().equals(transitionTo)) { - return s; - } - } - return null; + return specialization.findNextSpecialization(); } } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java Thu Mar 21 14:11:13 2013 +0100 @@ -30,16 +30,49 @@ private final ParameterSpec specification; private final TypeMirror actualType; + private TemplateMethod method; + private final String localName; + private final int index; + private final boolean implicit; - public ActualParameter(ParameterSpec specification, TypeMirror actualType) { + public ActualParameter(ParameterSpec specification, TypeMirror actualType, int index, boolean implicit) { this.specification = specification; this.actualType = actualType; + + this.index = index; + this.implicit = implicit; + String valueName = specification.getName() + "Value"; + + if (specification.isIndexed()) { + valueName += index; + } + this.localName = valueName; + } + + public boolean isImplicit() { + return implicit; + } + + public int getIndex() { + return index; + } + + public String getLocalName() { + return localName; + } + + void setMethod(TemplateMethod method) { + this.method = method; } public ParameterSpec getSpecification() { return specification; } + public TemplateMethod getMethod() { + return method; + } + public TypeMirror getActualType() { return actualType; } @@ -47,4 +80,8 @@ public TypeData getActualTypeData(TypeSystemData typeSystem) { return typeSystem.findTypeData(actualType); } + + public ActualParameter getPreviousParameter() { + return method.getPreviousParam(this); + } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ClassElementFactory.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ClassElementFactory.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ClassElementFactory.java Thu Mar 21 14:11:13 2013 +0100 @@ -128,6 +128,10 @@ CodeAnnotationMirror generatedByAnnotation = new CodeAnnotationMirror((DeclaredType) getContext().getType(GeneratedBy.class)); generatedByAnnotation.setElementValue(generatedByAnnotation.findExecutableElement("value"), new CodeAnnotationValue(templateType.asType())); + if (model.getTemplateMethodName() != null) { + generatedByAnnotation.setElementValue(generatedByAnnotation.findExecutableElement("methodName"), new CodeAnnotationValue(model.getTemplateMethodName())); + } + clazz.addAnnotationMirror(generatedByAnnotation); context.registerType(model.getTemplateType(), clazz.asType()); diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MessageContainer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MessageContainer.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,181 @@ +/* + * 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.truffle.codegen.processor.template; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.tools.Diagnostic.Kind; + +import com.oracle.truffle.codegen.processor.*; + +public abstract class MessageContainer { + + private final List messages = new ArrayList<>(); + + public final void addWarning(String text, Object... params) { + getMessages().add(new Message(this, String.format(text, params), Kind.WARNING)); + } + + public final void addError(String text, Object... params) { + getMessages().add(new Message(this, String.format(text, params), Kind.ERROR)); + } + + protected List findChildContainers() { + return Collections.emptyList(); + } + + public abstract Element getMessageElement(); + + public final void emitMessages(TypeElement baseElement, Log log) { + emitMessagesImpl(baseElement, log, new HashSet()); + } + + private void emitMessagesImpl(TypeElement baseElement, Log log, Set visitedSinks) { + for (Message message : getMessages()) { + emitDefault(baseElement, log, message); + } + + for (MessageContainer sink : findChildContainers()) { + if (visitedSinks.contains(sink)) { + continue; + } + + visitedSinks.add(sink); + sink.emitMessagesImpl(baseElement, log, visitedSinks); + } + } + + private void emitDefault(TypeElement baseType, Log log, Message message) { + TypeElement rootEnclosing = Utils.findRootEnclosingType(getMessageElement()); + if (rootEnclosing != null && Utils.typeEquals(baseType.asType(), rootEnclosing.asType()) && this == message.getOriginalContainer()) { + log.message(message.getKind(), getMessageElement(), getMessageAnnotation(), getMessageAnnotationValue(), message.getText()); + } else { + MessageContainer original = message.getOriginalContainer(); + log.message(message.getKind(), baseType, null, null, wrapText(original.getMessageElement(), original.getMessageAnnotation(), message.getText())); + } + } + + private static String wrapText(Element element, AnnotationMirror mirror, String text) { + StringBuilder b = new StringBuilder(); + if (element != null) { + b.append("Element " + element.toString()); + } + if (mirror != null) { + b.append(" at annotation @" + Utils.getSimpleName(mirror.getAnnotationType())); + } + + if (b.length() > 0) { + b.append(" is erroneous: ").append(text); + return b.toString(); + } else { + return text; + } + } + + public AnnotationMirror getMessageAnnotation() { + return null; + } + + public AnnotationValue getMessageAnnotationValue() { + return null; + } + + public final boolean hasErrors() { + return hasErrorsImpl(new HashSet()); + } + + public final List collectMessages() { + List collectedMessages = new ArrayList<>(); + collectMessagesImpl(collectedMessages, new HashSet()); + return collectedMessages; + } + + private void collectMessagesImpl(List collectedMessages, Set visitedSinks) { + collectedMessages.addAll(getMessages()); + for (MessageContainer sink : findChildContainers()) { + if (visitedSinks.contains(sink)) { + return; + } + + visitedSinks.add(sink); + sink.collectMessagesImpl(collectedMessages, visitedSinks); + } + } + + private boolean hasErrorsImpl(Set visitedSinks) { + for (Message msg : getMessages()) { + if (msg.getKind() == Kind.ERROR) { + return true; + } + } + for (MessageContainer sink : findChildContainers()) { + if (visitedSinks.contains(sink)) { + return false; + } + + visitedSinks.add(sink); + + if (sink.hasErrorsImpl(visitedSinks)) { + return true; + } + } + return false; + } + + public List getMessages() { + return messages; + } + + public static final class Message { + + private final MessageContainer originalContainer; + private final String text; + private final Kind kind; + + public Message(MessageContainer originalContainer, String text, Kind kind) { + this.originalContainer = originalContainer; + this.text = text; + this.kind = kind; + } + + public MessageContainer getOriginalContainer() { + return originalContainer; + } + + public String getText() { + return text; + } + + public Kind getKind() { + return kind; + } + + @Override + public String toString() { + return kind + ": " + text; + } + + } + +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,16 +24,25 @@ import java.util.*; +import javax.lang.model.type.*; + public class MethodSpec { + private final List implicitTypes; + private final ParameterSpec returnType; private final List parameters; - public MethodSpec(ParameterSpec returnType, List parameters) { + public MethodSpec(List prefixTypes, ParameterSpec returnType, List parameters) { + this.implicitTypes = prefixTypes; this.returnType = returnType; this.parameters = parameters; } + public List getImplicitTypes() { + return implicitTypes; + } + public ParameterSpec getReturnType() { return returnType; } @@ -41,4 +50,14 @@ public List getParameters() { return parameters; } + + public ParameterSpec findParameterSpec(String name) { + for (ParameterSpec spec : parameters) { + if (spec.getName().equals(name)) { + return spec; + } + } + return null; + } + } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java Thu Mar 21 14:11:13 2013 +0100 @@ -37,13 +37,13 @@ } private final String name; - private final TypeMirror[] allowedTypes; - private final TypeMirror valueType; + private final List allowedTypes; private final boolean optional; - private final Cardinality cardinality; + private Cardinality cardinality; + private boolean indexed; + private boolean local; - public ParameterSpec(String name, TypeMirror[] allowedTypes, TypeMirror valueType, boolean optional, Cardinality cardinality) { - this.valueType = valueType; + public ParameterSpec(String name, List allowedTypes, boolean optional, Cardinality cardinality) { this.allowedTypes = allowedTypes; this.name = name; this.optional = optional; @@ -52,20 +52,40 @@ /** Type constructor. */ public ParameterSpec(String name, TypeMirror singleFixedType, boolean optional) { - this(name, new TypeMirror[]{singleFixedType}, singleFixedType, optional, Cardinality.ONE); + this(name, Arrays.asList(singleFixedType), optional, Cardinality.ONE); } /** Type system value constructor. */ public ParameterSpec(String name, TypeSystemData typeSystem, boolean optional, Cardinality cardinality) { - this(name, typeSystem.getPrimitiveTypeMirrors(), typeSystem.getGenericType(), optional, cardinality); + this(name, typeSystem.getPrimitiveTypeMirrors(), optional, cardinality); } /** Node value constructor. */ public ParameterSpec(String name, NodeData nodeData, boolean optional, Cardinality cardinality) { - this(name, nodeTypeMirrors(nodeData), nodeData.getTypeSystem().getGenericType(), optional, cardinality); + this(name, nodeTypeMirrors(nodeData), optional, cardinality); + } + + public void setLocal(boolean local) { + this.local = local; + } + + public boolean isLocal() { + return local; } - private static TypeMirror[] nodeTypeMirrors(NodeData nodeData) { + public boolean isIndexed() { + return indexed; + } + + public void setIndexed(boolean indexed) { + this.indexed = indexed; + } + + public void setCardinality(Cardinality cardinality) { + this.cardinality = cardinality; + } + + private static List nodeTypeMirrors(NodeData nodeData) { Set typeMirrors = new LinkedHashSet<>(); for (ExecutableTypeData typeData : nodeData.getExecutableTypes()) { @@ -74,7 +94,7 @@ typeMirrors.add(nodeData.getTypeSystem().getGenericType()); - return typeMirrors.toArray(new TypeMirror[typeMirrors.size()]); + return new ArrayList<>(typeMirrors); } public final String getName() { @@ -89,13 +109,12 @@ return cardinality; } - public TypeMirror[] getAllowedTypes() { + public List getAllowedTypes() { return allowedTypes; } public boolean matches(TypeMirror actualType) { - for (int i = 0; i < allowedTypes.length; i++) { - TypeMirror mirror = allowedTypes[i]; + for (TypeMirror mirror : allowedTypes) { if (Utils.typeEquals(actualType, mirror)) { return true; } @@ -103,7 +122,4 @@ return false; } - public TypeMirror getValueType() { - return valueType; - } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java Thu Mar 21 14:11:13 2013 +0100 @@ -29,18 +29,34 @@ import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.api.element.*; -public abstract class Template { +public abstract class Template extends MessageContainer { private final TypeElement templateType; + private final String templateMethodName; private final AnnotationMirror annotation; private List extensionElements; - public Template(TypeElement templateType, AnnotationMirror annotation) { + public Template(TypeElement templateType, String templateMethodName, AnnotationMirror annotation) { this.templateType = templateType; + this.templateMethodName = templateMethodName; this.annotation = annotation; } + @Override + public Element getMessageElement() { + return templateType; + } + + @Override + protected List findChildContainers() { + return Collections.emptyList(); + } + + public String getTemplateMethodName() { + return templateMethodName; + } + public TypeElement getTemplateType() { return templateType; } diff -r dee7c8b578c7 -r c3657d00e343 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 Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Thu Mar 21 14:11:13 2013 +0100 @@ -22,33 +22,66 @@ */ package com.oracle.truffle.codegen.processor.template; +import java.util.*; + import javax.lang.model.element.*; +import javax.lang.model.type.*; -public class TemplateMethod { +import com.oracle.truffle.codegen.processor.*; +public class TemplateMethod extends MessageContainer { + + private String id; private final Template template; private final MethodSpec specification; private final ExecutableElement method; private final AnnotationMirror markerAnnotation; private final ActualParameter returnType; - private final ActualParameter[] parameters; + private final List parameters; - public TemplateMethod(Template template, MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, ActualParameter returnType, ActualParameter[] parameters) { + public TemplateMethod(String id, Template template, MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, ActualParameter returnType, + List parameters) { this.template = template; this.specification = specification; this.method = method; this.markerAnnotation = markerAnnotation; this.returnType = returnType; this.parameters = parameters; + this.id = id; + + if (parameters != null) { + for (ActualParameter param : parameters) { + param.setMethod(this); + } + } } public TemplateMethod(TemplateMethod method) { - this.template = method.template; - this.specification = method.specification; - this.method = method.method; - this.markerAnnotation = method.markerAnnotation; - this.returnType = method.returnType; - this.parameters = method.parameters; + this(method.id, method.template, method.specification, method.method, method.markerAnnotation, method.returnType, method.parameters); + getMessages().addAll(method.getMessages()); + } + + @Override + public Element getMessageElement() { + return method; + } + + @Override + public AnnotationMirror getMessageAnnotation() { + return markerAnnotation; + } + + @Override + protected List findChildContainers() { + return Collections.emptyList(); + } + + public void setId(String id) { + this.id = id; + } + + public String getId() { + return id; } public Template getTemplate() { @@ -63,34 +96,50 @@ return returnType; } - public ActualParameter[] getParameters() { + public List getParameters() { return parameters; } public ActualParameter findParameter(String valueName) { for (ActualParameter param : getParameters()) { - if (param.getSpecification().getName().equals(valueName)) { + if (param.getLocalName().equals(valueName)) { return param; } } return null; } + public List getReturnTypeAndParameters() { + List allParameters = new ArrayList<>(getParameters().size() + 1); + allParameters.add(getReturnType()); + allParameters.addAll(getParameters()); + return Collections.unmodifiableList(allParameters); + } + public ActualParameter findParameter(ParameterSpec spec) { for (ActualParameter param : getParameters()) { - if (param.getSpecification() == spec) { + if (param.getSpecification().getName().equals(spec.getName())) { return param; } } return null; } + public boolean canBeAccessedByInstanceOf(TypeMirror type) { + TypeMirror methodType = Utils.findNearestEnclosingType(getMethod()).asType(); + return Utils.isAssignable(type, methodType) || Utils.isAssignable(methodType, type); + } + public ExecutableElement getMethod() { return method; } public String getMethodName() { - return getMethod().getSimpleName().toString(); + if (getMethod() != null) { + return getMethod().getSimpleName().toString(); + } else { + return "$synthetic"; + } } public AnnotationMirror getMarkerAnnotation() { @@ -99,6 +148,17 @@ @Override public String toString() { - return getClass().getSimpleName() + " [method = " + method + "]"; + return "id = " + getId() + ", " + getClass().getSimpleName() + " [method = " + getMethod() + "]"; + } + + public ActualParameter getPreviousParam(ActualParameter searchParam) { + ActualParameter prev = null; + for (ActualParameter param : getParameters()) { + if (param == searchParam) { + return prev; + } + prev = param; + } + return prev; } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java Thu Mar 21 14:11:13 2013 +0100 @@ -31,6 +31,7 @@ import javax.lang.model.type.*; import javax.lang.model.util.*; +import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; @@ -95,19 +96,28 @@ mirror = Utils.findAnnotationMirror(getContext().getEnvironment(), method, annotationType); } - if (method.getModifiers().contains(Modifier.PRIVATE)) { - getContext().getLog().error(method, "Method must not be private."); + E parsedMethod = parse(method, mirror); + + if (method.getModifiers().contains(Modifier.PRIVATE) && emitErrors) { + parsedMethod.addError("Method must not be private."); valid = false; continue; } - E parsedMethod = parse(method, mirror); if (parsedMethod != null) { parsedMethods.add(parsedMethod); } else { valid = false; } } + Collections.sort(parsedMethods, new Comparator() { + + @Override + public int compare(TemplateMethod o1, TemplateMethod o2) { + return o1.getMethodName().compareTo(o2.getMethodName()); + } + }); + if (!valid && parseNullOnError) { return null; } @@ -120,108 +130,140 @@ return null; } + String id = method.getSimpleName().toString(); + AnnotationMirror idAnnotation = Utils.findAnnotationMirror(context.getEnvironment(), method, NodeId.class); + if (idAnnotation != null) { + id = Utils.getAnnotationValue(String.class, idAnnotation, "value"); + } + List typeDefs = createTypeDefinitions(methodSpecification.getReturnType(), methodSpecification.getParameters()); ParameterSpec returnTypeSpec = methodSpecification.getReturnType(); List parameterSpecs = new ArrayList<>(); parameterSpecs.addAll(methodSpecification.getParameters()); - ActualParameter returnTypeMirror = resolveTypeMirror(returnTypeSpec, method.getReturnType(), template); + ActualParameter returnTypeMirror = matchParameter(returnTypeSpec, method.getReturnType(), template, 0, false); if (returnTypeMirror == null) { - if (isEmitErrors()) { + if (emitErrors) { + E invalidMethod = create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList())); String expectedReturnType = createTypeSignature(returnTypeSpec, typeDefs, true); String actualReturnType = Utils.getSimpleName(method.getReturnType()); String message = String.format("The provided return type \"%s\" does not match expected return type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType, createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs)); + invalidMethod.addError(message); + return invalidMethod; + } else { + return null; + } + } - context.getLog().error(method, annotation, message); + List parameterTypes = new ArrayList<>(); + for (VariableElement var : method.getParameters()) { + parameterTypes.add(var.asType()); + } + + List parameters = parseParameters(parameterTypes, methodSpecification.getImplicitTypes(), parameterSpecs); + if (parameters == null) { + if (isEmitErrors()) { + E invalidMethod = create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList())); + String message = String.format("Method signature %s does not match to the expected signature: \n%s", createActualSignature(methodSpecification, method), + createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs)); + invalidMethod.addError(message); + return invalidMethod; + } else { + return null; } - return null; } - Iterator variableIterator = method.getParameters().iterator(); + return create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, parameters)); + } + + private static String createActualSignature(MethodSpec spec, ExecutableElement method) { + List types = new ArrayList<>(); + for (TypeMirror implicitType : spec.getImplicitTypes()) { + types.add("implicit " + Utils.getSimpleName(implicitType)); + } + for (VariableElement var : method.getParameters()) { + types.add(Utils.getSimpleName(var.asType())); + } + + StringBuilder b = new StringBuilder("("); + for (Iterator iterator = types.iterator(); iterator.hasNext();) { + b.append(iterator.next()); + if (iterator.hasNext()) { + b.append(", "); + } + } + b.append(")"); + return b.toString(); + } + + private List parseParameters(List types, List implicitTypes, List parameterSpecs) { + Iterator parameterIterator = types.iterator(); + Iterator implicitParametersIterator = implicitTypes.iterator(); Iterator specificationIterator = parameterSpecs.iterator(); - List resolvedMirrors = new ArrayList<>(); - VariableElement parameter = null; - ParameterSpec specification = null; - while (specificationIterator.hasNext() || specification != null) { - if (specification == null) { - specification = specificationIterator.next(); - } - - if (parameter == null && variableIterator.hasNext()) { - parameter = variableIterator.next(); - } - - if (parameter == null) { - if (specification.getCardinality() == Cardinality.MULTIPLE) { - specification = null; - continue; - } else if (!specification.isOptional()) { - if (isEmitErrors()) { - // non option type specification found -> argument missing - String expectedType = createTypeSignature(specification, typeDefs, false); - - String message = String.format("Missing argument \"%s\".\nExpected signature: \n %s", expectedType, - createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs)); + TypeMirror parameter = parameterIterator.hasNext() ? parameterIterator.next() : null; + TypeMirror implicitParameter = implicitParametersIterator.hasNext() ? implicitParametersIterator.next() : null; + ParameterSpec specification = specificationIterator.hasNext() ? specificationIterator.next() : null; - context.getLog().error(method, message); - } - return null; - } else { - // specification is optional -> continue - specification = null; + int specificationParameterIndex = 0; + List resolvedParameters = new ArrayList<>(); + while (parameter != null || specification != null || implicitParameter != null) { + if (parameter == null || specification == null) { + if (specification != null && (specification.isOptional() || specification.getCardinality() == Cardinality.MULTIPLE)) { + specification = specificationIterator.hasNext() ? specificationIterator.next() : null; + specificationParameterIndex = 0; continue; } - } - - ActualParameter resolvedMirror = resolveTypeMirror(specification, parameter.asType(), template); - - if (resolvedMirror == null) { - if (specification.isOptional()) { - specification = null; - continue; - } - - if (isEmitErrors()) { - String expectedReturnType = createTypeSignature(specification, typeDefs, false); - String actualReturnType = Utils.getSimpleName(parameter.asType()) + " " + parameter.getSimpleName(); - - String message = String.format("The provided argument type \"%s\" does not match expected type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType, - createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs)); - - context.getLog().error(parameter, message); - } return null; } - resolvedMirrors.add(resolvedMirror); - parameter = null; // consume parameter + ActualParameter resolvedParameter = null; + + boolean implicit = false; + if (implicitParameter != null) { + resolvedParameter = matchParameter(specification, implicitParameter, template, specificationParameterIndex, true); + if (resolvedParameter != null) { + implicit = true; + } + } + + if (resolvedParameter == null) { + resolvedParameter = matchParameter(specification, parameter, template, specificationParameterIndex, false); + } - if (specification.getCardinality() != Cardinality.MULTIPLE) { - specification = null; + if (resolvedParameter == null) { + // mismatch + if (specification.isOptional()) { + specification = specificationIterator.hasNext() ? specificationIterator.next() : null; + specificationParameterIndex = 0; + } else { + return null; + } + } else { + resolvedParameters.add(resolvedParameter); + + // match + if (implicit) { + implicitParameter = implicitParametersIterator.hasNext() ? implicitParametersIterator.next() : null; + } else { + parameter = parameterIterator.hasNext() ? parameterIterator.next() : null; + } + + if (specification.getCardinality() == Cardinality.ONE) { + specification = specificationIterator.hasNext() ? specificationIterator.next() : null; + specificationParameterIndex = 0; + } else if (specification.getCardinality() == Cardinality.MULTIPLE) { + specificationParameterIndex++; + } } } - - if (variableIterator.hasNext()) { - parameter = variableIterator.next(); - if (isEmitErrors()) { - String actualReturnType = Utils.getSimpleName(parameter.asType()) + " " + parameter.getSimpleName(); - String message = String.format("No argument expected but found \"%s\".\nExpected signature: \n %s", actualReturnType, - createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs)); - - context.getLog().error(parameter, message); - } - return null; - } - - ActualParameter[] paramMirrors = resolvedMirrors.toArray(new ActualParameter[resolvedMirrors.size()]); - return create(new TemplateMethod(template, methodSpecification, method, annotation, returnTypeMirror, paramMirrors)); + return resolvedParameters; } - private ActualParameter resolveTypeMirror(ParameterSpec specification, TypeMirror mirror, Template typeSystem) { + private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template typeSystem, int index, boolean implicit) { TypeMirror resolvedType = mirror; if (hasError(resolvedType)) { resolvedType = context.resolveNotYetCompiledType(mirror, typeSystem); @@ -230,7 +272,7 @@ if (!specification.matches(resolvedType)) { return null; } - return new ActualParameter(specification, resolvedType); + return new ActualParameter(specification, resolvedType, index, implicit); } protected List createTypeDefinitions(ParameterSpec returnType, List parameters) { @@ -242,12 +284,12 @@ int defIndex = 0; for (ParameterSpec spec : allParams) { - TypeMirror[] allowedTypes = spec.getAllowedTypes(); - TypeMirror[] types = spec.getAllowedTypes(); - if (types != null && allowedTypes.length > 1) { + List allowedTypes = spec.getAllowedTypes(); + List types = spec.getAllowedTypes(); + if (types != null && allowedTypes.size() > 1) { TypeDef foundDef = null; for (TypeDef def : typeDefs) { - if (Arrays.equals(allowedTypes, def.getTypes())) { + if (allowedTypes.equals(def.getTypes())) { foundDef = def; break; } @@ -267,11 +309,11 @@ protected static class TypeDef { - private final TypeMirror[] types; + private final List types; private final String name; private final List parameters = new ArrayList<>(); - public TypeDef(TypeMirror[] types, String name) { + public TypeDef(List types, String name) { this.types = types; this.name = name; } @@ -280,7 +322,7 @@ return parameters; } - public TypeMirror[] getTypes() { + public List getTypes() { return types; } @@ -349,7 +391,7 @@ private static String createTypeSignature(ParameterSpec spec, List typeDefs, boolean typeOnly) { StringBuilder builder = new StringBuilder(); - if (spec.getAllowedTypes().length > 1) { + if (spec.getAllowedTypes().size() > 1) { TypeDef foundTypeDef = null; for (TypeDef typeDef : typeDefs) { if (typeDef.getParameters().contains(spec)) { @@ -360,8 +402,8 @@ if (foundTypeDef != null) { builder.append("<" + foundTypeDef.getName() + ">"); } - } else if (spec.getAllowedTypes().length == 1) { - builder.append(Utils.getSimpleName(spec.getAllowedTypes()[0])); + } else if (spec.getAllowedTypes().size() == 1) { + builder.append(Utils.getSimpleName(spec.getAllowedTypes().get(0))); } else { builder.append("void"); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateParser.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateParser.java Thu Mar 21 14:11:13 2013 +0100 @@ -43,9 +43,8 @@ return extensionParser; } - protected boolean verifyExclusiveMethodAnnotation(TypeElement type, Class... annotationTypes) { - boolean valid = true; - List methods = ElementFilter.methodsIn(type.getEnclosedElements()); + protected void verifyExclusiveMethodAnnotation(Template template, Class... annotationTypes) { + List methods = ElementFilter.methodsIn(template.getTemplateType().getEnclosedElements()); for (ExecutableElement method : methods) { List foundAnnotations = new ArrayList<>(); for (int i = 0; i < annotationTypes.length; i++) { @@ -61,34 +60,9 @@ annotationNames.add("@" + Utils.getSimpleName(mirror.getAnnotationType())); } - for (AnnotationMirror mirror : foundAnnotations) { - context.getLog().error(method, mirror, "Non exclusive usage of annotations %s.", annotationNames); - } - valid = false; + template.addError("Non exclusive usage of annotations %s.", annotationNames); } } - return valid; - } - - protected boolean verifyTemplateType(TypeElement template, AnnotationMirror annotation) { - // annotation type on class path!? - boolean valid = true; - TypeElement annotationTypeElement = processingEnv.getElementUtils().getTypeElement(getAnnotationType().getCanonicalName()); - if (annotationTypeElement == null) { - log.error(template, annotation, "Required class " + getAnnotationType().getName() + " is not on the classpath."); - valid = false; - } - if (template.getModifiers().contains(Modifier.PRIVATE)) { - log.error(template, annotation, "The annotated class must have at least package protected visibility."); - valid = false; - } - - if (template.getModifiers().contains(Modifier.FINAL)) { - log.error(template, annotation, "The annotated class must not be final."); - valid = false; - } - - return valid; } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java Thu Mar 21 14:11:13 2013 +0100 @@ -26,15 +26,8 @@ public class GuardData extends TemplateMethod { - private final Template origin; - - public GuardData(TemplateMethod method, Template origin) { + public GuardData(TemplateMethod method) { super(method); - this.origin = origin; - } - - public Template getOrigin() { - return origin; } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java Thu Mar 21 14:11:13 2013 +0100 @@ -26,8 +26,8 @@ import java.util.*; import javax.lang.model.element.*; +import javax.lang.model.type.*; -import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; @@ -39,30 +39,31 @@ public GuardParser(ProcessorContext context, Template template, TypeSystemData typeSystem) { super(context, template); this.typeSystem = typeSystem; + setEmitErrors(false); + setParseNullOnError(false); } @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { List specs = new ArrayList<>(); - specs.add(new ParameterSpec("value1", typeSystem, false, Cardinality.ONE)); specs.add(new ParameterSpec("valueN", typeSystem, false, Cardinality.MULTIPLE)); ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), false); - return new MethodSpec(returnTypeSpec, specs); + return new MethodSpec(Collections. emptyList(), returnTypeSpec, specs); } @Override public boolean isParsable(ExecutableElement method) { - return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null; + return true; } @Override public GuardData create(TemplateMethod method) { - return new GuardData(method, template); + return new GuardData(method); } @Override public Class getAnnotationType() { - return GuardCheck.class; + return null; } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java Thu Mar 21 14:11:13 2013 +0100 @@ -26,6 +26,7 @@ import java.util.*; import javax.lang.model.element.*; +import javax.lang.model.type.*; import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; @@ -40,21 +41,21 @@ @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - TypeData targetType = findTypeByMethodName(method, mirror, "as"); + TypeData targetType = findTypeByMethodName(method.getSimpleName().toString(), "as"); if (targetType == null) { return null; } List specs = new ArrayList<>(); specs.add(new ParameterSpec("value", getTypeSystem(), false, Cardinality.ONE)); ParameterSpec returnTypeSpec = new ParameterSpec("returnType", targetType.getPrimitiveType(), false); - MethodSpec spec = new MethodSpec(returnTypeSpec, specs); + MethodSpec spec = new MethodSpec(Collections. emptyList(), returnTypeSpec, specs); return spec; } @Override public TypeCastData create(TemplateMethod method) { - TypeData targetType = findTypeByMethodName(method.getMethod(), method.getMarkerAnnotation(), "as"); - ActualParameter parameter = method.findParameter("value"); + TypeData targetType = findTypeByMethodName(method, "as"); + ActualParameter parameter = method.findParameter("valueValue"); return new TypeCastData(method, parameter.getActualTypeData(getTypeSystem()), targetType); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java Thu Mar 21 14:11:13 2013 +0100 @@ -26,6 +26,7 @@ import java.util.*; import javax.lang.model.element.*; +import javax.lang.model.type.*; import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; @@ -40,22 +41,22 @@ @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - TypeData targetType = findTypeByMethodName(method, mirror, "is"); + TypeData targetType = findTypeByMethodName(method.getSimpleName().toString(), "is"); if (targetType == null) { return null; } List specs = new ArrayList<>(); specs.add(new ParameterSpec("value", getTypeSystem(), false, Cardinality.ONE)); ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), false); - MethodSpec spec = new MethodSpec(returnTypeSpec, specs); + MethodSpec spec = new MethodSpec(Collections. emptyList(), returnTypeSpec, specs); return spec; } @Override public TypeCheckData create(TemplateMethod method) { - TypeData checkedType = findTypeByMethodName(method.getMethod(), method.getMarkerAnnotation(), "is"); + TypeData checkedType = findTypeByMethodName(method, "is"); assert checkedType != null; - ActualParameter parameter = method.findParameter("value"); + ActualParameter parameter = method.findParameter("valueValue"); assert parameter != null; return new TypeCheckData(method, checkedType, parameter.getActualTypeData(getTypeSystem())); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java Thu Mar 21 14:11:13 2013 +0100 @@ -30,21 +30,38 @@ import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; -public class TypeData extends Template { +public class TypeData extends MessageContainer { - protected TypeSystemData typeSystem; + private final TypeSystemData typeSystem; + private final AnnotationValue annotationValue; private final TypeMirror primitiveType; private final TypeMirror boxedType; private final List typeCasts = new ArrayList<>(); private final List typeChecks = new ArrayList<>(); - public TypeData(TypeElement templateType, AnnotationMirror annotation, TypeMirror primitiveType, TypeMirror boxedType) { - super(templateType, annotation); + public TypeData(TypeSystemData typeSystem, AnnotationValue value, TypeMirror primitiveType, TypeMirror boxedType) { + this.typeSystem = typeSystem; + this.annotationValue = value; this.primitiveType = primitiveType; this.boxedType = boxedType; } + @Override + public Element getMessageElement() { + return typeSystem.getMessageElement(); + } + + @Override + public AnnotationMirror getMessageAnnotation() { + return typeSystem.getMessageAnnotation(); + } + + @Override + public AnnotationValue getMessageAnnotationValue() { + return annotationValue; + } + void addTypeCast(TypeCastData typeCast) { this.typeCasts.add(typeCast); } @@ -89,4 +106,8 @@ return getClass().getSimpleName() + "[" + Utils.getSimpleName(primitiveType) + "]"; } + public boolean equalsType(TypeData actualTypeData) { + return Utils.typeEquals(boxedType, actualTypeData.boxedType); + } + } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemCodeGenerator.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemCodeGenerator.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemCodeGenerator.java Thu Mar 21 14:11:13 2013 +0100 @@ -41,15 +41,15 @@ } public static String isTypeMethodName(TypeData type) { - return "is" + Utils.getSimpleName(type.getBoxedType()); + return "is" + Utils.getTypeId(type.getBoxedType()); } public static String asTypeMethodName(TypeData type) { - return "as" + Utils.getSimpleName(type.getBoxedType()); + return "as" + Utils.getTypeId(type.getBoxedType()); } public static String expectTypeMethodName(TypeData type) { - return "expect" + Utils.getSimpleName(type.getBoxedType()); + return "expect" + Utils.getTypeId(type.getBoxedType()); } /** @@ -167,8 +167,8 @@ CodeTreeBuilder builder = method.createBuilder(); builder.startReturn(); - if (typeSystem.getTypes().length > 0) { - builder.typeLiteral(typeSystem.getTypes()[0].getBoxedType()); + if (!typeSystem.getTypes().isEmpty()) { + builder.typeLiteral(typeSystem.getTypes().get(0).getBoxedType()); } else { builder.null_(); } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java Thu Mar 21 14:11:13 2013 +0100 @@ -32,35 +32,42 @@ public class TypeSystemData extends Template { - private final TypeData[] types; - private final TypeMirror[] primitiveTypeMirrors; - private final TypeMirror[] boxedTypeMirrors; + private List types; + private List primitiveTypeMirrors = new ArrayList<>(); + private List boxedTypeMirrors = new ArrayList<>(); - private final TypeMirror genericType; + private TypeMirror genericType; + private TypeData voidType; + + public TypeSystemData(TypeElement templateType, AnnotationMirror annotation) { + super(templateType, null, annotation); + } - private final TypeData voidType; + void setTypes(List types) { + this.types = types; + if (types != null) { + for (TypeData typeData : types) { + primitiveTypeMirrors.add(typeData.getPrimitiveType()); + boxedTypeMirrors.add(typeData.getBoxedType()); + } + } + } - public TypeSystemData(TypeElement templateType, AnnotationMirror annotation, TypeData[] types, TypeMirror genericType, TypeData voidType) { - super(templateType, annotation); - this.types = types; + void setGenericType(TypeMirror genericType) { this.genericType = genericType; + } + + void setVoidType(TypeData voidType) { this.voidType = voidType; - this.primitiveTypeMirrors = new TypeMirror[types.length]; - for (int i = 0; i < types.length; i++) { - primitiveTypeMirrors[i] = types[i].getPrimitiveType(); - } + } - this.boxedTypeMirrors = new TypeMirror[types.length]; - for (int i = 0; i < types.length; i++) { - boxedTypeMirrors[i] = types[i].getBoxedType(); + @Override + protected List findChildContainers() { + List sinks = new ArrayList<>(); + if (types != null) { + sinks.addAll(types); } - - for (TypeData type : types) { - type.typeSystem = this; - } - if (voidType != null) { - voidType.typeSystem = this; - } + return sinks; } public boolean isGeneric(TypeMirror type) { @@ -71,16 +78,16 @@ return voidType; } - public TypeData[] getTypes() { - return types; + public List getBoxedTypeMirrors() { + return boxedTypeMirrors; } - public TypeMirror[] getPrimitiveTypeMirrors() { + public List getPrimitiveTypeMirrors() { return primitiveTypeMirrors; } - public TypeMirror[] getBoxedTypeMirrors() { - return boxedTypeMirrors; + public List getTypes() { + return types; } public TypeMirror getGenericType() { @@ -88,7 +95,7 @@ } public TypeData getGenericTypeData() { - TypeData result = types[types.length - 1]; + TypeData result = types.get(types.size() - 1); assert result.getBoxedType() == genericType; return result; } @@ -111,7 +118,7 @@ if (index == -1) { return null; } - return types[index]; + return types.get(index); } public int findType(TypeData typeData) { @@ -119,8 +126,8 @@ } public int findType(TypeMirror type) { - for (int i = 0; i < types.length; i++) { - if (Utils.typeEquals(types[i].getPrimitiveType(), type)) { + for (int i = 0; i < types.size(); i++) { + if (Utils.typeEquals(types.get(i).getPrimitiveType(), type)) { return i; } } @@ -129,7 +136,7 @@ @Override public String toString() { - return getClass().getSimpleName() + "[template = " + Utils.getSimpleName(getTemplateType()) + ", types = " + Arrays.toString(types) + "]"; + return getClass().getSimpleName() + "[template = " + Utils.getSimpleName(getTemplateType()) + ", types = " + types + "]"; } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java Thu Mar 21 14:11:13 2013 +0100 @@ -43,18 +43,24 @@ return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null; } - protected TypeData findTypeByMethodName(ExecutableElement method, AnnotationMirror annotationMirror, String prefix) { - String methodName = method.getSimpleName().toString(); + protected TypeData findTypeByMethodName(String methodName, String prefix) { + String typeName = methodName.substring(prefix.length(), methodName.length()); + TypeData type = getTypeSystem().findType(typeName); + return type; + } + + protected TypeData findTypeByMethodName(TemplateMethod method, String prefix) { + String methodName = method.getMethodName(); if (!methodName.startsWith(prefix)) { - String annotationName = Utils.getSimpleName(annotationMirror.getAnnotationType()); - getContext().getLog().error(method, "Methods annotated with %s must match the pattern '%s'.", annotationName, String.format("%s${typeName}", prefix)); + String annotationName = Utils.getSimpleName(method.getMessageAnnotation().getAnnotationType()); + method.addError("Methods annotated with %s must match the pattern '%s'.", annotationName, String.format("%s${typeName}", prefix)); return null; } String typeName = methodName.substring(prefix.length(), methodName.length()); TypeData type = getTypeSystem().findType(typeName); if (type == null) { String annotationName = TypeSystem.class.getSimpleName(); - getContext().getLog().error(method, "Type '%s' is not declared in this @%s.", typeName, annotationName); + method.addError("Type '%s' is not declared in this @%s.", typeName, annotationName); return null; } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java Thu Mar 21 14:11:13 2013 +0100 @@ -52,27 +52,39 @@ protected TypeSystemData parse(Element element, AnnotationMirror mirror) { TypeElement templateType = (TypeElement) element; AnnotationMirror templateTypeAnnotation = mirror; + TypeSystemData typeSystem = new TypeSystemData(templateType, templateTypeAnnotation); - if (!verifyTemplateType(templateType, templateTypeAnnotation)) { - return null; + // annotation type on class path!? + TypeElement annotationTypeElement = processingEnv.getElementUtils().getTypeElement(getAnnotationType().getCanonicalName()); + if (annotationTypeElement == null) { + typeSystem.addError("Required class %s is not on the classpath.", getAnnotationType().getName()); + } + if (templateType.getModifiers().contains(Modifier.PRIVATE)) { + typeSystem.addError("A @%s must have at least package protected visibility.", getAnnotationType().getName()); } - TypeData[] types = parseTypes(templateType, templateTypeAnnotation); - if (types == null) { - return null; + if (templateType.getModifiers().contains(Modifier.FINAL)) { + typeSystem.addError("The @%s must not be final.", getAnnotationType().getName()); + } + if (typeSystem.hasErrors()) { + return typeSystem; + } + + typeSystem.setTypes(parseTypes(typeSystem)); + if (typeSystem.getTypes() == null) { + return typeSystem; } TypeMirror genericType = context.getType(Object.class); - TypeData voidType = new TypeData(templateType, templateTypeAnnotation, context.getType(void.class), context.getType(Void.class)); - - TypeSystemData typeSystem = new TypeSystemData(templateType, templateTypeAnnotation, types, genericType, voidType); + TypeData voidType = new TypeData(typeSystem, null, context.getType(void.class), context.getType(Void.class)); - if (!verifyExclusiveMethodAnnotation(templateType, TypeCast.class, TypeCheck.class)) { - return null; - } + typeSystem.setGenericType(genericType); + typeSystem.setVoidType(voidType); + + verifyExclusiveMethodAnnotation(typeSystem, TypeCast.class, TypeCheck.class); List elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(templateType)); - typeSystem.setExtensionElements(getExtensionParser().parseAll(templateType, elements)); + typeSystem.setExtensionElements(getExtensionParser().parseAll(typeSystem, elements)); if (typeSystem.getExtensionElements() != null) { elements.addAll(typeSystem.getExtensionElements()); } @@ -81,7 +93,7 @@ List checks = new TypeCheckParser(context, typeSystem).parse(elements); if (casts == null || checks == null) { - return null; + return typeSystem; } for (TypeCheckData check : checks) { @@ -92,24 +104,15 @@ cast.getTargetType().addTypeCast(cast); } - if (!verifyGenericTypeChecksAndCasts(types)) { - return null; - } - - if (!verifyMethodSignatures(element, types)) { - return null; - } - - if (!verifyNamesUnique(templateType, templateTypeAnnotation, types)) { - return null; - } + verifyGenericTypeChecksAndCasts(typeSystem); + verifyMethodSignatures(typeSystem); + verifyNamesUnique(typeSystem); return typeSystem; } - private boolean verifyGenericTypeChecksAndCasts(TypeData[] types) { - boolean valid = true; - for (TypeData type : types) { + private static void verifyGenericTypeChecksAndCasts(TypeSystemData typeSystem) { + for (TypeData type : typeSystem.getTypes()) { if (!type.getTypeChecks().isEmpty()) { boolean hasGeneric = false; for (TypeCheckData typeCheck : type.getTypeChecks()) { @@ -119,10 +122,9 @@ } } if (!hasGeneric) { - log.error(type.getTypeSystem().getTemplateType(), "No generic but specific @%s method %s for type %s specified. " - + "Specify a generic @%s method with parameter type %s to resolve this.", TypeCheck.class.getSimpleName(), TypeSystemCodeGenerator.isTypeMethodName(type), - Utils.getSimpleName(type.getBoxedType()), TypeCheck.class.getSimpleName(), Object.class.getSimpleName()); - valid = false; + type.addError("No generic but specific @%s method %s for type %s specified. " + "Specify a generic @%s method with parameter type %s to resolve this.", + TypeCheck.class.getSimpleName(), TypeSystemCodeGenerator.isTypeMethodName(type), Utils.getSimpleName(type.getBoxedType()), TypeCheck.class.getSimpleName(), + Object.class.getSimpleName()); } } if (!type.getTypeCasts().isEmpty()) { @@ -134,63 +136,55 @@ } } if (!hasGeneric) { - log.error(type.getTypeSystem().getTemplateType(), "No generic but specific @%s method %s for type %s specified. " - + "Specify a generic @%s method with parameter type %s to resolve this.", TypeCast.class.getSimpleName(), TypeSystemCodeGenerator.asTypeMethodName(type), - Utils.getSimpleName(type.getBoxedType()), TypeCast.class.getSimpleName(), Object.class.getSimpleName()); - valid = false; + type.addError("No generic but specific @%s method %s for type %s specified. " + "Specify a generic @%s method with parameter type %s to resolve this.", + TypeCast.class.getSimpleName(), TypeSystemCodeGenerator.asTypeMethodName(type), Utils.getSimpleName(type.getBoxedType()), TypeCast.class.getSimpleName(), + Object.class.getSimpleName()); } } } - return valid; } - private TypeData[] parseTypes(TypeElement templateType, AnnotationMirror templateTypeAnnotation) { - List typeMirrors = Utils.getAnnotationValueList(templateTypeAnnotation, "value"); - if (typeMirrors.size() == 0) { - log.error(templateType, templateTypeAnnotation, "At least one type must be defined."); - return null; + private List parseTypes(TypeSystemData typeSystem) { + List types = new ArrayList<>(); + List typeMirrors = Utils.getAnnotationValueList(TypeMirror.class, typeSystem.getTemplateTypeAnnotation(), "value"); + if (typeMirrors.isEmpty()) { + typeSystem.addError("At least one type must be defined."); + return types; } - final AnnotationValue annotationValue = Utils.getAnnotationValue(templateTypeAnnotation, "value"); + final AnnotationValue annotationValue = Utils.getAnnotationValue(typeSystem.getTemplateTypeAnnotation(), "value"); final TypeMirror objectType = context.getType(Object.class); - List types = new ArrayList<>(); for (TypeMirror primitiveType : typeMirrors) { + TypeMirror boxedType = Utils.boxType(context, primitiveType); + TypeData typeData = new TypeData(typeSystem, annotationValue, primitiveType, boxedType); if (isPrimitiveWrapper(primitiveType)) { - log.error(templateType, templateTypeAnnotation, annotationValue, "Types must not contain primitive wrapper types."); - continue; - } - - TypeMirror boxedType = primitiveType; - if (boxedType.getKind().isPrimitive()) { - boxedType = processingEnv.getTypeUtils().boxedClass((PrimitiveType) boxedType).asType(); + typeData.addError("Types must not contain primitive wrapper types."); } if (Utils.typeEquals(boxedType, objectType)) { - log.error(templateType, templateTypeAnnotation, annotationValue, "Types must not contain the generic type java.lang.Object."); - continue; + typeData.addError("Types must not contain the generic type java.lang.Object."); } - types.add(new TypeData(templateType, templateTypeAnnotation, primitiveType, boxedType)); + types.add(typeData); } - verifyTypeOrder(templateType, templateTypeAnnotation, annotationValue, types); + verifyTypeOrder(types); - types.add(new TypeData(templateType, templateTypeAnnotation, objectType, objectType)); + types.add(new TypeData(typeSystem, annotationValue, objectType, objectType)); - return types.toArray(new TypeData[types.size()]); + return types; } - private void verifyTypeOrder(TypeElement templateType, AnnotationMirror templateTypeAnnotation, AnnotationValue annotationValue, List types) { + private static void verifyTypeOrder(List types) { Map> invalidTypes = new HashMap<>(); for (int i = types.size() - 1; i >= 0; i--) { TypeData typeData = types.get(i); TypeMirror type = typeData.getBoxedType(); if (invalidTypes.containsKey(Utils.getQualifiedName(type))) { - log.error(templateType, templateTypeAnnotation, annotationValue, "Invalid type order. The type(s) %s are inherited from a earlier defined type %s.", - invalidTypes.get(Utils.getQualifiedName(type)), Utils.getQualifiedName(type)); + typeData.addError("Invalid type order. The type(s) %s are inherited from a earlier defined type %s.", invalidTypes.get(Utils.getQualifiedName(type)), Utils.getQualifiedName(type)); } List nextInvalidTypes = Utils.getQualifiedSuperTypeNames(Utils.fromTypeMirror(type)); nextInvalidTypes.add(getQualifiedName(type)); @@ -219,19 +213,18 @@ return false; } - private boolean verifyMethodSignatures(Element element, TypeData[] types) { + private void verifyMethodSignatures(TypeSystemData typeSystem) { Set generatedIsMethodNames = new HashSet<>(); Set generatedAsMethodNames = new HashSet<>(); Set generatedExpectMethodNames = new HashSet<>(); - for (TypeData typeData : types) { + for (TypeData typeData : typeSystem.getTypes()) { generatedIsMethodNames.add(TypeSystemCodeGenerator.isTypeMethodName(typeData)); generatedAsMethodNames.add(TypeSystemCodeGenerator.asTypeMethodName(typeData)); generatedExpectMethodNames.add(TypeSystemCodeGenerator.expectTypeMethodName(typeData)); } - boolean valid = true; - List methods = ElementFilter.methodsIn(element.getEnclosedElements()); + List methods = ElementFilter.methodsIn(typeSystem.getTemplateType().getEnclosedElements()); for (ExecutableElement method : methods) { if (method.getModifiers().contains(Modifier.PRIVATE)) { // will not conflict overridden methods @@ -241,51 +234,48 @@ } String methodName = method.getSimpleName().toString(); if (generatedIsMethodNames.contains(methodName)) { - valid &= verifyIsMethod(method); + verifyIsMethod(typeSystem, method); } else if (generatedAsMethodNames.contains(methodName)) { - valid &= verifyAsMethod(method); + verifyAsMethod(typeSystem, method); } else if (generatedExpectMethodNames.contains(methodName)) { - valid &= verifyExpectMethod(method); + verifyExpectMethod(typeSystem); } } - return valid; } - private boolean verifyIsMethod(ExecutableElement method) { + private boolean verifyIsMethod(TypeSystemData typeSystem, ExecutableElement method) { AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, TypeCheck.class); if (mirror == null) { - log.error(method, "Method starting with the pattern is${typeName} must be annotated with @%s.", TypeCheck.class.getSimpleName()); + typeSystem.addError("Method starting with the pattern is${typeName} must be annotated with @%s.", TypeCheck.class.getSimpleName()); return false; } return true; } - private boolean verifyAsMethod(ExecutableElement method) { + private boolean verifyAsMethod(TypeSystemData typeSystem, ExecutableElement method) { AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, TypeCast.class); if (mirror == null) { - log.error(method, "Method starting with the pattern as${typeName} must be annotated with @%s.", TypeCast.class.getSimpleName()); + typeSystem.addError("Method starting with the pattern as${typeName} must be annotated with @%s.", TypeCast.class.getSimpleName()); return false; } return true; } - private boolean verifyExpectMethod(ExecutableElement method) { - log.error(method, "Method starting with the pattern expect${typeName} must not be declared manually."); + private static boolean verifyExpectMethod(TypeSystemData typeSystem) { + typeSystem.addError("Method starting with the pattern expect${typeName} must not be declared manually."); return false; } - private boolean verifyNamesUnique(TypeElement templateType, AnnotationMirror templateTypeAnnotation, TypeData[] types) { - boolean valid = true; - for (int i = 0; i < types.length; i++) { - for (int j = i + 1; j < types.length; j++) { - String name1 = Utils.getSimpleName(types[i].getBoxedType()); - String name2 = Utils.getSimpleName(types[j].getBoxedType()); + private static void verifyNamesUnique(TypeSystemData typeSystem) { + List types = typeSystem.getTypes(); + for (int i = 0; i < types.size(); i++) { + for (int j = i + 1; j < types.size(); j++) { + String name1 = Utils.getSimpleName(types.get(i).getBoxedType()); + String name2 = Utils.getSimpleName(types.get(j).getBoxedType()); if (name1.equalsIgnoreCase(name2)) { - log.error(templateType, templateTypeAnnotation, "Two types result in the same name: %s, %s.", name1, name2); - valid = false; + typeSystem.addError("Two types result in the same name: %s, %s.", name1, name2); } } } - return valid; } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/TernaryTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/TernaryTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,52 @@ +/* + * 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.truffle.sl.test; + +import org.junit.*; + +// @formatter:off +public class TernaryTest extends AbstractTest { + + private static String[] INPUT = new String[] { +"function main { " + +" print #(1 < 2) ? 1 : 2;" + +" print #(2 < 1) ? 100000000000000 : 1; ", +" print #(1 < 2) ? 100000000000000 : 1; ", +" print #(2 < 1) ? \"wrong\" : \"true\";", +" print #(2 < 1) ? \"wrong\" : 1;", +"} ", + }; + + private static String[] OUTPUT = new String[] { + "1", + "1", + "100000000000000", + "true", + "1", + }; + + @Test + public void test() { + executeSL(INPUT, OUTPUT, true); + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java Thu Mar 21 14:11:13 2013 +0100 @@ -27,8 +27,11 @@ import java.util.*; import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.sl.nodes.ArithmeticNodeFactory.AddNodeFactory; +import com.oracle.truffle.sl.nodes.ArithmeticNodeFactory.DivNodeFactory; +import com.oracle.truffle.sl.nodes.ArithmeticNodeFactory.MulNodeFactory; +import com.oracle.truffle.sl.nodes.ArithmeticNodeFactory.SubNodeFactory; import com.oracle.truffle.sl.nodes.*; -import com.oracle.truffle.sl.nodes.ArithmeticNodeFactory.*; public class NodeFactory { @@ -127,4 +130,8 @@ StatementNode write = WriteLocalNodeFactory.create(slot, value); return new ReturnNode(write); } + + public TypedNode createTernary(TypedNode condition, TypedNode thenPart, TypedNode elsePart) { + return TernaryNodeFactory.create(condition, thenPart, elsePart); + } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLTypes.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLTypes.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLTypes.java Thu Mar 21 14:11:13 2013 +0100 @@ -41,7 +41,7 @@ return (int) value; } else { int result = ((BigInteger) value).intValue(); - assert BigInteger.valueOf(result).equals(value) : "Loosing precision"; + assert BigInteger.valueOf(result).equals(value) : "Losing precision"; return result; } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArithmeticNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArithmeticNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArithmeticNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -37,11 +37,6 @@ super(node); } - @Generic - public Object doGeneric(Object left, Object right) { - throw new RuntimeException("Arithmetic not defined for types " + left.getClass().getSimpleName() + ", " + right.getClass().getSimpleName()); - } - public abstract static class AddNode extends ArithmeticNode { public AddNode(TypedNode left, TypedNode right) { @@ -52,9 +47,8 @@ super(node); } - @Specialization - @SpecializationThrows(javaClass = ArithmeticException.class, transitionTo = "doBigInteger") - int doInteger(int left, int right) { + @Specialization(rewriteOn = ArithmeticException.class) + int doInt(int left, int right) { return ExactMath.addExact(left, right); } @@ -64,13 +58,12 @@ } @Specialization - String doStringDirect(String left, String right) { + String doString(String left, String right) { return left + right; } - @Specialization - @SpecializationGuard(methodName = "isString") - String doString(Object left, Object right) { + @Specialization(guards = "isString") + String add(Object left, Object right) { return left.toString() + right.toString(); } } @@ -85,16 +78,16 @@ super(node); } - @Specialization - @SpecializationThrows(javaClass = ArithmeticException.class, transitionTo = "doBigInteger") - int doInteger(int left, int right) { + @Specialization(rewriteOn = ArithmeticException.class) + int sub(int left, int right) { return ExactMath.subtractExact(left, right); } @Specialization - BigInteger doBigInteger(BigInteger left, BigInteger right) { + BigInteger sub(BigInteger left, BigInteger right) { return left.subtract(right); } + } public abstract static class DivNode extends ArithmeticNode { @@ -107,14 +100,13 @@ super(node); } - @Specialization - @SpecializationThrows(javaClass = ArithmeticException.class, transitionTo = "doBigInteger") - int doInteger(int left, int right) { + @Specialization(rewriteOn = ArithmeticException.class) + int div(int left, int right) { return left / right; } @Specialization - BigInteger doBigInteger(BigInteger left, BigInteger right) { + BigInteger div(BigInteger left, BigInteger right) { return left.divide(right); } } @@ -129,16 +121,16 @@ super(node); } - @Specialization - @SpecializationThrows(javaClass = ArithmeticException.class, transitionTo = "doBigInteger") - int doInteger(int left, int right) { + @Specialization(rewriteOn = ArithmeticException.class) + int mul(int left, int right) { return ExactMath.multiplyExact(left, right); } @Specialization - BigInteger doBigInteger(BigInteger left, BigInteger right) { + BigInteger mul(BigInteger left, BigInteger right) { return left.multiply(right); } + } } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ConditionalNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ConditionalNode.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +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.truffle.sl.nodes; - -import java.math.*; - -import com.oracle.truffle.api.codegen.*; - -@SuppressWarnings("unused") -@ExecuteChildren({"conditionNode", "ifPartNode", "elsePartNode"}) -public abstract class ConditionalNode extends TypedNode { - - @Child protected ConditionNode conditionNode; - - @Child protected TypedNode ifPartNode; - - @Child protected TypedNode elsePartNode; - - public ConditionalNode(ConditionNode condition, TypedNode ifPart, TypedNode elsePart) { - this.conditionNode = adoptChild(condition); - this.ifPartNode = adoptChild(ifPart); - this.elsePartNode = adoptChild(elsePart); - } - - public ConditionalNode(ConditionalNode condition) { - this(condition.conditionNode, condition.ifPartNode, condition.elsePartNode); - } - - @ShortCircuit("ifPartNode") - public boolean needsIfPart(boolean condition) { - return condition; - } - - @ShortCircuit("ifPartNode") - public boolean needsIfPart(Object condition) { - throw new RuntimeException("operation not defined for type " + condition.getClass().getSimpleName()); - } - - @ShortCircuit("elsePartNode") - public boolean needsElsePart(Object condition, boolean hasIfPart, Object ifPart) { - return !hasIfPart; - } - - @ShortCircuit("elsePartNode") - public boolean needsElsePart(boolean condition, boolean hasIfPart, int ifPart) { - return !hasIfPart; - } - - @ShortCircuit("elsePartNode") - public boolean needsElsePart(boolean condition, boolean hasIfPart, BigInteger ifPart) { - return !hasIfPart; - } - - @Specialization - public int doInteger(boolean condition, boolean hasIfPart, int ifPart, boolean hasElsePart, int elsePart) { - return hasIfPart ? ifPart : elsePart; - } - - @Specialization - public BigInteger doBigInteger(boolean condition, boolean hasIfPart, BigInteger ifPart, boolean hasElsePart, BigInteger elsePart) { - return hasIfPart ? ifPart : elsePart; - } - - @Generic - public Object doGeneric(boolean condition, boolean hasIfPart, Object ifPart, boolean hasElsePart, Object elsePart) { - return hasIfPart ? ifPart : elsePart; - } -} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LessThanNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LessThanNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LessThanNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -46,8 +46,7 @@ return left.compareTo(right) < 0; } - @Specialization - @SpecializationGuard(methodName = "isString") + @Specialization(guards = "isString") public boolean doString(Object left, Object right) { return left.toString().compareTo(right.toString()) < 0; } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TernaryNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TernaryNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,73 @@ +/* + * 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.truffle.sl.nodes; + +import java.math.*; + +import com.oracle.truffle.api.codegen.*; + +@SuppressWarnings("unused") +@ExecuteChildren({"conditionNode", "ifPartNode", "elsePartNode"}) +public abstract class TernaryNode extends TypedNode { + + @Child protected ConditionNode conditionNode; + + @Child protected TypedNode ifPartNode; + + @Child protected TypedNode elsePartNode; + + public TernaryNode(ConditionNode condition, TypedNode ifPart, TypedNode elsePart) { + this.conditionNode = adoptChild(condition); + this.ifPartNode = adoptChild(ifPart); + this.elsePartNode = adoptChild(elsePart); + } + + public TernaryNode(TernaryNode condition) { + this(condition.conditionNode, condition.ifPartNode, condition.elsePartNode); + } + + @ShortCircuit("ifPartNode") + public boolean needsIfPart(boolean condition) { + return condition; + } + + @ShortCircuit("elsePartNode") + public boolean needsElsePart(boolean condition, boolean hasIfPart, Object ifPart) { + return !hasIfPart; + } + + @Specialization + public int doInteger(boolean condition, boolean hasIfPart, int ifPart, boolean hasElsePart, int elsePart) { + return hasIfPart ? ifPart : elsePart; + } + + @Specialization + public BigInteger doBigInteger(boolean condition, boolean hasIfPart, BigInteger ifPart, boolean hasElsePart, BigInteger elsePart) { + return hasIfPart ? ifPart : elsePart; + } + + @Generic + public Object doGeneric(boolean condition, boolean hasIfPart, Object ifPart, boolean hasElsePart, Object elsePart) { + return hasIfPart ? ifPart : elsePart; + } +} diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TypedNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TypedNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TypedNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,7 +24,6 @@ import java.math.*; -import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; @@ -49,7 +48,6 @@ public abstract Object executeGeneric(VirtualFrame frame); - @GuardCheck public boolean isString(Object a, Object b) { return a instanceof String || b instanceof String; } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -41,31 +41,31 @@ } @Specialization - public int doInteger(VirtualFrame frame, int right) { + public int write(VirtualFrame frame, int right) { frame.setInt(slot, right); return right; } @Specialization - public BigInteger doBigInteger(VirtualFrame frame, BigInteger right) { + public BigInteger write(VirtualFrame frame, BigInteger right) { frame.setObject(slot, right); return right; } @Specialization - public boolean doBoolean(VirtualFrame frame, boolean right) { + public boolean write(VirtualFrame frame, boolean right) { frame.setBoolean(slot, right); return right; } @Specialization - public String doString(VirtualFrame frame, String right) { + public String write(VirtualFrame frame, String right) { frame.setObject(slot, right); return right; } - @Generic - public Object doGeneric(VirtualFrame frame, Object right) { + @Generic(useSpecializations = false) + public Object writeGeneric(VirtualFrame frame, Object right) { frame.setObject(slot, right); return right; } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java Thu Mar 21 14:11:13 2013 +0100 @@ -21,10 +21,9 @@ * questions. */ -// The content of this file is automatically generated. DO NOT EDIT. + // The content of this file is automatically generated. DO NOT EDIT. package com.oracle.truffle.sl.parser; - import java.util.*; import com.oracle.truffle.sl.*; @@ -33,11 +32,11 @@ // Checkstyle: stop // @formatter:off public class Parser { - public static final int _EOF = 0; - public static final int _identifier = 1; - public static final int _stringLiteral = 2; - public static final int _numericLiteral = 3; - public static final int maxT = 25; + public static final int _EOF = 0; + public static final int _identifier = 1; + public static final int _stringLiteral = 2; + public static final int _numericLiteral = 3; + public static final int maxT = 28; static final boolean T = true; static final boolean x = false; @@ -50,7 +49,7 @@ public final Scanner scanner; public final Errors errors; private final NodeFactory factory; - + public Parser(Scanner scanner, NodeFactory factory) { this.scanner = scanner; this.factory = factory; @@ -121,226 +120,255 @@ } } - void SimpleLanguage() { - Function(); - while (la.kind == 4) { - Function(); - } - } - - void Function() { - Expect(4); - factory.startFunction(); - Expect(1); - String name = t.val; - StatementNode body = Block(); - factory.createFunction(body, name); - } - - StatementNode Block() { - StatementNode result; - List statements = new ArrayList<>(); - Expect(5); - while (StartOf(1)) { - StatementNode statement = Statement(); - statements.add(statement); - } - Expect(6); - result = factory.createBlock(statements); - return result; - } - - StatementNode Statement() { - StatementNode result; - result = null; - if (la.kind == 7) { - result = WhileStatement(); - } else if (la.kind == 1) { - result = AssignmentStatement(); - } else if (la.kind == 12) { - result = OutputStatement(); - } else if (la.kind == 13) { - result = ReturnStatement(); - } else SynErr(26); - return result; - } - - StatementNode WhileStatement() { - StatementNode result; - Expect(7); - Expect(8); - ConditionNode condition = Expression(); - Expect(9); - StatementNode body = Block(); - result = factory.createWhile(condition, body); - return result; - } - - StatementNode AssignmentStatement() { - StatementNode result; - Expect(1); - String name = t.val; - Expect(10); - TypedNode rvalue = Expression(); - Expect(11); - result = factory.createAssignment(name, rvalue); - return result; - } - - StatementNode OutputStatement() { - StatementNode result; - List expressions = new ArrayList<>(); - Expect(12); - while (StartOf(2)) { - TypedNode value = Expression(); - expressions.add(value); - } - Expect(11); - result = factory.createPrint(expressions); - return result; - } - - StatementNode ReturnStatement() { - StatementNode result; - Expect(13); - TypedNode value = Expression(); - Expect(11); - result = factory.createReturn(value); - return result; - } - - TypedNode Expression() { - TypedNode result; - result = ValueExpression(); - if (StartOf(3)) { - switch (la.kind) { - case 14: { - Get(); - break; - } - case 15: { - Get(); - break; - } - case 16: { - Get(); - break; - } - case 17: { - Get(); - break; - } - case 18: { - Get(); - break; - } - case 19: { - Get(); - break; - } - } - String op = t.val; - TypedNode right = ValueExpression(); - result = factory.createBinary(op, result, right); - } - return result; - } - - TypedNode ValueExpression() { - TypedNode result; - result = Term(); - while (la.kind == 20 || la.kind == 21) { - if (la.kind == 20) { - Get(); - } else { - Get(); - } - String op = t.val; - TypedNode right = Term(); - result = factory.createBinary(op, result, right); - } - return result; - } - - TypedNode Term() { - TypedNode result; - result = Factor(); - while (la.kind == 22 || la.kind == 23) { - if (la.kind == 22) { - Get(); - } else { - Get(); - } - String op = t.val; - TypedNode right = Factor(); - result = factory.createBinary(op, result, right); - } - return result; - } - - TypedNode Factor() { - TypedNode result; - result = null; - if (la.kind == 24) { - result = TimeRef(); - } else if (la.kind == 1) { - result = VariableRef(); - } else if (la.kind == 2) { - result = StringLiteral(); - } else if (la.kind == 3) { - result = NumericLiteral(); - } else if (la.kind == 8) { - Get(); - result = Expression(); - Expect(9); - } else SynErr(27); - return result; - } - - TypedNode TimeRef() { - TypedNode result; - Expect(24); - result = factory.createTime(); - return result; - } - - TypedNode VariableRef() { - TypedNode result; - Expect(1); - result = factory.createLocal(t.val); - return result; - } - - TypedNode StringLiteral() { - TypedNode result; - Expect(2); - result = factory.createStringLiteral(t.val.substring(1, t.val.length() - 1)); - return result; - } - - TypedNode NumericLiteral() { - TypedNode result; - Expect(3); - result = factory.createNumericLiteral(t.val); - return result; - } - + void SimpleLanguage() { + Function(); + while (la.kind == 4) { + Function(); + } + } + + void Function() { + Expect(4); + factory.startFunction(); + Expect(1); + String name = t.val; + StatementNode body = Block(); + factory.createFunction(body, name); + } + + StatementNode Block() { + StatementNode result; + List statements = new ArrayList<>(); + Expect(5); + while (StartOf(1)) { + StatementNode statement = Statement(); + statements.add(statement); + } + Expect(6); + result = factory.createBlock(statements); + return result; + } + + StatementNode Statement() { + StatementNode result; + result = null; + if (la.kind == 7) { + result = WhileStatement(); + } else if (la.kind == 1) { + result = AssignmentStatement(); + } else if (la.kind == 12) { + result = OutputStatement(); + } else if (la.kind == 13) { + result = ReturnStatement(); + } else SynErr(29); + return result; + } + + StatementNode WhileStatement() { + StatementNode result; + Expect(7); + Expect(8); + ConditionNode condition = Expression(); + Expect(9); + StatementNode body = Block(); + result = factory.createWhile(condition, body); + return result; + } + + StatementNode AssignmentStatement() { + StatementNode result; + Expect(1); + String name = t.val; + Expect(10); + TypedNode rvalue = Expression(); + Expect(11); + result = factory.createAssignment(name, rvalue); + return result; + } + + StatementNode OutputStatement() { + StatementNode result; + List expressions = new ArrayList<>(); + Expect(12); + while (StartOf(2)) { + TypedNode value = Expression(); + expressions.add(value); + } + Expect(11); + result = factory.createPrint(expressions); + return result; + } + + StatementNode ReturnStatement() { + StatementNode result; + Expect(13); + TypedNode value = Expression(); + Expect(11); + result = factory.createReturn(value); + return result; + } + + TypedNode Expression() { + TypedNode result; + result = ValueExpression(); + if (StartOf(3)) { + switch (la.kind) { + case 14: { + Get(); + break; + } + case 15: { + Get(); + break; + } + case 16: { + Get(); + break; + } + case 17: { + Get(); + break; + } + case 18: { + Get(); + break; + } + case 19: { + Get(); + break; + } + } + String op = t.val; + TypedNode right = ValueExpression(); + result = factory.createBinary(op, result, right); + } + return result; + } + + TypedNode ValueExpression() { + TypedNode result; + result = Term(); + while (la.kind == 20 || la.kind == 21) { + if (la.kind == 20) { + Get(); + } else { + Get(); + } + String op = t.val; + TypedNode right = Term(); + result = factory.createBinary(op, result, right); + } + return result; + } + + TypedNode Term() { + TypedNode result; + result = Factor(); + while (la.kind == 22 || la.kind == 23) { + if (la.kind == 22) { + Get(); + } else { + Get(); + } + String op = t.val; + TypedNode right = Factor(); + result = factory.createBinary(op, result, right); + } + return result; + } + + TypedNode Factor() { + TypedNode result; + result = null; + switch (la.kind) { + case 27: { + result = TimeRef(); + break; + } + case 1: { + result = VariableRef(); + break; + } + case 2: { + result = StringLiteral(); + break; + } + case 3: { + result = NumericLiteral(); + break; + } + case 24: { + result = Ternary(); + break; + } + case 8: { + Get(); + result = Expression(); + Expect(9); + break; + } + default: SynErr(30); break; + } + return result; + } + + TypedNode TimeRef() { + TypedNode result; + Expect(27); + result = factory.createTime(); + return result; + } + + TypedNode VariableRef() { + TypedNode result; + Expect(1); + result = factory.createLocal(t.val); + return result; + } + + TypedNode StringLiteral() { + TypedNode result; + Expect(2); + result = factory.createStringLiteral(t.val.substring(1, t.val.length() - 1)); + return result; + } + + TypedNode NumericLiteral() { + TypedNode result; + Expect(3); + result = factory.createNumericLiteral(t.val); + return result; + } + + TypedNode Ternary() { + TypedNode result; + TypedNode condition, thenPart, elsePart; + Expect(24); + condition = Expression(); + Expect(25); + thenPart = Expression(); + Expect(26); + elsePart = Expression(); + result = factory.createTernary(condition, thenPart, elsePart); + return result; + } + public void Parse() { la = new Token(); la.val = ""; Get(); - SimpleLanguage(); - Expect(0); + SimpleLanguage(); + Expect(0); } private static final boolean[][] set = { - {T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x}, - {x,T,x,x, x,x,x,T, x,x,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x}, - {x,T,T,T, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x}, - {x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, x,x,x,x, x,x,x} + {T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x}, + {x,T,x,x, x,x,x,T, x,x,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x}, + {x,T,T,T, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,T, x,x}, + {x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x} }; @@ -388,35 +416,38 @@ public void SynErr(int line, int col, int n) { String s; - switch (n) { - case 0: s = "EOF expected"; break; - case 1: s = "identifier expected"; break; - case 2: s = "stringLiteral expected"; break; - case 3: s = "numericLiteral expected"; break; - case 4: s = "\"function\" expected"; break; - case 5: s = "\"{\" expected"; break; - case 6: s = "\"}\" expected"; break; - case 7: s = "\"while\" expected"; break; - case 8: s = "\"(\" expected"; break; - case 9: s = "\")\" expected"; break; - case 10: s = "\"=\" expected"; break; - case 11: s = "\";\" expected"; break; - case 12: s = "\"print\" expected"; break; - case 13: s = "\"return\" expected"; break; - case 14: s = "\"<\" expected"; break; - case 15: s = "\">\" expected"; break; - case 16: s = "\"<=\" expected"; break; - case 17: s = "\">=\" expected"; break; - case 18: s = "\"==\" expected"; break; - case 19: s = "\"!=\" expected"; break; - case 20: s = "\"+\" expected"; break; - case 21: s = "\"-\" expected"; break; - case 22: s = "\"*\" expected"; break; - case 23: s = "\"/\" expected"; break; - case 24: s = "\"time\" expected"; break; - case 25: s = "??? expected"; break; - case 26: s = "invalid Statement"; break; - case 27: s = "invalid Factor"; break; + switch (n) { + case 0: s = "EOF expected"; break; + case 1: s = "identifier expected"; break; + case 2: s = "stringLiteral expected"; break; + case 3: s = "numericLiteral expected"; break; + case 4: s = "\"function\" expected"; break; + case 5: s = "\"{\" expected"; break; + case 6: s = "\"}\" expected"; break; + case 7: s = "\"while\" expected"; break; + case 8: s = "\"(\" expected"; break; + case 9: s = "\")\" expected"; break; + case 10: s = "\"=\" expected"; break; + case 11: s = "\";\" expected"; break; + case 12: s = "\"print\" expected"; break; + case 13: s = "\"return\" expected"; break; + case 14: s = "\"<\" expected"; break; + case 15: s = "\">\" expected"; break; + case 16: s = "\"<=\" expected"; break; + case 17: s = "\">=\" expected"; break; + case 18: s = "\"==\" expected"; break; + case 19: s = "\"!=\" expected"; break; + case 20: s = "\"+\" expected"; break; + case 21: s = "\"-\" expected"; break; + case 22: s = "\"*\" expected"; break; + case 23: s = "\"/\" expected"; break; + case 24: s = "\"#\" expected"; break; + case 25: s = "\"?\" expected"; break; + case 26: s = "\":\" expected"; break; + case 27: s = "\"time\" expected"; break; + case 28: s = "??? expected"; break; + case 29: s = "invalid Statement"; break; + case 30: s = "invalid Factor"; break; default: s = "error " + n; break; diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java Thu Mar 21 14:11:13 2013 +0100 @@ -311,8 +311,8 @@ static final char EOL = '\n'; static final int eofSym = 0; - static final int maxT = 25; - static final int noSym = 25; + static final int maxT = 28; + static final int noSym = 28; public Buffer buffer; // scanner buffer @@ -339,27 +339,30 @@ for (int i = 65; i <= 90; ++i) start.set(i, 1); for (int i = 97; i <= 122; ++i) start.set(i, 1); for (int i = 49; i <= 57; ++i) start.set(i, 4); - start.set(34, 2); - start.set(48, 5); - start.set(123, 6); - start.set(125, 7); - start.set(40, 8); - start.set(41, 9); - start.set(61, 20); - start.set(59, 10); - start.set(60, 21); - start.set(62, 22); - start.set(33, 14); - start.set(43, 16); - start.set(45, 17); - start.set(42, 18); - start.set(47, 19); + start.set(34, 2); + start.set(48, 5); + start.set(123, 6); + start.set(125, 7); + start.set(40, 8); + start.set(41, 9); + start.set(61, 23); + start.set(59, 10); + start.set(60, 24); + start.set(62, 25); + start.set(33, 14); + start.set(43, 16); + start.set(45, 17); + start.set(42, 18); + start.set(47, 19); + start.set(35, 20); + start.set(63, 21); + start.set(58, 22); start.set(Buffer.EOF, -1); literals.put("function", new Integer(4)); literals.put("while", new Integer(7)); literals.put("print", new Integer(12)); literals.put("return", new Integer(13)); - literals.put("time", new Integer(24)); + literals.put("time", new Integer(27)); } @@ -425,7 +428,7 @@ tval = newBuf; } if (ch != Buffer.EOF) { - tval[tlen++] = (char)ch; + tval[tlen++] = (char)ch; NextCh(); } @@ -484,9 +487,9 @@ } Token NextToken() { - while (ch == ' ' || + while (ch == ' ' || ch >= 9 && ch <= 10 || ch == 13 - ) NextCh(); + ) NextCh(); if (ch == '/' && Comment0() ||ch == '/' && Comment1()) return NextToken(); int recKind = noSym; int recEnd = pos; @@ -515,60 +518,66 @@ } // NextCh already done case 1: recEnd = pos; recKind = 1; - if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {AddCh(); state = 1; break;} + if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {AddCh(); state = 1; break;} else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;} case 2: - if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); state = 2; break;} - else if (ch == '"') {AddCh(); state = 3; break;} + if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); state = 2; break;} + else if (ch == '"') {AddCh(); state = 3; break;} else {state = 0; break;} - case 3: + case 3: {t.kind = 2; break loop;} case 4: recEnd = pos; recKind = 3; - if (ch >= '0' && ch <= '9') {AddCh(); state = 4; break;} + if (ch >= '0' && ch <= '9') {AddCh(); state = 4; break;} else {t.kind = 3; break loop;} - case 5: + case 5: {t.kind = 3; break loop;} - case 6: + case 6: {t.kind = 5; break loop;} - case 7: + case 7: {t.kind = 6; break loop;} - case 8: + case 8: {t.kind = 8; break loop;} - case 9: + case 9: {t.kind = 9; break loop;} - case 10: + case 10: {t.kind = 11; break loop;} - case 11: + case 11: {t.kind = 16; break loop;} - case 12: + case 12: {t.kind = 17; break loop;} - case 13: + case 13: {t.kind = 18; break loop;} case 14: - if (ch == '=') {AddCh(); state = 15; break;} + if (ch == '=') {AddCh(); state = 15; break;} else {state = 0; break;} - case 15: + case 15: {t.kind = 19; break loop;} - case 16: + case 16: {t.kind = 20; break loop;} - case 17: + case 17: {t.kind = 21; break loop;} - case 18: + case 18: {t.kind = 22; break loop;} - case 19: + case 19: {t.kind = 23; break loop;} - case 20: + case 20: + {t.kind = 24; break loop;} + case 21: + {t.kind = 25; break loop;} + case 22: + {t.kind = 26; break loop;} + case 23: recEnd = pos; recKind = 10; - if (ch == '=') {AddCh(); state = 13; break;} + if (ch == '=') {AddCh(); state = 13; break;} else {t.kind = 10; break loop;} - case 21: + case 24: recEnd = pos; recKind = 14; - if (ch == '=') {AddCh(); state = 11; break;} + if (ch == '=') {AddCh(); state = 11; break;} else {t.kind = 14; break loop;} - case 22: + case 25: recEnd = pos; recKind = 15; - if (ch == '=') {AddCh(); state = 12; break;} + if (ch == '=') {AddCh(); state = 12; break;} else {t.kind = 15; break loop;} } diff -r dee7c8b578c7 -r c3657d00e343 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg Thu Mar 21 11:30:38 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg Thu Mar 21 14:11:13 2013 +0100 @@ -131,11 +131,19 @@ | NumericLiteral | + Ternary +| "(" Expression ")" -) +) . -TimeRef +Ternary (. TypedNode condition, thenPart, elsePart; .) += +"#" Expression "?" Expression ":" Expression + (. result = factory.createTernary(condition, thenPart, elsePart); .) +. + +TimeRef = "time" (. result = factory.createTime(); .) . diff -r dee7c8b578c7 -r c3657d00e343 make/Makefile --- a/make/Makefile Thu Mar 21 11:30:38 2013 +0100 +++ b/make/Makefile Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -84,10 +84,12 @@ ALT_OUT= endif +# Directory for shared code (e.g. graal.jar) +SHARED_DIR=$(OUTPUTDIR)/shared + # Typical C1/C2 targets made available with this Makefile C1_VM_TARGETS=product1 fastdebug1 optimized1 jvmg1 C2_VM_TARGETS=product fastdebug optimized jvmg -KERNEL_VM_TARGETS=productkernel fastdebugkernel optimizedkernel jvmgkernel ZERO_VM_TARGETS=productzero fastdebugzero optimizedzero jvmgzero SHARK_VM_TARGETS=productshark fastdebugshark optimizedshark jvmgshark MINIMAL1_VM_TARGETS=productminimal1 fastdebugminimal1 jvmgminimal1 @@ -168,11 +170,6 @@ $(CD) $(GAMMADIR)/make; \ $(MAKE) BUILD_FLAVOR=$@ VM_TARGET=$@ generic_build2 $(ALT_OUT) -$(KERNEL_VM_TARGETS): - $(CD) $(GAMMADIR)/make; \ - $(MAKE) BUILD_FLAVOR=$(@:%kernel=%) VM_TARGET=$@ \ - generic_buildkernel $(ALT_OUT) - $(ZERO_VM_TARGETS): $(CD) $(GAMMADIR)/make; \ $(MAKE) BUILD_FLAVOR=$(@:%zero=%) VM_TARGET=$@ \ @@ -193,7 +190,7 @@ $(MAKE) VM_TARGET=$@ generic_buildgraal $(ALT_OUT) # Build compiler1 (client) rule, different for platforms -generic_build1: +generic_build1: buildshared $(MKDIR) -p $(OUTPUTDIR) ifeq ($(OSNAME),windows) ifeq ($(ARCH_DATA_MODEL), 32) @@ -214,7 +211,7 @@ endif # Build compiler2 (server) rule, different for platforms -generic_build2: +generic_build2: buildshared $(MKDIR) -p $(OUTPUTDIR) ifeq ($(OSNAME),windows) $(CD) $(OUTPUTDIR); \ @@ -230,24 +227,6 @@ $(MAKE_ARGS) $(VM_TARGET) endif -generic_buildkernel: - $(MKDIR) -p $(OUTPUTDIR) -ifeq ($(OSNAME),windows) - ifeq ($(ARCH_DATA_MODEL), 32) - $(CD) $(OUTPUTDIR); \ - $(NMAKE) -f $(ABS_OS_MAKEFILE) \ - Variant=kernel \ - WorkSpace=$(ABS_GAMMADIR) \ - BootStrapDir=$(ABS_BOOTDIR) \ - BuildUser=$(USERNAME) \ - $(MAKE_ARGS) $(VM_TARGET:%kernel=%) - else - @$(ECHO) "No kernel ($(VM_TARGET)) for ARCH_DATA_MODEL=$(ARCH_DATA_MODEL)" - endif -else - @$(ECHO) "No kernel ($(VM_TARGET)) for OS_NAME=$(OSNAME)" -endif - generic_buildzero: $(MKDIR) -p $(OUTPUTDIR) $(CD) $(OUTPUTDIR); \ @@ -281,12 +260,16 @@ @$(ECHO) "Error: trying to build a minimal target but JVM_VARIANT_MINIMAL1 is not true." endif -generic_buildgraal: +generic_buildgraal: buildshared $(MKDIR) -p $(OUTPUTDIR) $(CD) $(OUTPUTDIR); \ $(MAKE) -f $(ABS_OS_MAKEFILE) \ $(MAKE_ARGS) $(VM_TARGET) +# Builds code that can be shared among different build flavors +buildshared: + $(REMOTE) $(ANT) -f $(GAMMADIR)/make/build-graal.xml -Dgamma.dir=$(GAMMADIR) -Dshared.dir=$(SHARED_DIR) + # Export file rule generic_export: $(EXPORT_LIST) export_product: @@ -327,13 +310,11 @@ DOCS_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_docs C1_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_compiler1 C2_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_compiler2 -KERNEL_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_kernel ZERO_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_zero SHARK_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_shark GRAAL_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_graal C1_DIR=$(C1_BASE_DIR)/$(VM_SUBDIR) C2_DIR=$(C2_BASE_DIR)/$(VM_SUBDIR) -KERNEL_DIR=$(KERNEL_BASE_DIR)/$(VM_SUBDIR) ZERO_DIR=$(ZERO_BASE_DIR)/$(VM_SUBDIR) SHARK_DIR=$(SHARK_BASE_DIR)/$(VM_SUBDIR) MINIMAL1_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_minimal1 @@ -348,10 +329,6 @@ MISC_DIR=$(C1_DIR) GEN_DIR=$(C1_BASE_DIR)/generated endif -ifeq ($(JVM_VARIANT_KERNEL), true) - MISC_DIR=$(C2_DIR) - GEN_DIR=$(C2_BASE_DIR)/generated -endif ifeq ($(JVM_VARIANT_ZEROSHARK), true) MISC_DIR=$(SHARK_DIR) GEN_DIR=$(SHARK_BASE_DIR)/generated @@ -401,16 +378,6 @@ $(install-file) $(EXPORT_SERVER_DIR)/%.map: $(C2_DIR)/%.map $(install-file) - -# Kernel files always come from kernel area -$(EXPORT_KERNEL_DIR)/%.diz: $(KERNEL_DIR)/%.diz - $(install-file) -$(EXPORT_KERNEL_DIR)/%.dll: $(KERNEL_DIR)/%.dll - $(install-file) -$(EXPORT_KERNEL_DIR)/%.pdb: $(KERNEL_DIR)/%.pdb - $(install-file) -$(EXPORT_KERNEL_DIR)/%.map: $(KERNEL_DIR)/%.map - $(install-file) endif # Minimal JVM files always come from minimal area @@ -426,6 +393,7 @@ # Shared Library ifneq ($(OSNAME),windows) ifeq ($(JVM_VARIANT_SERVER), true) + # C2 $(EXPORT_JRE_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(C2_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) $(EXPORT_SERVER_DIR)/%.$(LIBRARY_SUFFIX): $(C2_DIR)/%.$(LIBRARY_SUFFIX) @@ -444,7 +412,27 @@ $(install-file) $(EXPORT_SERVER_DIR)/64/%.diz: $(C2_DIR)/%.diz $(install-file) - endif + + # Graal + $(EXPORT_JRE_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(GRAAL_DIR)/%.$(LIBRARY_SUFFIX) + $(install-file) + $(EXPORT_SERVER_DIR)/%.$(LIBRARY_SUFFIX): $(GRAAL_DIR)/%.$(LIBRARY_SUFFIX) + $(install-file) + $(EXPORT_SERVER_DIR)/64/%.$(LIBRARY_SUFFIX): $(GRAAL_DIR)/%.$(LIBRARY_SUFFIX) + $(install-file) + $(EXPORT_JRE_LIB_ARCH_DIR)/%.debuginfo: $(GRAAL_DIR)/%.debuginfo + $(install-file) + $(EXPORT_SERVER_DIR)/%.debuginfo: $(GRAAL_DIR)/%.debuginfo + $(install-file) + $(EXPORT_SERVER_DIR)/64/%.debuginfo: $(GRAAL_DIR)/%.debuginfo + $(install-file) + $(EXPORT_JRE_LIB_ARCH_DIR)/%.diz: $(GRAAL_DIR)/%.diz + $(install-file) + $(EXPORT_SERVER_DIR)/%.diz: $(GRAAL_DIR)/%.diz + $(install-file) + $(EXPORT_SERVER_DIR)/64/%.diz: $(GRAAL_DIR)/%.diz + $(install-file) + endif ifeq ($(JVM_VARIANT_CLIENT), true) $(EXPORT_JRE_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(C1_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) @@ -519,7 +507,8 @@ $(EXPORT_LIB_DIR)/%.jar: $(GEN_DIR)/%.jar $(install-file) -$(EXPORT_JRE_LIB_DIR)/%.jar: $(GEN_DIR)/%.jar +# Shared jar files +$(EXPORT_JRE_LIB_DIR)/%.jar: $(SHARED_DIR)/%.jar $(install-file) # Include files (jvmti.h, jvmticmlr.h, jni.h, $(JDK_INCLUDE_SUBDIR)/jni_md.h, jmm.h, jfr.h) @@ -553,7 +542,7 @@ $(install-file) # Xusage file -$(EXPORT_SERVER_DIR)/Xusage.txt $(EXPORT_CLIENT_DIR)/Xusage.txt $(EXPORT_KERNEL_DIR)/Xusage.txt $(EXPORT_MINIMAL_DIR)/Xusage.txt: $(XUSAGE) +$(EXPORT_SERVER_DIR)/Xusage.txt $(EXPORT_CLIENT_DIR)/Xusage.txt $(EXPORT_MINIMAL_DIR)/Xusage.txt: $(XUSAGE) $(prep-target) $(RM) $@.temp $(SED) 's/\(separated by \)[;:]/\1$(PATH_SEP)/g' $< > $@.temp @@ -564,9 +553,9 @@ # clobber clean: clean_build clean_export clean_jdk clean_build: + $(RM) -r $(SHARED_DIR) $(RM) -r $(C1_DIR) $(RM) -r $(C2_DIR) - $(RM) -r $(KERNEL_DIR) $(RM) -r $(ZERO_DIR) $(RM) -r $(SHARK_DIR) $(RM) -r $(MINIMAL1_DIR) @@ -602,10 +591,6 @@ $(JDK_IMAGE_DIR)/bin/java -d$(ARCH_DATA_MODEL) -server -Xinternalversion $(JDK_IMAGE_DIR)/bin/java -d$(ARCH_DATA_MODEL) -server -version endif - ifeq ($(JVM_VARIANT_KERNEL), true) - $(JDK_IMAGE_DIR)/bin/java -d$(ARCH_DATA_MODEL) -kernel -Xinternalversion - $(JDK_IMAGE_DIR)/bin/java -d$(ARCH_DATA_MODEL) -kernel -version - endif copy_product_jdk:: $(RM) -r $(JDK_IMAGE_DIR) @@ -681,7 +666,6 @@ @$(ECHO) "Other targets are:" @$(ECHO) " $(C1_VM_TARGETS)" @$(ECHO) " $(C2_VM_TARGETS)" - @$(ECHO) " $(KERNEL_VM_TARGETS)" @$(ECHO) " $(MINIMAL1_VM_TARGETS)" # Variable help (only common ones used by this workspace) @@ -777,8 +761,8 @@ include $(GAMMADIR)/make/jprt.gmk .PHONY: all world clobber clean help $(C1_VM_TARGETS) $(C2_VM_TARGETS) \ - $(KERNEL_VM_TARGETS) $(MINIMAL1_VM_TARGETS) \ - generic_build1 generic_build2 generic_buildkernel generic_buildminimal1 generic_export \ + $(MINIMAL1_VM_TARGETS) \ + generic_build1 generic_build2 generic_buildminimal1 generic_export \ export_product export_fastdebug export_debug export_optimized \ export_jdk_product export_jdk_fastdebug export_jdk_debug \ create_jdk copy_jdk update_jdk test_jdk \ diff -r dee7c8b578c7 -r c3657d00e343 make/bsd/makefiles/buildtree.make --- a/make/bsd/makefiles/buildtree.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/bsd/makefiles/buildtree.make Thu Mar 21 14:11:13 2013 +0100 @@ -354,7 +354,7 @@ $(BUILDTREE_COMMENT); \ [ -n "$$JAVA_HOME" ] && { echo ": \$${JAVA_HOME:=$${JAVA_HOME}}"; }; \ { \ - echo "CLASSPATH=$${CLASSPATH:+$$CLASSPATH:}.:\$${JAVA_HOME}/jre/lib/rt.jar:\$${JAVA_HOME}/jre/lib/i18n.jar"; \ + 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; \ echo "HOTSPOT_BUILD_USER=\"$${LOGNAME:-$$USER} in `basename $(GAMMADIR)`\""; \ echo "export JAVA_HOME CLASSPATH HOTSPOT_BUILD_USER"; \ diff -r dee7c8b578c7 -r c3657d00e343 make/bsd/makefiles/defs.make --- a/make/bsd/makefiles/defs.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/bsd/makefiles/defs.make Thu Mar 21 14:11:13 2013 +0100 @@ -157,8 +157,6 @@ EXPORT_CLIENT_DIR = $(EXPORT_JRE_LIB_ARCH_DIR)/client EXPORT_MINIMAL_DIR = $(EXPORT_JRE_LIB_ARCH_DIR)/minimal -EXPORT_LIST += $(EXPORT_JRE_LIB_DIR)/wb.jar - ifeq ($(findstring true, $(JVM_VARIANT_SERVER) $(JVM_VARIANT_ZERO) $(JVM_VARIANT_ZEROSHARK)), true) EXPORT_LIST += $(EXPORT_SERVER_DIR)/Xusage.txt EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm.$(LIBRARY_SUFFIX) diff -r dee7c8b578c7 -r c3657d00e343 make/bsd/makefiles/dtrace.make --- a/make/bsd/makefiles/dtrace.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/bsd/makefiles/dtrace.make Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -25,10 +25,9 @@ # Rules to build jvm_db/dtrace, used by vm.make # We build libjvm_dtrace/libjvm_db/dtrace for COMPILER1 and COMPILER2 -# but not for CORE or KERNEL configurations. +# but not for CORE configuration. ifneq ("${TYPE}", "CORE") -ifneq ("${TYPE}", "KERNEL") ifeq ($(OS_VENDOR), Darwin) # we build dtrace for macosx using USDT2 probes @@ -280,13 +279,6 @@ endif # ifeq ($(OS_VENDOR), Darwin) -else # KERNEL build - -dtraceCheck: - $(QUIETLY) echo "**NOTICE** Dtrace support disabled for KERNEL builds" - -endif # ifneq ("${TYPE}", "KERNEL") - else # CORE build dtraceCheck: diff -r dee7c8b578c7 -r c3657d00e343 make/bsd/makefiles/mapfile-vers-debug --- a/make/bsd/makefiles/mapfile-vers-debug Thu Mar 21 11:30:38 2013 +0100 +++ b/make/bsd/makefiles/mapfile-vers-debug Thu Mar 21 14:11:13 2013 +0100 @@ -188,6 +188,7 @@ JVM_IsSilentCompiler; JVM_IsSupportedJNIVersion; JVM_IsThreadAlive; + JVM_IsVMGeneratedMethodIx; JVM_LatestUserDefinedLoader; JVM_Listen; JVM_LoadClass0; diff -r dee7c8b578c7 -r c3657d00e343 make/bsd/makefiles/mapfile-vers-product --- a/make/bsd/makefiles/mapfile-vers-product Thu Mar 21 11:30:38 2013 +0100 +++ b/make/bsd/makefiles/mapfile-vers-product Thu Mar 21 14:11:13 2013 +0100 @@ -188,6 +188,7 @@ JVM_IsSilentCompiler; JVM_IsSupportedJNIVersion; JVM_IsThreadAlive; + JVM_IsVMGeneratedMethodIx; JVM_LatestUserDefinedLoader; JVM_Listen; JVM_LoadClass0; diff -r dee7c8b578c7 -r c3657d00e343 make/bsd/makefiles/minimal1.make --- a/make/bsd/makefiles/minimal1.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/bsd/makefiles/minimal1.make Thu Mar 21 14:11:13 2013 +0100 @@ -30,7 +30,7 @@ INCLUDE_JNI_CHECK ?= false INCLUDE_SERVICES ?= false INCLUDE_MANAGEMENT ?= false -INCLUDE_ALTERNATE_GCS ?= false +INCLUDE_ALL_GCS ?= false INCLUDE_NMT ?= false INCLUDE_CDS ?= false diff -r dee7c8b578c7 -r c3657d00e343 make/bsd/makefiles/vm.make --- a/make/bsd/makefiles/vm.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/bsd/makefiles/vm.make Thu Mar 21 14:11:13 2013 +0100 @@ -94,7 +94,12 @@ # This is VERY important! The version define must only be supplied to vm_version.o # If not, ccache will not re-use the cache at all, since the version string might contain # a time and date. -vm_version.o: CXXFLAGS += ${JRE_VERSION} +CXXFLAGS/vm_version.o += ${JRE_VERSION} + +CXXFLAGS/BYFILE = $(CXXFLAGS/$@) + +# File specific flags +CXXFLAGS += $(CXXFLAGS/BYFILE) ifdef DEFAULT_LIBPATH CXXFLAGS += -DDEFAULT_LIBPATH="\"$(DEFAULT_LIBPATH)\"" @@ -343,9 +348,6 @@ # Serviceability agent include $(MAKEFILES_DIR)/saproc.make -# Whitebox testing API -include $(MAKEFILES_DIR)/wb.make - #---------------------------------------------------------------------- ifeq ($(OS_VENDOR), Darwin) @@ -353,10 +355,10 @@ dsymutil $(LIBJVM) # no libjvm_db for macosx -build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(BUILDLIBSAPROC) dtraceCheck $(LIBJVM).dSYM $(WB_JAR) +build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(BUILDLIBSAPROC) dtraceCheck $(LIBJVM).dSYM echo "Doing vm.make build:" else -build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(LIBJVM_DB) $(BUILDLIBSAPROC) $(WB_JAR) +build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(LIBJVM_DB) $(BUILDLIBSAPROC) endif install: install_jvm install_jsig install_saproc diff -r dee7c8b578c7 -r c3657d00e343 make/bsd/makefiles/wb.make --- a/make/bsd/makefiles/wb.make Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +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. -# -# - -# Rules to build whitebox testing library, used by vm.make -WB = wb - -WBSRCDIR = $(GAMMADIR)/src/share/tools/whitebox - -WB_JAR = $(GENERATED)/$(WB).jar - -WB_JAVA_SRCS = $(shell find $(WBSRCDIR) -name '*.java') -WB_JAVA_CLASSDIR = $(GENERATED)/wb/classes - -WB_JAVA_CLASSES = $(patsubst $(WBSRCDIR)/%,$(WB_JAVA_CLASSDIR)/%, \ - $(patsubst %.java,%.class,$(WB_JAVA_SRCS))) - -$(WB_JAVA_CLASSDIR)/%.class: $(WBSRCDIR)/%.java $(WB_JAVA_CLASSDIR) - $(REMOTE) $(COMPILE.JAVAC) -sourcepath $(WBSRCDIR) -nowarn -d $(WB_JAVA_CLASSDIR) $< - -$(WB_JAR): $(WB_JAVA_CLASSES) - $(QUIETLY) $(REMOTE) $(RUN.JAR) cf $@ -C $(WB_JAVA_CLASSDIR)/ . - -$(WB_JAVA_CLASSDIR): - $(QUIETLY) mkdir -p $@ - diff -r dee7c8b578c7 -r c3657d00e343 make/build-graal.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make/build-graal.xml Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r dee7c8b578c7 -r c3657d00e343 make/defs.make --- a/make/defs.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/defs.make Thu Mar 21 14:11:13 2013 +0100 @@ -236,6 +236,33 @@ JDK_IMAGE_DIR=$(ALT_JDK_IMAGE_DIR) endif +# Utilities ant +ifeq ($(PLATFORM), windows) + ifeq ($(ANT_HOME),) + ANT_HOME := $(call DirExists,$(JDK_DEVTOOLS_DIR)/share/ant/latest,,) + endif +endif + +# There are few problems with ant we need to workaround: +# 1) ant is using temporary directory java.io.tmpdir +# However, this directory is not unique enough and two separate ant processes +# can easily end up using the exact same temp directory. This may lead to weird build failures +# To workaround this we will define tmp dir explicitly +# 2) ant attempts to detect JDK location based on java.exe location +# This is fragile as developer may have JRE first on the PATH. +# To workaround this we will specify JAVA_HOME explicitly +# 3) Sometimes we need to run ant with the boot jdk, sometimes with the import +# jdk, sometimes with the jdk we are building (see deploy repo). + +ANT_TMPDIR = $(OUTPUTDIR)/tmp +ANT_WORKAROUNDS = ANT_OPTS=-Djava.io.tmpdir='$(ANT_TMPDIR)' + +ifeq ($(ANT_HOME),) + ANT = $(ANT_WORKAROUNDS) JAVA_HOME='$(BOOTDIR)' ant +else + ANT = $(ANT_WORKAROUNDS) JAVA_HOME='$(BOOTDIR)' $(ANT_HOME)/bin/ant +endif + # The platform dependent defs.make defines platform specific variable such # as ARCH, EXPORT_LIST etc. We must place the include here after BOOTDIR is defined. include $(GAMMADIR)/make/$(OSNAME)/makefiles/defs.make @@ -336,6 +363,7 @@ EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jni.h EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/$(JDK_INCLUDE_SUBDIR)/jni_md.h EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jmm.h +EXPORT_LIST += $(EXPORT_JRE_LIB_DIR)/graal.jar # By default, run Queens test after building TEST_IN_BUILD ?= true diff -r dee7c8b578c7 -r c3657d00e343 make/excludeSrc.make --- a/make/excludeSrc.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/excludeSrc.make Thu Mar 21 14:11:13 2013 +0100 @@ -72,15 +72,13 @@ Src_Files_EXCLUDE += metaspaceShared.cpp endif -ifeq ($(INCLUDE_ALTERNATE_GCS), false) - CXXFLAGS += -DINCLUDE_ALTERNATE_GCS=0 - CFLAGS += -DINCLUDE_ALTERNATE_GCS=0 +ifeq ($(INCLUDE_ALL_GCS), false) + CXXFLAGS += -DINCLUDE_ALL_GCS=0 + CFLAGS += -DINCLUDE_ALL_GCS=0 - CXXFLAGS += -DSERIALGC - CFLAGS += -DSERIALGC Src_Files_EXCLUDE += \ cmsAdaptiveSizePolicy.cpp cmsCollectorPolicy.cpp \ - cmsGCAdaptivePolicyCounters.cpp cmsLockVerifier.cpp cmsPermGen.cpp compactibleFreeListSpace.cpp \ + cmsGCAdaptivePolicyCounters.cpp cmsLockVerifier.cpp compactibleFreeListSpace.cpp \ concurrentMarkSweepGeneration.cpp concurrentMarkSweepThread.cpp \ freeChunk.cpp adaptiveFreeList.cpp promotionInfo.cpp vmCMSOperations.cpp collectionSetChooser.cpp \ concurrentG1Refine.cpp concurrentG1RefineThread.cpp concurrentMark.cpp concurrentMarkThread.cpp \ @@ -93,11 +91,11 @@ gcTaskManager.cpp gcTaskThread.cpp objectStartArray.cpp parallelScavengeHeap.cpp parMarkBitMap.cpp \ pcTasks.cpp psAdaptiveSizePolicy.cpp psCompactionManager.cpp psGCAdaptivePolicyCounters.cpp \ psGenerationCounters.cpp psMarkSweep.cpp psMarkSweepDecorator.cpp psOldGen.cpp psParallelCompact.cpp \ - psPermGen.cpp psPromotionLAB.cpp psPromotionManager.cpp psScavenge.cpp psTasks.cpp psVirtualspace.cpp \ + psPromotionLAB.cpp psPromotionManager.cpp psScavenge.cpp psTasks.cpp psVirtualspace.cpp \ psYoungGen.cpp vmPSOperations.cpp asParNewGeneration.cpp parCardTableModRefBS.cpp \ parGCAllocBuffer.cpp parNewGeneration.cpp mutableSpace.cpp gSpaceCounters.cpp allocationStats.cpp \ spaceCounters.cpp gcAdaptivePolicyCounters.cpp mutableNUMASpace.cpp immutableSpace.cpp \ - immutableSpace.cpp g1MemoryPool.cpp psMemoryPool.cpp yieldWorkingGroup.cpp g1Log.cpp + immutableSpace.cpp g1MemoryPool.cpp psMemoryPool.cpp yieldingWorkGroup.cpp g1Log.cpp endif ifeq ($(INCLUDE_NMT), false) diff -r dee7c8b578c7 -r c3657d00e343 make/hotspot_version --- a/make/hotspot_version Thu Mar 21 11:30:38 2013 +0100 +++ b/make/hotspot_version Thu Mar 21 14:11:13 2013 +0100 @@ -35,7 +35,7 @@ HS_MAJOR_VER=25 HS_MINOR_VER=0 -HS_BUILD_NUMBER=17 +HS_BUILD_NUMBER=21 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 diff -r dee7c8b578c7 -r c3657d00e343 make/linux/makefiles/buildtree.make --- a/make/linux/makefiles/buildtree.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/linux/makefiles/buildtree.make Thu Mar 21 14:11:13 2013 +0100 @@ -347,7 +347,7 @@ $(BUILDTREE_COMMENT); \ [ -n "$$JAVA_HOME" ] && { echo ": \$${JAVA_HOME:=$${JAVA_HOME}}"; }; \ { \ - echo "CLASSPATH=$${CLASSPATH:+$$CLASSPATH:}.:\$${JAVA_HOME}/jre/lib/rt.jar:\$${JAVA_HOME}/jre/lib/i18n.jar"; \ + 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; \ echo "HOTSPOT_BUILD_USER=\"$${LOGNAME:-$$USER} in `basename $(GAMMADIR)`\""; \ echo "export JAVA_HOME CLASSPATH HOTSPOT_BUILD_USER"; \ diff -r dee7c8b578c7 -r c3657d00e343 make/linux/makefiles/defs.make --- a/make/linux/makefiles/defs.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/linux/makefiles/defs.make Thu Mar 21 14:11:13 2013 +0100 @@ -258,8 +258,6 @@ EXPORT_CLIENT_DIR = $(EXPORT_JRE_LIB_ARCH_DIR)/client EXPORT_MINIMAL_DIR = $(EXPORT_JRE_LIB_ARCH_DIR)/minimal -EXPORT_LIST += $(EXPORT_JRE_LIB_DIR)/wb.jar - ifeq ($(findstring true, $(JVM_VARIANT_SERVER) $(JVM_VARIANT_ZERO) $(JVM_VARIANT_ZEROSHARK)), true) EXPORT_LIST += $(EXPORT_SERVER_DIR)/Xusage.txt EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm.$(LIBRARY_SUFFIX) diff -r dee7c8b578c7 -r c3657d00e343 make/linux/makefiles/mapfile-vers-debug --- a/make/linux/makefiles/mapfile-vers-debug Thu Mar 21 11:30:38 2013 +0100 +++ b/make/linux/makefiles/mapfile-vers-debug Thu Mar 21 14:11:13 2013 +0100 @@ -184,6 +184,7 @@ JVM_IsSilentCompiler; JVM_IsSupportedJNIVersion; JVM_IsThreadAlive; + JVM_IsVMGeneratedMethodIx; JVM_LatestUserDefinedLoader; JVM_Listen; JVM_LoadClass0; diff -r dee7c8b578c7 -r c3657d00e343 make/linux/makefiles/mapfile-vers-product --- a/make/linux/makefiles/mapfile-vers-product Thu Mar 21 11:30:38 2013 +0100 +++ b/make/linux/makefiles/mapfile-vers-product Thu Mar 21 14:11:13 2013 +0100 @@ -184,6 +184,7 @@ JVM_IsSilentCompiler; JVM_IsSupportedJNIVersion; JVM_IsThreadAlive; + JVM_IsVMGeneratedMethodIx; JVM_LatestUserDefinedLoader; JVM_Listen; JVM_LoadClass0; diff -r dee7c8b578c7 -r c3657d00e343 make/linux/makefiles/minimal1.make --- a/make/linux/makefiles/minimal1.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/linux/makefiles/minimal1.make Thu Mar 21 14:11:13 2013 +0100 @@ -30,7 +30,7 @@ INCLUDE_JNI_CHECK ?= false INCLUDE_SERVICES ?= false INCLUDE_MANAGEMENT ?= false -INCLUDE_ALTERNATE_GCS ?= false +INCLUDE_ALL_GCS ?= false INCLUDE_NMT ?= false INCLUDE_CDS ?= false diff -r dee7c8b578c7 -r c3657d00e343 make/linux/makefiles/vm.make --- a/make/linux/makefiles/vm.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/linux/makefiles/vm.make Thu Mar 21 14:11:13 2013 +0100 @@ -100,7 +100,13 @@ # This is VERY important! The version define must only be supplied to vm_version.o # If not, ccache will not re-use the cache at all, since the version string might contain # a time and date. -vm_version.o: CXXFLAGS += ${JRE_VERSION} +CXXFLAGS/vm_version.o += ${JRE_VERSION} + +CXXFLAGS/BYFILE = $(CXXFLAGS/$@) + +# File specific flags +CXXFLAGS += $(CXXFLAGS/BYFILE) + ifndef JAVASE_EMBEDDED ifneq (${ARCH},arm) @@ -386,12 +392,9 @@ # Serviceability agent include $(MAKEFILES_DIR)/saproc.make -# Whitebox testing API -include $(MAKEFILES_DIR)/wb.make - #---------------------------------------------------------------------- -build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(LIBJVM_DB) $(BUILDLIBSAPROC) dtraceCheck $(WB_JAR) +build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(LIBJVM_DB) $(BUILDLIBSAPROC) dtraceCheck install: install_jvm install_jsig install_saproc diff -r dee7c8b578c7 -r c3657d00e343 make/linux/makefiles/wb.make --- a/make/linux/makefiles/wb.make Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +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. -# -# - -# Rules to build whitebox testing library, used by vm.make -WB = wb - -WBSRCDIR = $(GAMMADIR)/src/share/tools/whitebox - -WB_JAR = $(GENERATED)/$(WB).jar - -WB_JAVA_SRCS = $(shell find $(WBSRCDIR) -name '*.java') -WB_JAVA_CLASSDIR = $(GENERATED)/wb/classes - -WB_JAVA_CLASSES = $(patsubst $(WBSRCDIR)/%,$(WB_JAVA_CLASSDIR)/%, \ - $(patsubst %.java,%.class,$(WB_JAVA_SRCS))) - -$(WB_JAVA_CLASSDIR)/%.class: $(WBSRCDIR)/%.java $(WB_JAVA_CLASSDIR) - $(REMOTE) $(COMPILE.JAVAC) -sourcepath $(WBSRCDIR) -nowarn -d $(WB_JAVA_CLASSDIR) $< - -$(WB_JAR): $(WB_JAVA_CLASSES) - $(QUIETLY) $(REMOTE) $(RUN.JAR) cf $@ -C $(WB_JAVA_CLASSDIR)/ . - -$(WB_JAVA_CLASSDIR): - $(QUIETLY) mkdir -p $@ - diff -r dee7c8b578c7 -r c3657d00e343 make/sa.files --- a/make/sa.files Thu Mar 21 11:30:38 2013 +0100 +++ b/make/sa.files Thu Mar 21 14:11:13 2013 +0100 @@ -24,10 +24,7 @@ # This filelist macro is included in platform specific sa.make # included all packages/*.java. package list can be generated by -# $(GAMMADIR)/agent/make/build-pkglist. Then manually removed all -# classes in sun.jvm.hotspot.ui (and subpackages), all ui classes -# in sun.jvm.hotspot.bugspot/hotspot and SPARC and x86 disassembler -# classes and sun.jvm.hotspot.utilities.soql. +# $(GAMMADIR)/agent/make/build-pkglist. # define AGENT_DIR before including this file in sa.make @@ -40,8 +37,6 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/asm/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/asm/sparc/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/bugspot/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/bugspot/tree/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/c1/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/ci/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/code/*.java \ @@ -82,7 +77,6 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/gc_interface/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/interpreter/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/jdi/*.java \ -$(AGENT_SRC_DIR)/sun/jvm/hotspot/livejvm/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/memory/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/oops/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/opto/*.java \ diff -r dee7c8b578c7 -r c3657d00e343 make/solaris/Makefile --- a/make/solaris/Makefile Thu Mar 21 11:30:38 2013 +0100 +++ b/make/solaris/Makefile Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -157,14 +157,12 @@ SUBDIRS_C2 = $(addprefix $(OSNAME)_$(BUILDARCH)_compiler2/,$(TARGETS)) SUBDIRS_TIERED = $(addprefix $(OSNAME)_$(BUILDARCH)_tiered/,$(TARGETS)) SUBDIRS_CORE = $(addprefix $(OSNAME)_$(BUILDARCH)_core/,$(TARGETS)) -SUBDIRS_KERNEL = $(addprefix $(OSNAME)_$(BUILDARCH)_kernel/,$(TARGETS)) SUBDIRS_GRAAL = $(addprefix $(OSNAME)_$(BUILDARCH)_graal/,$(TARGETS)) TARGETS_C2 = $(TARGETS) TARGETS_C1 = $(addsuffix 1,$(TARGETS)) TARGETS_TIERED = $(addsuffix tiered,$(TARGETS)) TARGETS_CORE = $(addsuffix core,$(TARGETS)) -TARGETS_KERNEL = $(addsuffix kernel,$(TARGETS)) TARGETS_GRAAL = $(addsuffix graal,$(TARGETS)) BUILDTREE_MAKE = $(GAMMADIR)/make/$(OSNAME)/makefiles/buildtree.make @@ -232,10 +230,6 @@ $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks $(BUILDTREE) VARIANT=core -$(SUBDIRS_KERNEL): $(BUILDTREE_MAKE) - $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=kernel - $(SUBDIRS_GRAAL): $(BUILDTREE_MAKE) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks $(BUILDTREE) VARIANT=graal @@ -278,15 +272,6 @@ cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS) install endif -$(TARGETS_KERNEL): $(SUBDIRS_KERNEL) - cd $(OSNAME)_$(BUILDARCH)_kernel/$(patsubst %kernel,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_kernel/$(patsubst %kernel,%,$@) && ./test_gamma -endif -ifdef INSTALL - cd $(OSNAME)_$(BUILDARCH)_kernel/$(patsubst %kernel,%,$@) && $(MAKE) $(MFLAGS) install -endif - $(TARGETS_GRAAL): $(SUBDIRS_GRAAL) cd $(OSNAME)_$(BUILDARCH)_graal/$(patsubst %graal,%,$@) && $(MAKE) $(MFLAGS) ifdef INSTALL @@ -297,7 +282,6 @@ tree: $(SUBDIRS_C2) tree1: $(SUBDIRS_C1) treecore: $(SUBDIRS_CORE) -treekernel: $(SUBDIRS_KERNEL) treegraal: $(SUBDIRS_GRAAL) # Doc target. This is the same for all build options. @@ -318,10 +302,10 @@ clean_docs: rm -rf $(SUBDIR_DOCS) -clean_compiler1 clean_compiler2 clean_core clean_kernel clean_graal: +clean_compiler1 clean_compiler2 clean_core clean_graal: rm -rf $(OSNAME)_$(BUILDARCH)_$(subst clean_,,$@) -clean: clean_compiler2 clean_compiler1 clean_core clean_docs clean_kernel clean_graal +clean: clean_compiler2 clean_compiler1 clean_core clean_docs clean_graal include $(GAMMADIR)/make/cscope.make diff -r dee7c8b578c7 -r c3657d00e343 make/solaris/makefiles/buildtree.make --- a/make/solaris/makefiles/buildtree.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/solaris/makefiles/buildtree.make Thu Mar 21 14:11:13 2013 +0100 @@ -336,7 +336,7 @@ $(BUILDTREE_COMMENT); \ [ -n "$$JAVA_HOME" ] && { echo ": \$${JAVA_HOME:=$${JAVA_HOME}}"; }; \ { \ - echo "CLASSPATH=$${CLASSPATH:+$$CLASSPATH:}.:\$${JAVA_HOME}/jre/lib/rt.jar:\$${JAVA_HOME}/jre/lib/i18n.jar"; \ + 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; \ echo "HOTSPOT_BUILD_USER=\"$${LOGNAME:-$$USER} in `basename $(GAMMADIR)`\""; \ echo "export JAVA_HOME LD_LIBRARY_PATH CLASSPATH HOTSPOT_BUILD_USER"; \ diff -r dee7c8b578c7 -r c3657d00e343 make/solaris/makefiles/defs.make --- a/make/solaris/makefiles/defs.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/solaris/makefiles/defs.make Thu Mar 21 14:11:13 2013 +0100 @@ -187,8 +187,6 @@ endif endif -EXPORT_LIST += $(EXPORT_JRE_LIB_DIR)/wb.jar - EXPORT_SERVER_DIR = $(EXPORT_JRE_LIB_ARCH_DIR)/server EXPORT_CLIENT_DIR = $(EXPORT_JRE_LIB_ARCH_DIR)/client diff -r dee7c8b578c7 -r c3657d00e343 make/solaris/makefiles/dtrace.make --- a/make/solaris/makefiles/dtrace.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/solaris/makefiles/dtrace.make Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -25,10 +25,9 @@ # Rules to build jvm_db/dtrace, used by vm.make # We build libjvm_dtrace/libjvm_db/dtrace for COMPILER1 and COMPILER2 -# but not for CORE or KERNEL configurations. +# but not for CORE configuration. ifneq ("${TYPE}", "CORE") -ifneq ("${TYPE}", "KERNEL") ifdef USE_GCC @@ -362,13 +361,6 @@ endif # ifdef USE_GCC -else # KERNEL build - -dtraceCheck: - $(QUIETLY) echo "**NOTICE** Dtrace support disabled for KERNEL builds" - -endif # ifneq ("${TYPE}", "KERNEL") - else # CORE build dtraceCheck: diff -r dee7c8b578c7 -r c3657d00e343 make/solaris/makefiles/kernel.make --- a/make/solaris/makefiles/kernel.make Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -# -# Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. -# 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. -# -# -# -# Sets make macros for making kernel version of VM. -# This target on solaris is just tempoarily for debugging the kernel build. - -TYPE=KERNEL - -VM_SUBDIR = client - -CFLAGS += -DKERNEL diff -r dee7c8b578c7 -r c3657d00e343 make/solaris/makefiles/mapfile-vers --- a/make/solaris/makefiles/mapfile-vers Thu Mar 21 11:30:38 2013 +0100 +++ b/make/solaris/makefiles/mapfile-vers Thu Mar 21 14:11:13 2013 +0100 @@ -184,6 +184,7 @@ JVM_IsSilentCompiler; JVM_IsSupportedJNIVersion; JVM_IsThreadAlive; + JVM_IsVMGeneratedMethodIx; JVM_LatestUserDefinedLoader; JVM_Listen; JVM_LoadClass0; diff -r dee7c8b578c7 -r c3657d00e343 make/solaris/makefiles/vm.make --- a/make/solaris/makefiles/vm.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/solaris/makefiles/vm.make Thu Mar 21 14:11:13 2013 +0100 @@ -88,7 +88,13 @@ # This is VERY important! The version define must only be supplied to vm_version.o # If not, ccache will not re-use the cache at all, since the version string might contain # a time and date. -vm_version.o: CXXFLAGS += ${JRE_VERSION} +CXXFLAGS/vm_version.o += ${JRE_VERSION} + +CXXFLAGS/BYFILE = $(CXXFLAGS/$@) + +# File specific flags +CXXFLAGS += $(CXXFLAGS/BYFILE) + # CFLAGS_WARN holds compiler options to suppress/enable warnings. CFLAGS += $(CFLAGS_WARN) @@ -347,12 +353,9 @@ # Serviceability agent include $(MAKEFILES_DIR)/saproc.make -# Whitebox testing API -include $(MAKEFILES_DIR)/wb.make - #---------------------------------------------------------------------- -build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(LIBJVM_DB) $(LIBJVM_DTRACE) $(BUILDLIBSAPROC) dtraceCheck $(WB_JAR) +build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(LIBJVM_DB) $(LIBJVM_DTRACE) $(BUILDLIBSAPROC) dtraceCheck install: install_jvm install_jsig install_saproc diff -r dee7c8b578c7 -r c3657d00e343 make/solaris/makefiles/wb.make --- a/make/solaris/makefiles/wb.make Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +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. -# - -# Rules to build whitebox testing library, used by vm.make - -WB = wb - -WBSRCDIR = $(GAMMADIR)/src/share/tools/whitebox - -WB_JAR = $(GENERATED)/$(WB).jar - -WB_JAVA_SRCS = $(shell find $(WBSRCDIR) -name '*.java') -WB_JAVA_CLASSDIR = $(GENERATED)/wb/classes - -WB_JAVA_CLASSES = $(patsubst $(WBSRCDIR)/%,$(WB_JAVA_CLASSDIR)/%, \ - $(patsubst %.java,%.class,$(WB_JAVA_SRCS))) - -$(WB_JAVA_CLASSDIR)/%.class: $(WBSRCDIR)/%.java $(WB_JAVA_CLASSDIR) - $(REMOTE) $(COMPILE.JAVAC) -sourcepath $(WBSRCDIR) -nowarn -d $(WB_JAVA_CLASSDIR) $< - -$(WB_JAR): $(WB_JAVA_CLASSES) - $(QUIETLY) $(REMOTE) $(RUN.JAR) cf $@ -C $(WB_JAVA_CLASSDIR)/ . - -$(WB_JAVA_CLASSDIR): - $(QUIETLY) mkdir -p $@ - diff -r dee7c8b578c7 -r c3657d00e343 make/windows/build.bat --- a/make/windows/build.bat Thu Mar 21 11:30:38 2013 +0100 +++ b/make/windows/build.bat Thu Mar 21 14:11:13 2013 +0100 @@ -1,6 +1,6 @@ @echo off REM -REM Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. +REM Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. REM REM This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,6 @@ :test1 if "%2" == "core" goto test2 -if "%2" == "kernel" goto test2 if "%2" == "compiler1" goto test2 if "%2" == "compiler2" goto test2 if "%2" == "tiered" goto test2 @@ -109,7 +108,7 @@ echo. echo where: echo flavor is "product", "debug" or "fastdebug", -echo version is "core", "kernel", "compiler1", "compiler2", or "tiered", +echo version is "core", "compiler1", "compiler2", or "tiered", echo workspace is source directory without trailing slash, echo bootstrap_dir is a full path to a JDK in which bin/java echo and bin/javac are present and working, and build_id is an diff -r dee7c8b578c7 -r c3657d00e343 make/windows/create_obj_files.sh --- a/make/windows/create_obj_files.sh Thu Mar 21 11:30:38 2013 +0100 +++ b/make/windows/create_obj_files.sh Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, 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 @@ -107,7 +107,6 @@ # Include dirs per type. case "${TYPE}" in "core") Src_Dirs="${CORE_PATHS}" ;; - "kernel") Src_Dirs="${BASE_PATHS} ${COMPILER1_PATHS}" ;; "compiler1") Src_Dirs="${CORE_PATHS} ${COMPILER1_PATHS}" ;; "compiler2") Src_Dirs="${CORE_PATHS} ${COMPILER2_PATHS}" ;; "tiered") Src_Dirs="${CORE_PATHS} ${COMPILER1_PATHS} ${COMPILER2_PATHS}" ;; @@ -120,16 +119,12 @@ SHARK_SPECIFIC_FILES="shark" ZERO_SPECIFIC_FILES="zero" -# These files need to be excluded when building the kernel target. -KERNEL_EXCLUDED_FILES="attachListener.cpp attachListener_windows.cpp metaspaceShared_${Platform_arch_model}.cpp forte.cpp fprofiler.cpp heapDumper.cpp heapInspection.cpp jniCheck.cpp jvmtiCodeBlobEvents.cpp jvmtiExtensions.cpp jvmtiImpl.cpp jvmtiRawMonitor.cpp jvmtiTagMap.cpp jvmtiTrace.cpp vmStructs.cpp g1MemoryPool.cpp psMemoryPool.cpp gcAdaptivePolicyCounters.cpp concurrentGCThread.cpp metaspaceShared.cpp mutableNUMASpace.cpp allocationStats.cpp gSpaceCounters.cpp immutableSpace.cpp mutableSpace.cpp spaceCounters.cpp yieldingWorkgroup.cpp" - # Always exclude these. Src_Files_EXCLUDE="jsig.c jvmtiEnvRecommended.cpp jvmtiEnvStub.cpp" # Exclude per type. case "${TYPE}" in "core") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;; - "kernel") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER2_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ${KERNEL_EXCLUDED_FILES} ciTypeFlow.cpp" ;; "compiler1") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER2_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;; "compiler2") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES}" ;; "tiered") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES}" ;; diff -r dee7c8b578c7 -r c3657d00e343 make/windows/makefiles/debug.make --- a/make/windows/makefiles/debug.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/windows/makefiles/debug.make Thu Mar 21 14:11:13 2013 +0100 @@ -33,7 +33,7 @@ BUILD_PCH_FILE=_build_pch_file.obj !endif -default:: $(BUILD_PCH_FILE) $(AOUT) launcher checkAndBuildSA wb +default:: $(BUILD_PCH_FILE) $(AOUT) launcher checkAndBuildSA !include ../local.make !include compile.make @@ -72,4 +72,3 @@ !include $(WorkSpace)/make/windows/makefiles/shared.make !include $(WorkSpace)/make/windows/makefiles/sa.make !include $(WorkSpace)/make/windows/makefiles/launcher.make -!include $(WorkSpace)/make/windows/makefiles/wb.make diff -r dee7c8b578c7 -r c3657d00e343 make/windows/makefiles/defs.make --- a/make/windows/makefiles/defs.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/windows/makefiles/defs.make Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -157,7 +157,7 @@ MAKE_ARGS += RM="$(RM)" MAKE_ARGS += ZIPEXE=$(ZIPEXE) -# On 32 bit windows we build server, client and kernel, on 64 bit just server. +# On 32 bit windows we build server and client, on 64 bit just server. ifeq ($(JVM_VARIANTS),) ifeq ($(ARCH_DATA_MODEL), 32) JVM_VARIANTS:=client,server @@ -250,7 +250,6 @@ EXPORT_SERVER_DIR = $(EXPORT_JRE_BIN_DIR)/server EXPORT_CLIENT_DIR = $(EXPORT_JRE_BIN_DIR)/client -EXPORT_KERNEL_DIR = $(EXPORT_JRE_BIN_DIR)/kernel ifeq ($(JVM_VARIANT_SERVER),true) EXPORT_LIST += $(EXPORT_SERVER_DIR)/Xusage.txt @@ -277,20 +276,6 @@ endif endif endif -ifeq ($(JVM_VARIANT_KERNEL),true) - EXPORT_LIST += $(EXPORT_KERNEL_DIR)/Xusage.txt - EXPORT_LIST += $(EXPORT_KERNEL_DIR)/jvm.$(LIBRARY_SUFFIX) - ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - ifeq ($(ZIP_DEBUGINFO_FILES),1) - EXPORT_LIST += $(EXPORT_KERNEL_DIR)/jvm.diz - else - EXPORT_LIST += $(EXPORT_KERNEL_DIR)/jvm.pdb - EXPORT_LIST += $(EXPORT_KERNEL_DIR)/jvm.map - endif - endif -endif - -EXPORT_LIST += $(EXPORT_JRE_LIB_DIR)/wb.jar ifeq ($(BUILD_WIN_SA), 1) EXPORT_LIST += $(EXPORT_JRE_BIN_DIR)/sawindbg.$(LIBRARY_SUFFIX) diff -r dee7c8b578c7 -r c3657d00e343 make/windows/makefiles/fastdebug.make --- a/make/windows/makefiles/fastdebug.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/windows/makefiles/fastdebug.make Thu Mar 21 14:11:13 2013 +0100 @@ -33,7 +33,7 @@ BUILD_PCH_FILE=_build_pch_file.obj !endif -default:: $(BUILD_PCH_FILE) $(AOUT) launcher checkAndBuildSA wb +default:: $(BUILD_PCH_FILE) $(AOUT) launcher checkAndBuildSA !include ../local.make !include compile.make @@ -71,4 +71,3 @@ !include $(WorkSpace)/make/windows/makefiles/shared.make !include $(WorkSpace)/make/windows/makefiles/sa.make !include $(WorkSpace)/make/windows/makefiles/launcher.make -!include $(WorkSpace)/make/windows/makefiles/wb.make diff -r dee7c8b578c7 -r c3657d00e343 make/windows/makefiles/product.make --- a/make/windows/makefiles/product.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/windows/makefiles/product.make Thu Mar 21 14:11:13 2013 +0100 @@ -32,7 +32,7 @@ BUILD_PCH_FILE=_build_pch_file.obj !endif -default:: $(BUILD_PCH_FILE) $(AOUT) launcher checkAndBuildSA wb +default:: $(BUILD_PCH_FILE) $(AOUT) launcher checkAndBuildSA !include ../local.make !include compile.make @@ -82,4 +82,3 @@ !include $(WorkSpace)/make/windows/makefiles/shared.make !include $(WorkSpace)/make/windows/makefiles/sa.make !include $(WorkSpace)/make/windows/makefiles/launcher.make -!include $(WorkSpace)/make/windows/makefiles/wb.make diff -r dee7c8b578c7 -r c3657d00e343 make/windows/makefiles/projectcreator.make --- a/make/windows/makefiles/projectcreator.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/windows/makefiles/projectcreator.make Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -145,8 +145,10 @@ -ignorePath_TARGET c1_ ProjectCreatorIDEOptionsIgnoreGraal=\ - -ignorePath_TARGET graal - + -ignorePath_TARGET src/share/vm/graal \ + -ignorePath_TARGET graal/generated \ + -ignorePath_TARGET vm/graal + ProjectCreatorIDEOptionsIgnoreCompiler2=\ -ignorePath_TARGET compiler2 \ -ignorePath_TARGET tiered \ @@ -170,70 +172,13 @@ $(ProjectCreatorIDEOptionsIgnoreCompiler2:TARGET=core) ################################################## -# JKERNEL specific options -################################################## -ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \ - -define_kernel KERNEL \ -$(ProjectCreatorIDEOptionsIgnoreCompiler2:TARGET=kernel) \ - -ignorePath_kernel src/share/vm/gc_implementation/parallelScavenge \ - -ignorePath_kernel src/share/vm/gc_implementation/parNew \ - -ignorePath_kernel src/share/vm/gc_implementation/concurrentMarkSweep \ - -ignorePath_kernel src/share/vm/gc_implementation/g1 \ - -ignoreFile_kernel attachListener.cpp \ - -ignoreFile_kernel attachListener_windows.cpp \ - -ignoreFile_kernel dump.cpp \ - -ignoreFile_kernel dump_$(Platform_arch_model).cpp \ - -ignoreFile_kernel forte.cpp \ - -ignoreFile_kernel fprofiler.cpp \ - -ignoreFile_kernel heapDumper.cpp \ - -ignoreFile_kernel heapInspection.cpp \ - -ignoreFile_kernel jniCheck.cpp \ - -ignoreFile_kernel jvmtiCodeBlobEvents.cpp \ - -ignoreFile_kernel jvmtiExtensions.cpp \ - -ignoreFile_kernel jvmtiImpl.cpp \ - -ignoreFile_kernel jvmtiRawMonitor.cpp \ - -ignoreFile_kernel jvmtiTagMap.cpp \ - -ignoreFile_kernel jvmtiTrace.cpp \ - -ignoreFile_kernel jvmtiTrace.hpp \ - -ignoreFile_kernel restore.cpp \ - -ignoreFile_kernel serialize.cpp \ - -ignoreFile_kernel vmStructs.cpp \ - -ignoreFile_kernel g1MemoryPool.cpp \ - -ignoreFile_kernel g1MemoryPool.hpp \ - -ignoreFile_kernel psMemoryPool.cpp \ - -ignoreFile_kernel psMemoryPool.hpp \ - -ignoreFile_kernel gcAdaptivePolicyCounters.cpp \ - -ignoreFile_kernel concurrentGCThread.cpp \ - -ignoreFile_kernel mutableNUMASpace.cpp \ - -ignoreFile_kernel ciTypeFlow.cpp \ - -ignoreFile_kernel ciTypeFlow.hpp \ - -ignoreFile_kernel oop.pcgc.inline.hpp \ - -ignoreFile_kernel oop.psgc.inline.hpp \ - -ignoreFile_kernel allocationStats.cpp \ - -ignoreFile_kernel allocationStats.hpp \ - -ignoreFile_kernel concurrentGCThread.hpp \ - -ignoreFile_kernel gSpaceCounters.cpp \ - -ignoreFile_kernel gSpaceCounters.hpp \ - -ignoreFile_kernel gcAdaptivePolicyCounters.hpp \ - -ignoreFile_kernel immutableSpace.cpp \ - -ignoreFile_kernel mutableNUMASpace.hpp \ - -ignoreFile_kernel mutableSpace.cpp \ - -ignoreFile_kernel spaceCounters.cpp \ - -ignoreFile_kernel spaceCounters.hpp \ - -ignoreFile_kernel yieldingWorkgroup.cpp \ - -ignoreFile_kernel yieldingWorkgroup.hpp \ - -ignorePath_kernel vmStructs_ \ - -ignoreFile_kernel $(Platform_arch_model).ad \ - -additionalFile_kernel gcTaskManager.hpp - -################################################## # Client(C1) compiler specific options ################################################## ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \ -define_compiler1 COMPILER1 \ + -define_compiler1 GRAAL \ -ignorePath_compiler1 core \ - -ignorePath_compiler1 src/share/vm/graal \ - $(ProjectCreatorIDEOptionsIgnoreGraal:TARGET=compiler1) \ + -ignorePath_compiler1 graal/generated \ $(ProjectCreatorIDEOptionsIgnoreCompiler2:TARGET=compiler1) ################################################## @@ -242,7 +187,6 @@ ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \ -define_graal GRAAL \ -ignorePath_graal core \ - -ignorePath_graal src/share/vm/c1 \ $(ProjectCreatorIDEOptionsIgnoreCompiler1:TARGET=graal) \ $(ProjectCreatorIDEOptionsIgnoreCompiler2:TARGET=graal) @@ -252,8 +196,10 @@ #NOTE! This list must be kept in sync with GENERATED_NAMES in adlc.make. ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \ -define_compiler2 COMPILER2 \ + -define_compiler2 GRAAL \ + -define_compiler2 TIERED \ -ignorePath_compiler2 core \ - -ignorePath_compiler2 src/share/vm/graal \ + -ignorePath_compiler2 graal/generated \ -additionalFile_compiler2 $(Platform_arch_model).ad \ -additionalFile_compiler2 ad_$(Platform_arch_model).cpp \ -additionalFile_compiler2 ad_$(Platform_arch_model).hpp \ @@ -266,7 +212,6 @@ -additionalFile_compiler2 ad_$(Platform_arch_model)_pipeline.cpp \ -additionalFile_compiler2 adGlobals_$(Platform_arch_model).hpp \ -additionalFile_compiler2 dfa_$(Platform_arch_model).cpp \ - $(ProjectCreatorIDEOptionsIgnoreGraal:TARGET=compiler2) \ $(ProjectCreatorIDEOptionsIgnoreCompiler1:TARGET=compiler2) # Add in the jvmti (JSR-163) options diff -r dee7c8b578c7 -r c3657d00e343 make/windows/makefiles/vm.make --- a/make/windows/makefiles/vm.make Thu Mar 21 11:30:38 2013 +0100 +++ b/make/windows/makefiles/vm.make Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -44,10 +44,6 @@ # No need to define anything, CORE is defined as !COMPILER1 && !COMPILER2 !endif -!if "$(Variant)" == "kernel" -CXX_FLAGS=$(CXX_FLAGS) /D "KERNEL" -!endif - !if "$(Variant)" == "compiler1" CXX_FLAGS=$(CXX_FLAGS) /D "COMPILER1" !endif diff -r dee7c8b578c7 -r c3657d00e343 make/windows/makefiles/wb.make --- a/make/windows/makefiles/wb.make Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +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. -# -# - -# This makefile is used to build the whitebox testing lib -# and compile the tests which use it - -!include $(WorkSpace)/make/windows/makefiles/rules.make - -WBSRCDIR = $(WorkSpace)/src/share/tools/whitebox - -# turn GENERATED into a windows path to get sane dependencies -WB_CLASSES=$(GENERATED:/=\)\wb\classes -WB_JAR=$(GENERATED:/=\)\wb.jar - -# call recursive make to do wildcard expansion -.SUFFIXES : .java .class -wb_java_srcs: $(WorkSpace)\src\share\tools\whitebox\sun\hotspot\*.java $(WB_CLASSES) - $(MAKE) -f $(WorkSpace)\make\windows\makefiles\$(BUILD_FLAVOR).make $(**:.java=.class) - - -{$(WorkSpace)\src\share\tools\whitebox\sun\hotspot}.java.class:: - $(COMPILE_JAVAC) -sourcepath $(WBSRCDIR) -d $(WB_CLASSES) $< - -$(WB_JAR): wb_java_srcs - $(RUN_JAR) cf $@ -C $(WB_CLASSES) . - -# turn $@ to a unix path because mkdir in PATH is cygwin/mks mkdir -$(WB_CLASSES): - mkdir -p $(@:\=/) - -# main target to build wb -wb: $(WB_JAR) - diff -r dee7c8b578c7 -r c3657d00e343 mx/JUnitWrapper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mx/JUnitWrapper.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,73 @@ +/* + * 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. + */ + + +/* Execute testcases by reading names from a given file, due to limits of + * the operating system regarding command line size (windows: 32k, + * linux [depending on the settings]: ~2097k) + * see http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx + */ + +import org.junit.runner.*; +import java.io.*; +import java.util.*; + +public class JUnitWrapper { + + /** + * @param args + * args[0] is the path where to read the names of the testclasses. + */ + public static void main(String[] args) { + if (args.length == 0) { + System.err.printf("wrong usage. provide a filename\n"); + System.exit(1); + } + ArrayList tests = new ArrayList(1000); + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(args[0])); + + String buf; + while ((buf = br.readLine()) != null) { + tests.add(buf); + } + } catch (IOException ioe) { + ioe.printStackTrace(); + System.exit(2); + } finally { + try { + if (br != null) { + br.close(); + } + } catch (IOException ioe) { + ioe.printStackTrace(); + System.exit(3); + } + } + + String[] strargs = tests.toArray(new String[tests.size()]); + System.out.printf("executing junit tests now... (%d testclasses)\n", strargs.length); + JUnitCore.main(strargs); + } +} diff -r dee7c8b578c7 -r c3657d00e343 mx/commands.py --- a/mx/commands.py Thu Mar 21 11:30:38 2013 +0100 +++ b/mx/commands.py Thu Mar 21 14:11:13 2013 +0100 @@ -27,7 +27,7 @@ # ---------------------------------------------------------------------------------------------------- import os, sys, shutil, zipfile, tempfile, re, time, datetime, platform, subprocess, multiprocessing -from os.path import join, exists, dirname, basename +from os.path import join, exists, dirname, basename, getmtime from argparse import ArgumentParser, REMAINDER import mx import sanitycheck @@ -52,30 +52,7 @@ _make_eclipse_launch = False -_copyrightTemplate = """/* - * Copyright (c) {0}, Oracle and/or its affiliates. All rights reserved. - * 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. - */ - -""" +_minVersion = mx.JavaVersion('1.7.0_04') def _chmodDir(chmodFlags, dirname, fnames): os.chmod(dirname, chmodFlags) @@ -91,7 +68,7 @@ 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' + mx.java().version) + jdks = join(_graal_home, 'jdk' + str(mx.java().version)) if exists(jdks): shutil.rmtree(jdks) @@ -314,11 +291,11 @@ return join(jdk, 'jre', 'lib', _arch(), 'jvm.cfg') return join(_vmLibDirInJdk(jdk), 'jvm.cfg') -def _jdk(build='product', create=False): +def _jdk(build='product', vmToCheck=None, create=False): """ Get the JDK into which Graal is installed, creating it first if necessary. """ - jdk = join(_graal_home, 'jdk' + mx.java().version, build) + jdk = join(_graal_home, 'jdk' + str(mx.java().version), build) jdkContents = ['bin', 'include', 'jre', 'lib'] if (exists(join(jdk, 'db'))): jdkContents.append('db') @@ -342,7 +319,6 @@ if not exists(jvmCfg): mx.abort(jvmCfg + ' does not exist') - lines = [] defaultVM = None with open(jvmCfg) as f: for line in f: @@ -351,17 +327,14 @@ assert len(parts) == 2, parts assert parts[1] == 'KNOWN', parts[1] defaultVM = parts[0][1:] - lines.append('-' + defaultVM + '0 KNOWN\n') - lines.append(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')) - with open(jvmCfg, 'w') as f: - for line in lines: - f.write(line) + with open(jvmCfg, 'w') as fp: + print >> fp, '-' + defaultVM + '0 KNOWN' # Install a copy of the disassembler library try: @@ -370,9 +343,36 @@ pass else: if not exists(jdk): - mx.abort('The ' + build + ' VM has not been created - run \'mx clean; mx build ' + build + '\'') + mx.abort('The ' + build + ' VM has not been created - run "mx build ' + build + '"') + + _installGraalJarInJdks(mx.distribution('GRAAL')) + + if vmToCheck is not None: + jvmCfg = _vmCfgInJdk(jdk) + found = False + with open(jvmCfg) as f: + for line in f: + if line.strip() == '-' + vmToCheck + ' KNOWN': + found = True + break + if not found: + mx.abort('The ' + build + ' ' + vmToCheck + ' VM has not been created - run "mx --vm ' + vmToCheck + ' build ' + build + '"') + return jdk +def _installGraalJarInJdks(graalDist): + graalJar = graalDist.path + jdks = join(_graal_home, 'jdk' + str(mx.java().version)) + if exists(jdks): + for e in os.listdir(jdks): + jreLibDir = join(jdks, e, 'jre', 'lib') + if exists(jreLibDir): + # do a copy and then a move to get atomic updating (on Unix) of graal.jar in the JRE + fd, tmp = tempfile.mkstemp(suffix='', prefix='graal.jar', dir=jreLibDir) + shutil.copyfile(graalJar, tmp) + os.close(fd) + shutil.move(tmp, join(jreLibDir, 'graal.jar')) + # run a command in the windows SDK Debug Shell def _runInDebugShell(cmd, workingDir, logFile=None, findInOutput=None, respondTo={}): newLine = os.linesep @@ -435,7 +435,79 @@ """print the JDK directory selected for the 'vm' command""" build = _vmbuild if _vmSourcesAvailable else 'product' - print join(_graal_home, 'jdk' + mx.java().version, build) + print join(_graal_home, 'jdk' + str(mx.java().version), build) + +def initantbuild(args): + """(re)generates an ant build file for producing graal.jar""" + parser=ArgumentParser(prog='mx initantbuild') + parser.add_argument('-f', '--buildfile', help='file to generate', default=join(_graal_home, 'make', 'build-graal.xml')) + + args = parser.parse_args(args) + + out = mx.XMLDoc() + + out.comment(""" + 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. Oracle designates this + particular file as subject to the "Classpath" exception as provided + by Oracle in the LICENSE file that accompanied this code. + + 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. +""") + + out.open('project', {'name' : 'graal', 'default' : 'main', 'basedir' : '.'}) + out.element('property', {'name' : 'src.dir', 'value' : '${gamma.dir}/graal'}) + out.element('property', {'name' : 'classes.dir', 'value' : '${shared.dir}/graal'}) + out.element('property', {'name' : 'jar.dir', 'value' : '${shared.dir}'}) + out.element('property', {'name' : 'jar.file', 'value' : '${jar.dir}/graal.jar'}) + + out.element('target', {'name' : 'main', 'depends' : 'jar'}) + + out.open('target', {'name' : 'compile'}) + 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): + out.element('src', {'path' : '${src.dir}/' + p.name}) + out.element('compilerarg', {'value' : '-XDignore.symbol.file'}) + + out.open('classpath') + out.open('fileset', {'dir' : '${java.home}/../lib'}) + out.element('include', {'name' : 'tools.jar'}) + out.close('fileset') + out.close('classpath') + + out.close('javac') + out.close('target') + + out.open('target', {'name' : 'jar', 'depends' : 'compile'}) + out.element('mkdir', {'dir' : '${jar.dir}'}) + out.element('jar', {'destfile' : '${jar.file}', 'basedir' : '${classes.dir}'}) + out.close('target') + + out.open('target', {'name' : 'clean'}) + out.element('delete', {'dir' : '${classes.dir}'}) + out.element('delete', {'file' : '${jar.filr}'}) + out.close('target') + + out.close('project') + + mx.update_file(args.buildfile, out.xml(indent=' ', newl='\n')) def build(args, vm=None): """build the VM binary @@ -465,6 +537,8 @@ else: assert vm == 'graal', vm buildSuffix = 'graal' + + initantbuild([]) for build in builds: if build == 'ide-build-target': @@ -486,25 +560,6 @@ if not 'Xusage.txt' in line: sys.stderr.write(line + os.linesep) - # Check that the declaration of graal_projects in arguments.cpp is up to date - argumentsCpp = join(_graal_home, 'src', 'share', 'vm', 'runtime', 'arguments.cpp') - assert exists(argumentsCpp), 'File does not exist: ' + argumentsCpp - with open(argumentsCpp) as fp: - source = fp.read(); - decl = 'const char* graal_projects[] = {' - start = source.find(decl) - assert start != -1, 'Could not find "' + decl + '" in ' + fp.name - end = source.find('};', start) - assert end != -1, 'Could not find "' + decl + '" ... "};" in ' + fp.name - actual = frozenset(re.findall(r'"([^"]+)"', source[start + len(decl):end])) - expected = frozenset([p.name for p in mx.project('com.oracle.graal.hotspot.' + _arch()).all_deps([], False)]) - missing = expected - actual - extra = actual - expected - if len(missing) != 0: - mx.abort(fp.name + ':' + str(source[:start].count('\n') + 1) + ': add missing project(s) to declaration:\n ' + '\n '.join(missing)) - if len(extra) != 0: - mx.abort(fp.name + ':' + str(source[:start].count('\n') + 1) + ': remove project(s) from declaration:\n ' + '\n '.join(extra)) - # Check if a build really needs to be done timestampFile = join(vmDir, '.build-timestamp') if opts2.force or not exists(timestampFile): @@ -589,23 +644,18 @@ mx.abort(jvmCfg + ' does not exist') prefix = '-' + vm - vmKnown = prefix + ' KNOWN\n' - lines = [] + vmKnown = prefix + ' KNOWN' with open(jvmCfg) as f: for line in f: - if vmKnown in line: + if vmKnown == line.strip(): found = True break - if not line.startswith(prefix): - lines.append(line) if not found: mx.log('Appending "' + prefix + ' KNOWN" to ' + jvmCfg) - lines.append(vmKnown) if mx.get_os() != 'windows': os.chmod(jvmCfg, 0755) - with open(jvmCfg, 'w') as f: - for line in lines: - f.write(line) + with open(jvmCfg, 'a') as f: + print >> f, vmKnown if exists(timestampFile): os.utime(timestampFile, None) @@ -627,7 +677,7 @@ vm = _vm build = vmbuild if vmbuild is not None else _vmbuild if _vmSourcesAvailable else 'product' - jdk = _jdk(build) + jdk = _jdk(build, vmToCheck=vm) mx.expand_project_in_args(args) if _make_eclipse_launch: mx.make_eclipse_launch(args, 'graal-' + build, name=None, deps=mx.project('com.oracle.graal.hotspot').all_deps([], True)) @@ -654,6 +704,7 @@ args = ['-javaagent:' + jacocoagent.get_path(True) + '=' + ','.join([k + '=' + v for k, v in agentOptions.items()])] + args if '-d64' not in args: args = ['-d64'] + args + exe = join(jdk, 'bin', mx.exe_suffix('java')) dbg = _native_dbg.split() if _native_dbg is not None else [] return mx.run(dbg + [exe, '-' + vm] + args, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd, timeout=timeout) @@ -668,7 +719,7 @@ matches = lambda line : len([a for a in annotations if line == a or line.startswith(a + '(')]) != 0 return p.find_classes_with_matching_source_line(pkgRoot, matches, includeInnerClasses) -def _run_tests(args, harness): +def _run_tests(args, harness, annotations, testfile): pos = [a for a in args if a[0] != '-' and a[0] != '@' ] neg = [a[1:] for a in args if a[0] == '-'] vmArgs = [a[1:] for a in args if a[0] == '@'] @@ -679,29 +730,66 @@ return True return False + classes = [] for p in mx.projects(): - classes = _find_classes_with_annotations(p, None, ['@Test']) + classes += _find_classes_with_annotations(p, None, annotations) if len(pos) != 0: classes = [c for c in classes if containsAny(c, pos)] if len(neg) != 0: classes = [c for c in classes if not containsAny(c, neg)] - if len(classes) != 0: - mx.log('running tests in ' + p.name) - harness(p, vmArgs, classes) + projectscp = mx.classpath([pcp.name for pcp in mx.projects()]) + + if len(classes) != 0: + f_testfile = open(testfile, 'w') + for c in classes: + f_testfile.write(c + '\n') + f_testfile.close() + harness(projectscp, vmArgs) + +def _unittest(args, annotations): + mxdir = dirname(__file__) + name = 'JUnitWrapper' + javaSource = join(mxdir, name + '.java') + javaClass = join(mxdir, name + '.class') + (_, 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]) + prefixArgs = ['-XX:-BootstrapGraal', '-esa', '-ea'] + vm(prefixArgs + vmArgs + ['-cp', projectscp + ':' + mxdir, name] + [testfile]) + + _run_tests(args, harness, annotations, testfile) + os.remove(testfile) def unittest(args): - """run the JUnit tests + """run the JUnit tests (all testcases) If filters are supplied, only tests whose fully qualified name include a filter as a substring are run. Negative filters are those with a '-' prefix. VM args should have a @ prefix.""" - def harness(p, vmArgs, classes): - prefixArgs = ['-XX:-BootstrapGraal', '-esa', '-ea'] - vm(prefixArgs + vmArgs + ['-cp', mx.classpath(p.name), 'org.junit.runner.JUnitCore'] + classes) - _run_tests(args, harness) + _unittest(args, ['@Test', '@LongTest']) + +def shortunittest(args): + """run the JUnit tests (short testcases only) + + If filters are supplied, only tests whose fully qualified name + include a filter as a substring are run. Negative filters are + those with a '-' prefix. VM args should have a @ prefix.""" + + _unittest(args, ['@Test']) + +def longunittest(args): + """run the JUnit tests (long testcases only) + + If filters are supplied, only tests whose fully qualified name + include a filter as a substring are run. Negative filters are + those with a '-' prefix. VM args should have a @ prefix.""" + + _unittest(args, ['@LongTest']) def buildvms(args): """build one or more VMs in various configurations""" @@ -784,11 +872,22 @@ if mx.eclipseformat(['-e', eclipse_exe]) != 0: t.abort('Formatter modified files - run "mx eclipseformat", check in changes and repush') tasks.append(t.stop()) + + t = Task('Canonicalization Check') + mx.log(time.strftime('%d %b %Y %H:%M:%S - Ensuring mx/projects files are canonicalized...')) + if mx.canonicalizeprojects([]) != 0: + t.abort('Rerun "mx canonicalizeprojects" and check-in the modified mx/projects files.') + tasks.append(t.stop()) t = Task('BuildJava') build(['--no-native', '--jdt-warning-as-error']) tasks.append(t.stop()) + t = Task('Checkstyle') + if mx.checkstyle([]) != 0: + t.abort('Checkstyle warnings were found') + tasks.append(t.stop()) + if exists('jacoco.exec'): os.unlink('jacoco.exec') @@ -796,10 +895,9 @@ _jacoco = 'append' else: _jacoco = 'off' - t = Task('BuildHotSpotGraal: fastdebug,product') - buildvms(['--vms', 'graal', '--builds', 'fastdebug,product']) + buildvms(['--vms', 'graal,server', '--builds', 'fastdebug,product']) tasks.append(t.stop()) _vmbuild = 'fastdebug' @@ -808,9 +906,16 @@ tasks.append(t.stop()) _vmbuild = 'product' - t = Task('UnitTests:product') + t = Task('BootstrapWithRegisterPressure:product') + vm(['-G:RegisterPressure=rbx,r11,r14,xmm3,xmm11,xmm14', '-esa', '-version']) + tasks.append(t.stop()) + + originalVm = _vm + _vm = 'server' # hosted mode + t = Task('UnitTests:hosted-product') unittest([]) tasks.append(t.stop()) + _vm = originalVm for vmbuild in ['fastdebug', 'product']: for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild): @@ -824,17 +929,6 @@ _jacoco = 'off' - t = Task('Checkstyle') - if mx.checkstyle([]) != 0: - t.abort('Checkstyle warnings were found') - tasks.append(t.stop()) - - t = Task('Canonicalization Check') - mx.log(time.strftime('%d %b %Y %H:%M:%S - Ensuring mx/projects files are canonicalized...')) - if mx.canonicalizeprojects([]) != 0: - t.abort('Rerun "mx canonicalizeprojects" and check-in the modified mx/projects files.') - tasks.append(t.stop()) - t = Task('CleanAndBuildGraalVisualizer') mx.run(['ant', '-f', join(_graal_home, 'visualizer', 'build.xml'), '-q', 'clean', 'build']) tasks.append(t.stop()) @@ -1016,6 +1110,24 @@ benchArgs.remove(args[itIdx+1]) vm = _vm; sanitycheck.getSPECjvm2008(benchArgs, skipCheck, skipValid, wt, it).bench(vm, opts=vmArgs) + +def specjbb2013(args): + """runs the composite SPECjbb2013 benchmark + + All options begining with - will be passed to the vm""" + benchArgs = [a for a in args if a[0] != '-'] + vmArgs = [a for a in args if a[0] == '-'] + vm = _vm; + sanitycheck.getSPECjbb2013(benchArgs).bench(vm, opts=vmArgs) + +def specjbb2005(args): + """runs the composite SPECjbb2005 benchmark + + All options begining with - will be passed to the vm""" + benchArgs = [a for a in args if a[0] != '-'] + vmArgs = [a for a in args if a[0] == '-'] + vm = _vm; + sanitycheck.getSPECjbb2005(benchArgs).bench(vm, opts=vmArgs) def hsdis(args, copyToDir=None): """download the hsdis library @@ -1094,20 +1206,6 @@ mx.abort('jacocoreport takes only one argument : an output directory') mx.run_java(['-jar', jacocoreport.get_path(True), '-in', 'jacoco.exec', '-g', join(_graal_home, 'graal'), out]) -def jar(args): - parser = ArgumentParser(prog='mx jar'); - parser.add_argument('projects', nargs=REMAINDER, metavar='projects...') - args = parser.parse_args(args) - - if not args.projects: - mx.abort('Please specify at least one project to jar.') - - for pname in args.projects: - p = mx.project(pname, fatalIfMissing=True) - outputDir = p.output_dir() - targetJar = join(p.dir, p.name + '.jar') - mx.jar(targetJar, [outputDir]) - def site(args): """create a website containing javadoc and the project dependency graph""" @@ -1129,17 +1227,21 @@ 'clean': [clean, ''], 'hsdis': [hsdis, '[att]'], 'hcfdis': [hcfdis, ''], + 'initantbuild' : [initantbuild, '[-options]'], 'igv' : [igv, ''], 'jdkhome': [jdkhome, ''], 'dacapo': [dacapo, '[[n] benchmark] [VM options|@DaCapo options]'], 'scaladacapo': [scaladacapo, '[[n] benchmark] [VM options|@Scala DaCapo options]'], - 'specjvm2008': [specjvm2008, '[VM options|@specjvm2008 options]'], - 'jar': [jar, '[-options]'], + 'specjvm2008': [specjvm2008, '[VM options|specjvm2008 options (-v, -ikv, -ict, -wt, -it)]'], + 'specjbb2013': [specjbb2013, '[VM options]'], + 'specjbb2005': [specjbb2005, '[VM options]'], #'example': [example, '[-v] example names...'], 'gate' : [gate, '[-options]'], 'gv' : [gv, ''], 'bench' : [bench, '[-resultfile file] [all(default)|dacapo|specjvm2008|bootstrap]'], 'unittest' : [unittest, '[filters...]'], + 'longunittest' : [longunittest, '[filters...]'], + 'shortunittest' : [shortunittest, '[filters...]'], 'jacocoreport' : [jacocoreport, '[output directory]'], 'site' : [site, '[-options]'], 'vm': [vm, '[-options] class [args...]'], @@ -1168,23 +1270,10 @@ mx.commands.update(commands) -def mx_post_parse_cmd_line(opts): - version = mx.java().version.split('-')[0] - parts = version.split('.') - assert len(parts) >= 2 - assert parts[0] == '1' - major = int(parts[1]) - minor = 0 - update = 0 - if len(parts) >= 3: - minorParts = parts[2].split('_') - if len(minorParts) >= 1: - minor = int(minorParts[0]) - if len(minorParts) >= 2: - update = int(minorParts[1]) - - if (not major >= 7) or (major == 7 and minor == 0 and not update >= 4) : - mx.abort('Requires Java version 1.7.0_04 or greater, got version ' + version) +def mx_post_parse_cmd_line(opts):# + # TODO _minVersion check could probably be part of a Suite in mx? + if (mx.java().version < _minVersion) : + mx.abort('Requires Java version ' + str(_minVersion) + ' or greater, got version ' + str(mx.java().version)) if (_vmSourcesAvailable): if hasattr(opts, 'vm') and opts.vm is not None: @@ -1199,3 +1288,5 @@ _jacoco = opts.jacoco global _native_dbg _native_dbg = opts.native_dbg + + mx.distribution('GRAAL').add_update_listener(_installGraalJarInJdks) diff -r dee7c8b578c7 -r c3657d00e343 mx/eclipse-settings/org.eclipse.jdt.core.prefs --- a/mx/eclipse-settings/org.eclipse.jdt.core.prefs Thu Mar 21 11:30:38 2013 +0100 +++ b/mx/eclipse-settings/org.eclipse.jdt.core.prefs Thu Mar 21 14:11:13 2013 +0100 @@ -132,7 +132,7 @@ org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=48 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 @@ -140,7 +140,7 @@ org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 -org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=48 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 @@ -149,7 +149,7 @@ org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=48 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 diff -r dee7c8b578c7 -r c3657d00e343 mx/projects --- a/mx/projects Thu Mar 21 11:30:38 2013 +0100 +++ b/mx/projects Thu Mar 21 14:11:13 2013 +0100 @@ -22,6 +22,9 @@ library@DACAPO_SCALA@path=lib/dacapo-scala-0.1.0-20120216.jar library@DACAPO_SCALA@urls=http://repo.scalabench.org/snapshots/org/scalabench/benchmarks/scala-benchmark-suite/0.1.0-SNAPSHOT/scala-benchmark-suite-0.1.0-20120216.103539-3.jar +distribution@GRAAL@path=graal.jar +distribution@GRAAL@dependencies=com.oracle.graal.hotspot.amd64,com.oracle.graal.hotspot.sparc + # graal.api.runtime project@com.oracle.graal.api.runtime@subDir=graal project@com.oracle.graal.api.runtime@sourceDirs=src @@ -62,6 +65,13 @@ project@com.oracle.graal.amd64@checkstyle=com.oracle.graal.graph project@com.oracle.graal.amd64@javaCompliance=1.7 +# graal.ptx +project@com.oracle.graal.ptx@subDir=graal +project@com.oracle.graal.ptx@sourceDirs=src +project@com.oracle.graal.ptx@dependencies=com.oracle.graal.api.code +project@com.oracle.graal.ptx@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.ptx@javaCompliance=1.7 + # graal.sparc project@com.oracle.graal.sparc@subDir=graal project@com.oracle.graal.sparc@sourceDirs=src @@ -79,7 +89,7 @@ # graal.hotspot.amd64 project@com.oracle.graal.hotspot.amd64@subDir=graal project@com.oracle.graal.hotspot.amd64@sourceDirs=src -project@com.oracle.graal.hotspot.amd64@dependencies=com.oracle.graal.hotspot,com.oracle.graal.compiler.amd64 +project@com.oracle.graal.hotspot.amd64@dependencies=com.oracle.graal.hotspot,com.oracle.graal.compiler.amd64,com.oracle.graal.snippets.amd64 project@com.oracle.graal.hotspot.amd64@checkstyle=com.oracle.graal.graph project@com.oracle.graal.hotspot.amd64@javaCompliance=1.7 @@ -104,6 +114,13 @@ project@com.oracle.graal.hotspot.test@checkstyle=com.oracle.graal.graph project@com.oracle.graal.hotspot.test@javaCompliance=1.7 +# graal.hotspot.amd64.test +project@com.oracle.graal.hotspot.amd64.test@subDir=graal +project@com.oracle.graal.hotspot.amd64.test@sourceDirs=src +project@com.oracle.graal.hotspot.amd64.test@dependencies=com.oracle.graal.asm.amd64,com.oracle.graal.compiler.test +project@com.oracle.graal.hotspot.amd64.test@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.hotspot.amd64.test@javaCompliance=1.7 + # graal.graph project@com.oracle.graal.graph@subDir=graal project@com.oracle.graal.graph@sourceDirs=src @@ -137,6 +154,13 @@ project@com.oracle.graal.lir.amd64@checkstyle=com.oracle.graal.graph project@com.oracle.graal.lir.amd64@javaCompliance=1.7 +# graal.lir.ptx +project@com.oracle.graal.lir.ptx@subDir=graal +project@com.oracle.graal.lir.ptx@sourceDirs=src +project@com.oracle.graal.lir.ptx@dependencies=com.oracle.graal.asm.ptx,com.oracle.graal.lir +project@com.oracle.graal.lir.ptx@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.lir.ptx@javaCompliance=1.7 + # graal.lir.sparc project@com.oracle.graal.lir.sparc@subDir=graal project@com.oracle.graal.lir.sparc@sourceDirs=src @@ -165,6 +189,13 @@ project@com.oracle.graal.snippets@checkstyle=com.oracle.graal.graph project@com.oracle.graal.snippets@javaCompliance=1.7 +# graal.snippets.amd64 +project@com.oracle.graal.snippets.amd64@subDir=graal +project@com.oracle.graal.snippets.amd64@sourceDirs=src +project@com.oracle.graal.snippets.amd64@dependencies=com.oracle.graal.snippets +project@com.oracle.graal.snippets.amd64@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.snippets.amd64@javaCompliance=1.7 + # graal.snippets.test project@com.oracle.graal.snippets.test@subDir=graal project@com.oracle.graal.snippets.test@sourceDirs=src @@ -221,6 +252,27 @@ project@com.oracle.graal.compiler.amd64@checkstyle=com.oracle.graal.graph project@com.oracle.graal.compiler.amd64@javaCompliance=1.7 +# graal.compiler.amd64.test +project@com.oracle.graal.compiler.amd64.test@subDir=graal +project@com.oracle.graal.compiler.amd64.test@sourceDirs=src +project@com.oracle.graal.compiler.amd64.test@dependencies=com.oracle.graal.compiler.test +project@com.oracle.graal.compiler.amd64.test@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.compiler.amd64.test@javaCompliance=1.7 + +# graal.compiler.ptx +project@com.oracle.graal.compiler.ptx@subDir=graal +project@com.oracle.graal.compiler.ptx@sourceDirs=src +project@com.oracle.graal.compiler.ptx@dependencies=com.oracle.graal.compiler,com.oracle.graal.lir.ptx +project@com.oracle.graal.compiler.ptx@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.compiler.ptx@javaCompliance=1.7 + +# graal.compiler.ptx.test +project@com.oracle.graal.compiler.ptx.test@subDir=graal +project@com.oracle.graal.compiler.ptx.test@sourceDirs=src +project@com.oracle.graal.compiler.ptx.test@dependencies=com.oracle.graal.compiler.ptx,com.oracle.graal.compiler.test,com.oracle.graal.ptx +project@com.oracle.graal.compiler.ptx.test@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.compiler.ptx.test@javaCompliance=1.7 + # graal.compiler.sparc project@com.oracle.graal.compiler.sparc@subDir=graal project@com.oracle.graal.compiler.sparc@sourceDirs=src @@ -297,6 +349,13 @@ project@com.oracle.graal.asm.amd64.test@checkstyle=com.oracle.graal.graph project@com.oracle.graal.asm.amd64.test@javaCompliance=1.7 +# graal.asm.ptx +project@com.oracle.graal.asm.ptx@subDir=graal +project@com.oracle.graal.asm.ptx@sourceDirs=src +project@com.oracle.graal.asm.ptx@dependencies=com.oracle.graal.asm +project@com.oracle.graal.asm.ptx@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.asm.ptx@javaCompliance=1.7 + # graal.asm.sparc project@com.oracle.graal.asm.sparc@subDir=graal project@com.oracle.graal.asm.sparc@sourceDirs=src @@ -321,21 +380,29 @@ # truffle.api.codegen project@com.oracle.truffle.api.codegen@subDir=graal project@com.oracle.truffle.api.codegen@sourceDirs=src -project@com.oracle.truffle.api.codegen@dependencies= +project@com.oracle.truffle.api.codegen@dependencies=com.oracle.truffle.api project@com.oracle.truffle.api.codegen@checkstyle=com.oracle.graal.graph project@com.oracle.truffle.api.codegen@javaCompliance=1.7 +# truffle.api.codegen.test +project@com.oracle.truffle.api.codegen.test@subDir=graal +project@com.oracle.truffle.api.codegen.test@sourceDirs=src +project@com.oracle.truffle.api.codegen.test@dependencies=com.oracle.truffle.api.codegen,JUNIT +project@com.oracle.truffle.api.codegen.test@checkstyle=com.oracle.graal.graph +project@com.oracle.truffle.api.codegen.test@javaCompliance=1.7 +project@com.oracle.truffle.api.codegen.test@annotationProcessors=com.oracle.truffle.codegen.processor + # truffle.codegen.processor project@com.oracle.truffle.codegen.processor@subDir=graal project@com.oracle.truffle.codegen.processor@sourceDirs=src -project@com.oracle.truffle.codegen.processor@dependencies=com.oracle.truffle.api.codegen,com.oracle.truffle.api +project@com.oracle.truffle.codegen.processor@dependencies=com.oracle.truffle.api.codegen project@com.oracle.truffle.codegen.processor@checkstyle=com.oracle.graal.graph project@com.oracle.truffle.codegen.processor@javaCompliance=1.7 # truffle.sl project@com.oracle.truffle.sl@subDir=graal project@com.oracle.truffle.sl@sourceDirs=src -project@com.oracle.truffle.sl@dependencies=com.oracle.truffle.api.codegen,com.oracle.truffle.api +project@com.oracle.truffle.sl@dependencies=com.oracle.truffle.api.codegen project@com.oracle.truffle.sl@checkstyle=com.oracle.graal.graph project@com.oracle.truffle.sl@javaCompliance=1.7 project@com.oracle.truffle.sl@annotationProcessors=com.oracle.truffle.codegen.processor diff -r dee7c8b578c7 -r c3657d00e343 mx/sanitycheck.py --- a/mx/sanitycheck.py Thu Mar 21 11:30:38 2013 +0100 +++ b/mx/sanitycheck.py Thu Mar 21 14:11:13 2013 +0100 @@ -49,7 +49,7 @@ dacapoScalaSanityWarmup = { 'actors': [0, 0, 2, 8, 10], # (lstadler) apparat was disabled due to a deadlock which I think is the benchmarks fault. -# 'apparat': [0, 0, 1, 2, 3], + 'apparat': [0, 0, 0, 0, 0], 'factorie': [0, 0, 2, 5, 5], 'kiama': [0, 0, 3, 13, 15], 'scalac': [0, 0, 5, 15, 20], @@ -58,7 +58,8 @@ 'scalariform':[0, 0, 6, 15, 20], 'scalatest': [0, 0, 2, 10, 12], 'scalaxb': [0, 0, 5, 15, 25], - 'specs': [0, 0, 3, 13, 18], +#(gdub) specs sometimes returns a non-zero value event though there is no apparent failure + 'specs': [0, 0, 0, 0, 0], 'tmt': [0, 0, 3, 10, 12] } @@ -121,7 +122,7 @@ success = re.compile(r"org.spec.jbb.controller: Run finished", re.MULTILINE) matcherMax = ValuesMatcher(jops, {'group' : 'SPECjbb2013', 'name' : 'max', 'score' : ''}) matcherCritical = ValuesMatcher(jops, {'group' : 'SPECjbb2013', 'name' : 'critical', 'score' : ''}) - return Test("SPECjbb2013", ['-jar', 'specjbb2013.jar', '-m', 'composite'] + benchArgs, [success], [], [matcherCritical, matcherMax], vmOpts=['-Xms7g', '-XX:+'+gc, '-XX:-UseCompressedOops'], defaultCwd=specjbb2013) + return Test("SPECjbb2013", ['-jar', 'specjbb2013.jar', '-m', 'composite'] + benchArgs, [success], [], [matcherCritical, matcherMax], vmOpts=['-Xmx6g', '-Xms6g', '-Xmn3g', '-XX:+UseParallelOldGC', '-XX:-UseAdaptiveSizePolicy', '-XX:-UseBiasedLocking', '-XX:-UseCompressedOops'], defaultCwd=specjbb2013) def getSPECjvm2008(benchArgs = [], skipCheck=False, skipKitValidation=False, warmupTime=None, iterationTime=None): @@ -272,9 +273,12 @@ if len(valueMaps) == 0: return False - assert len(valueMaps) == 1, 'Test matchers should not return more than one record' - - record = valueMaps[0] + record = {} + for valueMap in valueMaps: + for key, value in valueMap.items(): + if record.has_key(key) and record[key] != value: + mx.abort('Inconsistant values returned by test machers : ' + str(valueMaps)) + record[key] = value jvmErrorFile = record.get('jvmError') if jvmErrorFile: diff -r dee7c8b578c7 -r c3657d00e343 mxtool/mx.py --- a/mxtool/mx.py Thu Mar 21 11:30:38 2013 +0100 +++ b/mxtool/mx.py Thu Mar 21 14:11:13 2013 +0100 @@ -143,12 +143,36 @@ _projects = dict() _libs = dict() +_dists = dict() _suites = dict() _mainSuite = None _opts = None _java = None """ +A distribution is a jar or zip file containing the output from one or more Java projects. +""" +class Distribution: + def __init__(self, suite, name, path, deps): + self.suite = suite + self.name = name + self.path = path.replace('/', os.sep) + if not isabs(self.path): + self.path = join(suite.dir, self.path) + self.deps = deps + self.update_listeners = set() + + def __str__(self): + return self.name + + def add_update_listener(self, listener): + self.update_listeners.add(listener) + + def notify_updated(self): + for l in self.update_listeners: + l(self) + +""" A dependency is a library or project specified in a suite. """ class Dependency: @@ -416,6 +440,7 @@ self.dir = d self.projects = [] self.libs = [] + self.dists = [] self.includes = [] self.commands = None self.primary = primary @@ -427,6 +452,7 @@ def _load_projects(self, mxDir): libsMap = dict() projsMap = dict() + distsMap = dict() projectsFile = join(mxDir, 'projects') if not exists(projectsFile): return @@ -447,8 +473,10 @@ m = projsMap elif kind == 'library': m = libsMap + elif kind == 'distribution': + m = distsMap else: - abort('Property name does not start with "project@" or "library@": ' + key) + abort('Property name does not start with "project@", "library@" or "distribution@": ' + key) attrs = m.get(name) if attrs is None: @@ -494,6 +522,13 @@ l.__dict__.update(attrs) self.libs.append(l) + for name, attrs in distsMap.iteritems(): + path = attrs.pop('path') + deps = pop_list(attrs, 'dependencies') + d = Distribution(self, name, path, deps) + d.__dict__.update(attrs) + self.dists.append(d) + def _load_commands(self, mxDir): commands = join(mxDir, 'commands.py') if exists(commands): @@ -536,8 +571,6 @@ def _post_init(self, opts): mxDir = join(self.dir, 'mx') self._load_projects(mxDir) - if hasattr(self, 'mx_post_parse_cmd_line'): - self.mx_post_parse_cmd_line(opts) for p in self.projects: existing = _projects.get(p.name) if existing is not None: @@ -549,6 +582,13 @@ if existing is not None: abort('cannot redefine library ' + l.name) _libs[l.name] = l + for d in self.dists: + existing = _dists.get(l.name) + if existing is not None: + abort('cannot redefine distribution ' + d.name) + _dists[d.name] = d + if hasattr(self, 'mx_post_parse_cmd_line'): + self.mx_post_parse_cmd_line(opts) class XMLElement(xml.dom.minidom.Element): def writexml(self, writer, indent="", addindent="", newl=""): @@ -590,6 +630,9 @@ e.ownerDocument = self return e + def comment(self, txt): + self.current.appendChild(self.createComment(txt)) + def open(self, tag, attributes={}, data=None): element = self.createElement(tag) for key, value in attributes.items(): @@ -653,6 +696,16 @@ """ return _projects.values() +def distribution(name, fatalIfMissing=True): + """ + Get the distribution for a given name. This will abort if the named distribution does + not exist and 'fatalIfMissing' is true. + """ + d = _dists.get(name) + if d is None and fatalIfMissing: + abort('distribution named ' + name + ' not found') + return d + def project(name, fatalIfMissing=True): """ Get the project for a given name. This will abort if the named project does @@ -1001,6 +1054,24 @@ other = JavaCompliance(other) return cmp(self.value, other.value) + +""" +A Java version as defined in JSR-56 +""" +class JavaVersion: + def __init__(self, versionString): + validChar = '[\x21-\x25\x27-\x29\x2c\x2f-\x5e\x60-\x7f]' + separator = '[.\-_]' + m = re.match(validChar + '+(' + separator + validChar + '+)*', versionString) + assert m is not None, 'not a recognized version string: ' + versionString + self.versionString = versionString; + self.parts = [int(f) if f.isdigit() else f for f in re.split(separator, versionString)] + + def __str__(self): + return self.versionString + + def __cmp__(self, other): + return cmp(self.parts, other.parts) """ A JavaConfig object encapsulates info on how Java commands are run. @@ -1039,8 +1110,8 @@ output = output.split() assert output[1] == 'version' - self.version = output[2].strip('"') - self.javaCompliance = JavaCompliance(self.version) + self.version = JavaVersion(output[2].strip('"')) + self.javaCompliance = JavaCompliance(self.version.versionString) if self.debug_port is not None: self.java_args += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(self.debug_port)] @@ -1459,6 +1530,9 @@ finally: for n in toBeDeleted: os.remove(n) + + for dist in _dists.values(): + archive(['@' + dist.name]) if suppliedParser: return args @@ -1557,59 +1631,59 @@ return 0 def processorjars(): - projects = set([]) + projects = set() for p in sorted_deps(): - if _needsEclipseJarBuild(p): + if _isAnnotationProcessorDependency(p): projects.add(p) if len(projects) <= 0: return - build(['--projects', ",".join(map(lambda p: p.name, projects))]) - - for p in projects: - targetJar = join(p.dir, p.name + '.jar') - jar(targetJar, [p.output_dir()]) - - -def jar(destFileName, dirs): - latestMod = _latestModification(dirs) - - if exists(destFileName): - mod = os.path.getmtime(destFileName) - if int(round(latestMod*1000)) == int(round(mod*1000)): - # nothing todo - return - - if latestMod is None and exists(destFileName): - return - - jarCmd = [java().jar, 'cf', destFileName] + pnames = [p.name for p in projects] + build(['--projects', ",".join(pnames)]) + archive(pnames) + +def archive(args): + """create jar files for projects and distributions""" + parser = ArgumentParser(prog='mx archive'); + parser.add_argument('names', nargs=REMAINDER, metavar='[|@]...') + args = parser.parse_args(args) - for directory in dirs: - jarCmd += ['-C', directory, '.'] - - subprocess.check_call(jarCmd) - log('Written jar file {0}'.format(destFileName)) - - atime = os.path.getatime(destFileName) - os.utime(destFileName, (atime, latestMod)) - -def _latestModification(directories): - latestMod = None - for directory in directories: - if not os.path.exists (directory): - continue - for root, _, files in os.walk(directory): - for names in files: - filepath = os.path.join(root, names) - mod = os.path.getmtime(filepath) - if latestMod is None: - latestMod = mod - elif mod > latestMod: - latestMod = mod - return latestMod + for name in args.names: + if name.startswith('@'): + dname = name[1:] + d = distribution(dname) + fd, tmp = tempfile.mkstemp(suffix='', prefix=basename(d.path) + '.', dir=dirname(d.path)) + zf = zipfile.ZipFile(tmp, 'w') + for p in sorted_deps(d.deps): + outputDir = p.output_dir() + for root, _, files in os.walk(outputDir): + for f in files: + relpath = root[len(outputDir) + 1:] + arcname = join(relpath, f).replace(os.sep, '/') + zf.write(join(root, f), arcname) + zf.close() + os.close(fd) + # Atomic on Unix + shutil.move(tmp, d.path) + #print time.time(), 'move:', tmp, '->', d.path + d.notify_updated() + + else: + p = project(name) + outputDir = p.output_dir() + fd, tmp = tempfile.mkstemp(suffix='', prefix=p.name, dir=p.dir) + zf = zipfile.ZipFile(tmp, 'w') + for root, _, files in os.walk(outputDir): + for f in files: + relpath = root[len(outputDir) + 1:] + arcname = join(relpath, f).replace(os.sep, '/') + zf.write(join(root, f), arcname) + zf.close() + os.close(fd) + # Atomic on Unix + shutil.move(tmp, join(p.dir, p.name + '.jar')) def canonicalizeprojects(args): """process all project files to canonicalize the dependencies @@ -1989,6 +2063,12 @@ if buildProcessorJars: processorjars() + projToDist = dict() + for dist in _dists.values(): + distDeps = sorted_deps(dist.deps) + for p in distDeps: + projToDist[p.name] = (dist, [dep.name for dep in distDeps]) + for p in projects(): if p.native: continue @@ -2103,24 +2183,14 @@ out.element('arguments', data='') out.close('buildCommand') - if (_needsEclipseJarBuild(p)): - targetValues = _genEclipseJarBuild(p); - for value in targetValues: - out.open('buildCommand') - out.element('name', data='org.eclipse.ui.externaltools.ExternalToolBuilder') - out.element('triggers', data='auto,full,incremental,') - out.open('arguments') - out.open('dictionary') - out.element('key', data = 'LaunchConfigHandle') - out.element('value', data = value) - out.close('dictionary') - out.open('dictionary') - out.element('key', data = 'incclean') - out.element('value', data = 'true') - out.close('dictionary') - out.close('arguments') - out.close('buildCommand') - + if _isAnnotationProcessorDependency(p): + _genEclipseBuilder(out, p, 'Jar.launch', 'archive ' + p.name, refresh = False, async = False) + _genEclipseBuilder(out, p, 'Refresh.launch', '', refresh = True, async = True) + + if projToDist.has_key(p.name): + dist, distDeps = projToDist[p.name] + _genEclipseBuilder(out, p, 'Create' + dist.name + 'Dist.launch', 'archive @' + dist.name, refresh=False, async=True) + out.close('buildSpec') out.open('natures') out.element('nature', data='org.eclipse.jdt.core.javanature') @@ -2175,8 +2245,11 @@ make_eclipse_attach('localhost', '8000', deps=projects()) -def _needsEclipseJarBuild(p): - processors = set([]) +def _isAnnotationProcessorDependency(p): + """ + Determines if a given project is part of an annotation processor. + """ + processors = set() for otherProject in projects(): if hasattr(otherProject, 'annotationProcessors') and len(otherProject.annotationProcessors) > 0: @@ -2193,19 +2266,18 @@ return False -def _genEclipseJarBuild(p): - builders = [] - builders.append(_genEclipseLaunch(p, 'Jar.launch', ''.join(['jar ', p.name]), refresh = False, async = False)) - builders.append(_genEclipseLaunch(p, 'Refresh.launch', '', refresh = True, async = True)) - return builders - -def _genEclipseLaunch(p, name, mxCommand, refresh=True, async=False): +def _genEclipseBuilder(dotProjectDoc, p, name, mxCommand, refresh=True, async=False, logToConsole=False): launchOut = XMLDoc(); + consoleOn = 'true' if logToConsole else 'false' launchOut.open('launchConfiguration', {'type' : 'org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType'}) + launchOut.open('mapAttribute', {'key' : 'org.eclipse.debug.core.environmentVariables'}) + launchOut.element('mapEntry', {'key' : 'JAVA_HOME', 'value' : java().jdk}) + launchOut.close('mapAttribute') + if refresh: launchOut.element('stringAttribute', {'key' : 'org.eclipse.debug.core.ATTR_REFRESH_SCOPE', 'value': '${project}'}) - launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.core.capture_output', 'value': 'false'}) - launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.ui.ATTR_CONSOLE_OUTPUT_ON', 'value': 'false'}) + 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'}) @@ -2229,9 +2301,21 @@ os.makedirs(externalToolDir) update_file(join(externalToolDir, name), launchOut.xml(indent='\t', newl='\n')) - return ''.join(["/.externalToolBuilders/", name]) - - + dotProjectDoc.open('buildCommand') + dotProjectDoc.element('name', data='org.eclipse.ui.externaltools.ExternalToolBuilder') + dotProjectDoc.element('triggers', data='auto,full,incremental,') + dotProjectDoc.open('arguments') + dotProjectDoc.open('dictionary') + dotProjectDoc.element('key', data = 'LaunchConfigHandle') + dotProjectDoc.element('value', data = '/.externalToolBuilders/' + name) + dotProjectDoc.close('dictionary') + dotProjectDoc.open('dictionary') + dotProjectDoc.element('key', data = 'incclean') + dotProjectDoc.element('value', data = 'true') + dotProjectDoc.close('dictionary') + dotProjectDoc.close('arguments') + dotProjectDoc.close('buildCommand') + def netbeansinit(args, suite=None): """(re)generate NetBeans project configurations""" @@ -2256,6 +2340,14 @@ out.open('project', {'name' : p.name, 'default' : 'default', 'basedir' : '.'}) out.element('description', data='Builds, tests, and runs the project ' + p.name + '.') out.element('import', {'file' : 'nbproject/build-impl.xml'}) + out.open('target', {'name' : '-post-compile'}) + out.open('exec', { 'executable' : sys.executable}) + out.element('env', {'key' : 'JAVA_HOME', 'value' : java().jdk}) + out.element('arg', {'value' : os.path.abspath(__file__)}) + out.element('arg', {'value' : 'archive'}) + out.element('arg', {'value' : '@GRAAL'}) + out.close('exec') + out.close('target') out.close('project') updated = update_file(join(p.dir, 'build.xml'), out.xml(indent='\t', newl='\n')) or updated @@ -2303,7 +2395,7 @@ updated = update_file(join(p.dir, 'nbproject', 'project.xml'), out.xml(indent=' ', newl='\n')) or updated out = StringIO.StringIO() - jdkPlatform = 'JDK_' + java().version + jdkPlatform = 'JDK_' + str(java().version) annotationProcessorEnabled = "false" annotationProcessorReferences = "" @@ -2444,7 +2536,7 @@ if updated: log('If using NetBeans:') - log(' 1. Ensure that a platform named "JDK ' + java().version + '" is defined (Tools -> Java Platforms)') + log(' 1. Ensure that a platform named "JDK_' + str(java().version) + '" is defined (Tools -> Java Platforms)') log(' 2. Open/create a Project Group for the directory containing the projects (File -> Project Group -> New Group... -> Folder of Projects)') def ideclean(args, suite=None): @@ -2474,6 +2566,24 @@ """(re)generate Eclipse and NetBeans project configurations""" eclipseinit(args, suite) netbeansinit(args, suite) + fsckprojects([]) + +def fsckprojects(args): + """find directories corresponding to deleted Java projects and delete them""" + for suite in suites(): + projectDirs = [p.dir for p in suite.projects] + for root, dirnames, files in os.walk(suite.dir): + currentDir = join(suite.dir, root) + if currentDir in projectDirs: + # don't traverse subdirs of an existing project + dirnames[:] = [] + else: + projectConfigFiles = frozenset(['.classpath', 'nbproject']) + indicators = projectConfigFiles.intersection(files) + if len(indicators) != 0: + if not sys.stdout.isatty() or raw_input(currentDir + ' looks like a removed project -- delete it? [yn]: ') == 'y': + shutil.rmtree(currentDir) + log('Deleted ' + currentDir) def javadoc(args, parser=None, docDir='javadoc', includeDeps=True): """generate javadoc for some/all Java projects""" @@ -2926,9 +3036,11 @@ 'eclipseinit': [eclipseinit, ''], 'eclipseformat': [eclipseformat, ''], 'findclass': [findclass, ''], + 'fsckprojects': [fsckprojects, ''], 'help': [help_, '[command]'], 'ideclean': [ideclean, ''], 'ideinit': [ideinit, ''], + 'archive': [archive, '[options]'], 'projectgraph': [projectgraph, ''], 'javap': [javap, ''], 'javadoc': [javadoc, '[options]'], diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp --- a/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -30,10 +30,11 @@ #include "c1/c1_Runtime1.hpp" #include "nativeInst_sparc.hpp" #include "runtime/sharedRuntime.hpp" +#include "utilities/macros.hpp" #include "vmreg_sparc.inline.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" -#endif +#endif // INCLUDE_ALL_GCS #define __ ce->masm()-> @@ -420,7 +421,7 @@ /////////////////////////////////////////////////////////////////////////////////// -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { // At this point we know that marking is in progress. @@ -483,7 +484,7 @@ __ delayed()->nop(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS /////////////////////////////////////////////////////////////////////////////////// #undef __ diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/sparc/vm/c1_Runtime1_sparc.cpp --- a/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -35,6 +35,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/vframeArray.hpp" +#include "utilities/macros.hpp" #include "vmreg_sparc.inline.hpp" // Implementation of StubAssembler @@ -822,7 +823,7 @@ } break; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case g1_pre_barrier_slow_id: { // G4: previous value of memory BarrierSet* bs = Universe::heap()->barrier_set(); @@ -984,7 +985,7 @@ __ delayed()->restore(); } break; -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS default: { __ set_info("unimplemented entry", dont_gc_arguments); diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/sparc/vm/c2_globals_sparc.hpp --- a/src/cpu/sparc/vm/c2_globals_sparc.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/sparc/vm/c2_globals_sparc.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -43,7 +43,7 @@ #else define_pd_global(bool, ProfileInterpreter, true); #endif // CC_INTERP -define_pd_global(bool, TieredCompilation, trueInTiered); +define_pd_global(bool, TieredCompilation, false); define_pd_global(intx, CompileThreshold, 10000); define_pd_global(intx, BackEdgeThreshold, 140000); diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/sparc/vm/cppInterpreter_sparc.cpp --- a/src/cpu/sparc/vm/cppInterpreter_sparc.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/sparc/vm/cppInterpreter_sparc.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -45,6 +45,7 @@ #include "runtime/timer.hpp" #include "runtime/vframeArray.hpp" #include "utilities/debug.hpp" +#include "utilities/macros.hpp" #ifdef SHARK #include "shark/shark_globals.hpp" #endif @@ -551,7 +552,7 @@ } address InterpreterGenerator::generate_Reference_get_entry(void) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseG1GC) { // We need to generate have a routine that generates code to: // * load the value in the referent field @@ -563,7 +564,7 @@ // field as live. Unimplemented(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/sparc/vm/frame_sparc.cpp --- a/src/cpu/sparc/vm/frame_sparc.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/sparc/vm/frame_sparc.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -216,6 +216,11 @@ } } + // Could just be some random pointer within the codeBlob + if (!_cb->code_contains(_pc)) { + return false; + } + // Entry frame checks if (is_entry_frame()) { // an entry frame must have a valid fp. diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/sparc/vm/frame_sparc.inline.hpp --- a/src/cpu/sparc/vm/frame_sparc.inline.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/sparc/vm/frame_sparc.inline.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -74,8 +74,7 @@ // return address: -inline address* frame::sender_pc_addr() const { return (address*) (I7_addr() + pc_return_offset); } -inline address frame::sender_pc() const { return *sender_pc_addr(); } +inline address frame::sender_pc() const { return *I7_addr() + pc_return_offset; } inline address* frame::I7_addr() const { return (address*) &sp()[ I7->sp_offset_in_saved_window()]; } inline address* frame::I0_addr() const { return (address*) &sp()[ I0->sp_offset_in_saved_window()]; } diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/sparc/vm/jniTypes_sparc.hpp --- a/src/cpu/sparc/vm/jniTypes_sparc.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/sparc/vm/jniTypes_sparc.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -112,25 +112,6 @@ return *(jdouble *)&jl; } #endif - static inline jint get_int (intptr_t *from, int& pos) { - return get_int(from + pos++); - } - static inline jlong get_long (intptr_t *from, int& pos) { - jlong result = get_long(from + pos); - pos += 2; - return result; - } - static inline oop get_obj (intptr_t *from, int& pos) { - return get_obj(from + pos++); - } - static inline jfloat get_float (intptr_t *from, int& pos) { - return get_float(from + pos++); - } - static inline jdouble get_double(intptr_t *from, int& pos) { - jdouble result = get_double(from + pos); - pos += 2; - return result; - } }; #endif // CPU_SPARC_VM_JNITYPES_SPARC_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/sparc/vm/macroAssembler_sparc.cpp --- a/src/cpu/sparc/vm/macroAssembler_sparc.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/sparc/vm/macroAssembler_sparc.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -36,11 +36,12 @@ #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/heapRegion.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ @@ -3867,7 +3868,7 @@ } /////////////////////////////////////////////////////////////////////////////////// -#ifndef SERIALGC +#if INCLUDE_ALL_GCS static address satb_log_enqueue_with_frame = NULL; static u_char* satb_log_enqueue_with_frame_end = NULL; @@ -4231,7 +4232,7 @@ bind(filtered); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS /////////////////////////////////////////////////////////////////////////////////// void MacroAssembler::card_write_barrier_post(Register store_addr, Register new_val, Register tmp) { diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/sparc/vm/macroAssembler_sparc.hpp --- a/src/cpu/sparc/vm/macroAssembler_sparc.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/sparc/vm/macroAssembler_sparc.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -26,6 +26,7 @@ #define CPU_SPARC_VM_MACROASSEMBLER_SPARC_HPP #include "asm/assembler.hpp" +#include "utilities/macros.hpp" // promises that the system will not use traps 16-31 #define ST_RESERVED_FOR_USER_0 0x10 @@ -1181,13 +1182,13 @@ void card_write_barrier_post(Register store_addr, Register new_val, Register tmp); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // General G1 pre-barrier generator. void g1_write_barrier_pre(Register obj, Register index, int offset, Register pre_val, Register tmp, bool preserve_o_regs); // General G1 post-barrier generator void g1_write_barrier_post(Register store_addr, Register new_val, Register tmp); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // pushes double TOS element of FPU stack on CPU stack; pops from FPU stack void push_fTOS(); diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/sparc/vm/templateInterpreter_sparc.cpp --- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -44,6 +44,7 @@ #include "runtime/timer.hpp" #include "runtime/vframeArray.hpp" #include "utilities/debug.hpp" +#include "utilities/macros.hpp" #ifndef CC_INTERP #ifndef FAST_DISPATCH @@ -734,7 +735,7 @@ // Method entry for java.lang.ref.Reference.get. address InterpreterGenerator::generate_Reference_get_entry(void) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Code: _aload_0, _getfield, _areturn // parameter size = 1 // @@ -805,7 +806,7 @@ (void) generate_normal_entry(false); return entry; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/sparc/vm/templateTable_sparc.cpp --- a/src/cpu/sparc/vm/templateTable_sparc.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/sparc/vm/templateTable_sparc.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/synchronizer.hpp" +#include "utilities/macros.hpp" #ifndef CC_INTERP #define __ _masm-> @@ -53,7 +54,7 @@ assert(tmp != val && tmp != base && tmp != index, "register collision"); assert(index == noreg || offset == 0, "only one offset"); switch (barrier) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case BarrierSet::G1SATBCT: case BarrierSet::G1SATBCTLogging: { @@ -82,7 +83,7 @@ } } break; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS case BarrierSet::CardTableModRef: case BarrierSet::CardTableExtension: { @@ -339,8 +340,6 @@ __ bind(notInt); // __ cmp(O2, JVM_CONSTANT_String); - __ brx(Assembler::equal, true, Assembler::pt, isString); - __ delayed()->cmp(O2, JVM_CONSTANT_Object); __ brx(Assembler::notEqual, true, Assembler::pt, notString); __ delayed()->ldf(FloatRegisterImpl::S, O0, O1, Ftos_f); __ bind(isString); diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/assembler_x86.cpp --- a/src/cpu/x86/vm/assembler_x86.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/assembler_x86.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -36,11 +36,12 @@ #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/heapRegion.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ @@ -2269,10 +2270,11 @@ } void Assembler::vpermq(XMMRegister dst, XMMRegister src, int imm8, bool vector256) { - int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, true, vector256); - emit_int8(0x00); - emit_int8(0xC0 | encode); - emit_int8(imm8); + assert(VM_Version::supports_avx2(), ""); + int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, true, vector256); + emit_int8(0x00); + emit_int8(0xC0 | encode); + emit_int8(imm8); } void Assembler::pcmpestri(XMMRegister dst, Address src, int imm8) { diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/assembler_x86.hpp --- a/src/cpu/x86/vm/assembler_x86.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/assembler_x86.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -543,7 +543,7 @@ // of instructions are freely declared without the need for wrapping them an ifdef. // (Some dangerous instructions are ifdef's out of inappropriate jvm's.) // In the .cpp file the implementations are wrapped so that they are dropped out - // of the resulting jvm. This is done mostly to keep the footprint of KERNEL + // of the resulting jvm. This is done mostly to keep the footprint of MINIMAL // to the size it was prior to merging up the 32bit and 64bit assemblers. // // This does mean you'll get a linker/runtime error if you use a 64bit only instruction diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/c1_CodeStubs_x86.cpp --- a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -30,10 +30,11 @@ #include "c1/c1_Runtime1.hpp" #include "nativeInst_x86.hpp" #include "runtime/sharedRuntime.hpp" +#include "utilities/macros.hpp" #include "vmreg_x86.inline.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" -#endif +#endif // INCLUDE_ALL_GCS #define __ ce->masm()-> @@ -482,7 +483,7 @@ } ///////////////////////////////////////////////////////////////////////////// -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { // At this point we know that marking is in progress. @@ -528,7 +529,7 @@ __ jmp(_continuation); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS ///////////////////////////////////////////////////////////////////////////// #undef __ diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/c1_Runtime1_x86.cpp --- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -36,6 +36,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/vframeArray.hpp" +#include "utilities/macros.hpp" #include "vmreg_x86.inline.hpp" @@ -1607,7 +1608,7 @@ } break; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case g1_pre_barrier_slow_id: { StubFrame f(sasm, "g1_pre_barrier", dont_gc_arguments); @@ -1804,7 +1805,7 @@ } break; -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS default: { StubFrame f(sasm, "unimplemented entry", dont_gc_arguments); diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/c2_globals_x86.hpp --- a/src/cpu/x86/vm/c2_globals_x86.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/c2_globals_x86.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -45,7 +45,7 @@ #else define_pd_global(bool, ProfileInterpreter, true); #endif // CC_INTERP -define_pd_global(bool, TieredCompilation, trueInTiered); +define_pd_global(bool, TieredCompilation, false); define_pd_global(intx, CompileThreshold, 10000); define_pd_global(intx, BackEdgeThreshold, 100000); diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/cppInterpreter_x86.cpp --- a/src/cpu/x86/vm/cppInterpreter_x86.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/cppInterpreter_x86.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -45,6 +45,7 @@ #include "runtime/timer.hpp" #include "runtime/vframeArray.hpp" #include "utilities/debug.hpp" +#include "utilities/macros.hpp" #ifdef SHARK #include "shark/shark_globals.hpp" #endif @@ -938,7 +939,7 @@ } address InterpreterGenerator::generate_Reference_get_entry(void) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseG1GC) { // We need to generate have a routine that generates code to: // * load the value in the referent field @@ -950,7 +951,7 @@ // field as live. Unimplemented(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/frame_x86.cpp --- a/src/cpu/x86/vm/frame_x86.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/frame_x86.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -91,6 +91,12 @@ return false; } } + + // Could just be some random pointer within the codeBlob + if (!_cb->code_contains(_pc)) { + return false; + } + // Entry frame checks if (is_entry_frame()) { // an entry frame must have a valid fp. @@ -302,11 +308,6 @@ ptr_at_put(interpreter_frame_sender_sp_offset, (intptr_t) sender_sp); } -intptr_t** frame::interpreter_frame_sender_sp_addr() const { - assert(is_interpreted_frame(), "interpreted frame expected"); - return (intptr_t**) addr_at(interpreter_frame_sender_sp_offset); -} - // monitor elements diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/frame_x86.hpp --- a/src/cpu/x86/vm/frame_x86.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/frame_x86.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -191,12 +191,13 @@ // Note: not necessarily the real 'frame pointer' (see real_fp) intptr_t* fp() const { return _fp; } + inline address* sender_pc_addr() const; + // return address of param, zero origin index. inline address* native_param_addr(int idx) const; // expression stack tos if we are nested in a java call intptr_t* interpreter_frame_last_sp() const; - intptr_t** interpreter_frame_last_sp_addr() const; // helper to update a map with callee-saved RBP static void update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr); diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/frame_x86.inline.hpp --- a/src/cpu/x86/vm/frame_x86.inline.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/frame_x86.inline.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -133,9 +133,8 @@ -inline intptr_t* frame::link() const { return (intptr_t*) *(intptr_t **)addr_at(link_offset); } -inline intptr_t** frame::link_addr() const { return (intptr_t **)addr_at(link_offset); } -inline void frame::set_link(intptr_t* addr) { *(intptr_t **)addr_at(link_offset) = addr; } +inline intptr_t* frame::link() const { return (intptr_t*) *(intptr_t **)addr_at(link_offset); } +inline void frame::set_link(intptr_t* addr) { *(intptr_t **)addr_at(link_offset) = addr; } inline intptr_t* frame::unextended_sp() const { return _unextended_sp; } @@ -211,10 +210,6 @@ return *(intptr_t**)addr_at(interpreter_frame_last_sp_offset); } -inline intptr_t** frame::interpreter_frame_last_sp_addr() const { - return (intptr_t**)addr_at(interpreter_frame_last_sp_offset); -} - inline intptr_t* frame::interpreter_frame_bcx_addr() const { return (intptr_t*)addr_at(interpreter_frame_bcx_offset); } diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/graalRuntime_x86.cpp --- a/src/cpu/x86/vm/graalRuntime_x86.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/graalRuntime_x86.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -46,12 +46,6 @@ assert(!(oop_result1->is_valid() || metadata_result->is_valid()) || oop_result1 != metadata_result, "registers must be different"); assert(oop_result1 != thread && metadata_result != thread, "registers must be different"); assert(args_size >= 0, "illegal args_size"); - bool align_stack = false; -#ifdef _LP64 - // At a method handle call, the stack may not be properly aligned - // when returning with an exception. - align_stack = (stub_id() == false /*GraalRuntime::handle_exception_from_callee_id*/); -#endif #ifdef _LP64 mov(c_rarg0, thread); @@ -65,20 +59,11 @@ #endif // _LP64 int call_offset; - if (!align_stack) { - set_last_Java_frame(thread, noreg, rbp, NULL); - } else { - address the_pc = pc(); - call_offset = offset(); - set_last_Java_frame(thread, noreg, rbp, the_pc); - andptr(rsp, -(StackAlignmentInBytes)); // Align stack - } + set_last_Java_frame(thread, rsp, noreg, NULL); // do the call call(RuntimeAddress(entry)); - if (!align_stack) { - call_offset = offset(); - } + call_offset = offset(); // verify callee-saved register #ifdef ASSERT guarantee(thread != rax, "change this code"); @@ -93,7 +78,7 @@ } pop(rax); #endif - reset_last_Java_frame(thread, true, align_stack); + reset_last_Java_frame(thread, true, false); // discard thread and arguments NOT_LP64(addptr(rsp, num_rt_args()*BytesPerWord)); @@ -115,7 +100,7 @@ restore_live_registers(this, false); movptr(Address(thread, Thread::pending_exception_offset()), NULL_WORD); leave(); - movl(rscratch1, Deoptimization::make_trap_request(Deoptimization::Reason_constraint, Deoptimization::Action_reinterpret)); + movl(Address(thread, ThreadShadow::pending_deoptimization_offset()), Deoptimization::make_trap_request(Deoptimization::Reason_constraint, Deoptimization::Action_reinterpret)); jump(RuntimeAddress(SharedRuntime::deopt_blob()->uncommon_trap())); bind(L); } @@ -356,6 +341,7 @@ map->set_callee_saved(VMRegImpl::stack2reg(rcx_off + num_rt_args), rcx->as_VMReg()); map->set_callee_saved(VMRegImpl::stack2reg(rdx_off + num_rt_args), rdx->as_VMReg()); map->set_callee_saved(VMRegImpl::stack2reg(rbx_off + num_rt_args), rbx->as_VMReg()); + map->set_callee_saved(VMRegImpl::stack2reg(rbp_off + num_rt_args), rbp->as_VMReg()); map->set_callee_saved(VMRegImpl::stack2reg(rsi_off + num_rt_args), rsi->as_VMReg()); map->set_callee_saved(VMRegImpl::stack2reg(rdi_off + num_rt_args), rdi->as_VMReg()); #ifdef _LP64 @@ -373,6 +359,7 @@ map->set_callee_saved(VMRegImpl::stack2reg(rcxH_off + num_rt_args), rcx->as_VMReg()->next()); map->set_callee_saved(VMRegImpl::stack2reg(rdxH_off + num_rt_args), rdx->as_VMReg()->next()); map->set_callee_saved(VMRegImpl::stack2reg(rbxH_off + num_rt_args), rbx->as_VMReg()->next()); + map->set_callee_saved(VMRegImpl::stack2reg(rbpH_off + num_rt_args), rbp->as_VMReg()->next()); map->set_callee_saved(VMRegImpl::stack2reg(rsiH_off + num_rt_args), rsi->as_VMReg()->next()); map->set_callee_saved(VMRegImpl::stack2reg(rdiH_off + num_rt_args), rdi->as_VMReg()->next()); @@ -638,9 +625,9 @@ OopMapSet* oop_maps = new OopMapSet(); OopMap* oop_map = NULL; switch (id) { - case graal_handle_exception_nofpu_id: + case handle_exception_nofpu_id: // At this point all registers MAY be live. - oop_map = save_live_registers(sasm, 1 /*thread*/, id == graal_handle_exception_nofpu_id); + oop_map = save_live_registers(sasm, 1 /*thread*/, id == handle_exception_nofpu_id); break; default: ShouldNotReachHere(); } @@ -712,9 +699,9 @@ __ movptr(Address(rbp, 1*BytesPerWord), rax); switch (id) { - case graal_handle_exception_nofpu_id: + case handle_exception_nofpu_id: // Restore the registers that were saved at the beginning. - restore_live_registers(sasm, id == graal_handle_exception_nofpu_id); + restore_live_registers(sasm, id == handle_exception_nofpu_id); break; default: ShouldNotReachHere(); } @@ -824,7 +811,7 @@ OopMapSet* oop_maps = NULL; switch (id) { - case graal_new_instance_id: + case new_instance_id: { Register klass = rdx; // Incoming Register obj = rax; // Result @@ -844,7 +831,7 @@ break; - case graal_new_array_id: + case new_array_id: { Register length = rbx; // Incoming Register klass = rdx; // Incoming @@ -869,7 +856,7 @@ } break; - case graal_new_multi_array_id: + case new_multi_array_id: { GraalStubFrame f(sasm, "new_multi_array", dont_gc_arguments); // rax,: klass // rbx,: rank @@ -886,7 +873,7 @@ } break; - case graal_register_finalizer_id: + case register_finalizer_id: { __ set_info("register_finalizer", dont_gc_arguments); @@ -927,88 +914,16 @@ } break; - case graal_handle_exception_nofpu_id: + case handle_exception_nofpu_id: { GraalStubFrame f(sasm, "handle_exception", dont_gc_arguments); oop_maps = generate_handle_exception(id, sasm); } break; - case graal_slow_subtype_check_id: - { - // Typical calling sequence: - // __ push(klass_RInfo); // object klass or other subclass - // __ push(sup_k_RInfo); // array element klass or other superclass - // __ call(slow_subtype_check); - // Note that the subclass is pushed first, and is therefore deepest. - // Previous versions of this code reversed the names 'sub' and 'super'. - // This was operationally harmless but made the code unreadable. - enum layout { - rax_off, SLOT2(raxH_off) - rcx_off, SLOT2(rcxH_off) - rsi_off, SLOT2(rsiH_off) - rdi_off, SLOT2(rdiH_off) - // saved_rbp_off, SLOT2(saved_rbpH_off) - return_off, SLOT2(returnH_off) - sup_k_off, SLOT2(sup_kH_off) - klass_off, SLOT2(superH_off) - framesize, - result_off = klass_off // deepest argument is also the return value - }; - - __ set_info("slow_subtype_check", dont_gc_arguments); - __ push(rdi); - __ push(rsi); - __ push(rcx); - __ push(rax); - - // This is called by pushing args and not with C abi - __ movptr(rsi, Address(rsp, (klass_off) * VMRegImpl::stack_slot_size)); // subclass - __ movptr(rax, Address(rsp, (sup_k_off) * VMRegImpl::stack_slot_size)); // superclass - - Label miss; - Label success; - __ check_klass_subtype_fast_path(rsi, rax, rcx, &success, &miss, NULL); - - __ check_klass_subtype_slow_path(rsi, rax, rcx, rdi, NULL, &miss); - - // fallthrough on success: - __ bind(success); - __ movptr(Address(rsp, (result_off) * VMRegImpl::stack_slot_size), 1); // result - __ pop(rax); - __ pop(rcx); - __ pop(rsi); - __ pop(rdi); - __ ret(0); - - __ bind(miss); - __ movptr(Address(rsp, (result_off) * VMRegImpl::stack_slot_size), NULL_WORD); // result - __ pop(rax); - __ pop(rcx); - __ pop(rsi); - __ pop(rdi); - __ ret(0); - } - break; - - case graal_unwind_exception_call_id: { + case unwind_exception_call_id: { // remove the frame from the stack __ movptr(rsp, rbp); __ pop(rbp); - // exception_oop is passed using ordinary java calling conventions - __ movptr(rax, j_rarg0); - - Label nonNullExceptionOop; - __ testptr(rax, rax); - __ jcc(Assembler::notZero, nonNullExceptionOop); - { - __ enter(); - oop_maps = new OopMapSet(); - OopMap* oop_map = save_live_registers(sasm, 0); - int call_offset = __ call_RT(rax, noreg, (address)graal_create_null_exception, 0); - oop_maps->add_gc_map(call_offset, oop_map); - __ leave(); - } - __ bind(nonNullExceptionOop); __ set_info("unwind_exception", dont_gc_arguments); // note: no stubframe since we are about to leave the current @@ -1018,7 +933,7 @@ break; } - case graal_OSR_migration_end_id: { + case OSR_migration_end_id: { __ enter(); save_live_registers(sasm, 0); __ movptr(c_rarg0, j_rarg0); @@ -1029,39 +944,33 @@ break; } - case graal_set_deopt_info_id: { - __ movptr(Address(r15_thread, JavaThread::graal_deopt_info_offset()), rscratch1); - __ ret(0); - break; - } - - case graal_create_null_pointer_exception_id: { + case create_null_pointer_exception_id: { __ enter(); oop_maps = new OopMapSet(); OopMap* oop_map = save_live_registers(sasm, 0); - int call_offset = __ call_RT(rax, noreg, (address)graal_create_null_exception, 0); + int call_offset = __ call_RT(rax, noreg, (address)create_null_exception, 0); oop_maps->add_gc_map(call_offset, oop_map); __ leave(); __ ret(0); break; } - case graal_create_out_of_bounds_exception_id: { + case create_out_of_bounds_exception_id: { __ enter(); oop_maps = new OopMapSet(); OopMap* oop_map = save_live_registers(sasm, 0); - int call_offset = __ call_RT(rax, noreg, (address)graal_create_out_of_bounds_exception, j_rarg0); + int call_offset = __ call_RT(rax, noreg, (address)create_out_of_bounds_exception, j_rarg0); oop_maps->add_gc_map(call_offset, oop_map); __ leave(); __ ret(0); break; } - case graal_vm_error_id: { + case vm_error_id: { __ enter(); oop_maps = new OopMapSet(); OopMap* oop_map = save_live_registers(sasm, 0); - int call_offset = __ call_RT(noreg, noreg, (address)graal_vm_error, j_rarg0, j_rarg1, j_rarg2); + 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); __ leave(); @@ -1069,11 +978,11 @@ break; } - case graal_log_printf_id: { + case log_printf_id: { __ enter(); oop_maps = new OopMapSet(); OopMap* oop_map = save_live_registers(sasm, 0); - int call_offset = __ call_RT(noreg, noreg, (address)graal_log_printf, j_rarg0, j_rarg1, j_rarg2, j_rarg3); + 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); __ leave(); @@ -1081,11 +990,11 @@ break; } - case graal_log_primitive_id: { + case log_primitive_id: { __ enter(); oop_maps = new OopMapSet(); OopMap* oop_map = save_live_registers(sasm, 0); - int call_offset = __ call_RT(noreg, noreg, (address)graal_log_primitive, j_rarg0, j_rarg1, j_rarg2); + 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); __ leave(); @@ -1093,11 +1002,11 @@ break; } - case graal_log_object_id: { + case log_object_id: { __ enter(); oop_maps = new OopMapSet(); OopMap* oop_map = save_live_registers(sasm, 0); - int call_offset = __ call_RT(noreg, noreg, (address)graal_log_object, j_rarg0, j_rarg1); + 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); __ leave(); @@ -1105,7 +1014,7 @@ break; } - case graal_verify_oop_id: { + case verify_oop_id: { // We use enter & leave so that a better stack trace is produced in the hs_err file __ enter(); __ verify_oop(r13, "Graal verify oop"); @@ -1114,7 +1023,7 @@ break; } - case graal_arithmetic_frem_id: { + case arithmetic_frem_id: { __ subptr(rsp, 8); __ movflt(Address(rsp, 0), xmm1); __ fld_s(Address(rsp, 0)); @@ -1135,7 +1044,7 @@ __ ret(0); break; } - case graal_arithmetic_drem_id: { + case arithmetic_drem_id: { __ subptr(rsp, 8); __ movdbl(Address(rsp, 0), xmm1); __ fld_d(Address(rsp, 0)); @@ -1156,15 +1065,15 @@ __ ret(0); break; } - case graal_monitorenter_id: { + case monitorenter_id: { Register obj = j_rarg0; Register lock = j_rarg1; { - GraalStubFrame f(sasm, "graal_monitorenter", dont_gc_arguments); + GraalStubFrame f(sasm, "monitorenter", dont_gc_arguments); OopMap* map = save_live_registers(sasm, 2, save_fpu_registers); // Called with store_parameter and not C abi - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, graal_monitorenter), obj, lock); + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorenter), obj, lock); oop_maps = new OopMapSet(); oop_maps->add_gc_map(call_offset, map); @@ -1173,17 +1082,17 @@ __ ret(0); break; } - case graal_monitorexit_id: { + case monitorexit_id: { Register obj = j_rarg0; Register lock = j_rarg1; { - GraalStubFrame f(sasm, "graal_monitorexit", dont_gc_arguments); + GraalStubFrame f(sasm, "monitorexit", dont_gc_arguments); OopMap* map = save_live_registers(sasm, 2, save_fpu_registers); // note: really a leaf routine but must setup last java sp // => use call_RT for now (speed can be improved by // doing last java sp setup manually) - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, graal_monitorexit), obj, lock); + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorexit), obj, lock); oop_maps = new OopMapSet(); oop_maps->add_gc_map(call_offset, map); @@ -1192,7 +1101,7 @@ __ ret(0); break; } - case graal_wb_pre_call_id: { + case wb_pre_call_id: { Register obj = j_rarg0; { GraalStubFrame f(sasm, "graal_wb_pre_call", dont_gc_arguments); @@ -1201,7 +1110,7 @@ // note: really a leaf routine but must setup last java sp // => use call_RT for now (speed can be improved by // doing last java sp setup manually) - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, graal_wb_pre_call), obj); + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, wb_pre_call), obj); oop_maps = new OopMapSet(); oop_maps->add_gc_map(call_offset, map); @@ -1210,7 +1119,7 @@ __ ret(0); break; } - case graal_wb_post_call_id: { + case wb_post_call_id: { Register obj = j_rarg0; Register caddr = j_rarg1; { @@ -1220,7 +1129,7 @@ // note: really a leaf routine but must setup last java sp // => use call_RT for now (speed can be improved by // doing last java sp setup manually) - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, graal_wb_post_call), obj, caddr); + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, wb_post_call), obj, caddr); oop_maps = new OopMapSet(); oop_maps->add_gc_map(call_offset, map); @@ -1230,12 +1139,13 @@ break; } - case graal_identity_hash_code_id: { + + case identity_hash_code_id: { Register obj = j_rarg0; // Incoming __ set_info("identity_hash_code", dont_gc_arguments); __ enter(); OopMap* map = save_live_registers(sasm, 1); - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, graal_identity_hash_code), obj); + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, identity_hash_code), obj); oop_maps = new OopMapSet(); oop_maps->add_gc_map(call_offset, map); restore_live_registers_except_rax(sasm); @@ -1243,14 +1153,14 @@ __ ret(0); break; } - case graal_thread_is_interrupted_id: { + case thread_is_interrupted_id: { Register thread = j_rarg0; Register clear_interrupted = j_rarg1; __ set_info("identity_hash_code", dont_gc_arguments); __ enter(); OopMap* map = save_live_registers(sasm, 1); - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, graal_thread_is_interrupted), thread, clear_interrupted); + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, thread_is_interrupted), thread, clear_interrupted); oop_maps = new OopMapSet(); oop_maps->add_gc_map(call_offset, map); restore_live_registers_except_rax(sasm); diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/interpreterGenerator_x86.hpp --- a/src/cpu/x86/vm/interpreterGenerator_x86.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/interpreterGenerator_x86.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -30,6 +30,8 @@ // friend class AbstractInterpreterGenerator; + address generate_deopt_entry_for(TosState state, int step); + private: address generate_normal_entry(bool synchronized); diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/jniTypes_x86.hpp --- a/src/cpu/x86/vm/jniTypes_x86.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/jniTypes_x86.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -127,26 +127,6 @@ static inline oop get_obj (intptr_t *from) { return *(oop *) from; } static inline jfloat get_float (intptr_t *from) { return *(jfloat *) from; } static inline jdouble get_double(intptr_t *from) { return *(jdouble *)(from + _JNI_SLOT_OFFSET); } - - static inline jint get_int (intptr_t *from, int& pos) { - return get_int(from + pos++); - } - static inline jlong get_long (intptr_t *from, int& pos) { - jlong result = get_long(from + pos); - pos += 2; - return result; - } - static inline oop get_obj (intptr_t *from, int& pos) { - return get_obj(from + pos++); - } - static inline jfloat get_float (intptr_t *from, int& pos) { - return get_float(from + pos++); - } - static inline jdouble get_double(intptr_t *from, int& pos) { - jdouble result = get_double(from + pos); - pos += 2; - return result; - } #undef _JNI_SLOT_OFFSET }; diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/macroAssembler_x86.cpp --- a/src/cpu/x86/vm/macroAssembler_x86.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/macroAssembler_x86.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -37,11 +37,12 @@ #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/heapRegion.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ @@ -2057,7 +2058,7 @@ } // !defined(COMPILER2) is because of stupid core builds -#if !defined(_LP64) || defined(COMPILER1) || !defined(COMPILER2) +#if !defined(_LP64) || defined(COMPILER1) || !defined(COMPILER2) || defined(GRAAL) void MacroAssembler::empty_FPU_stack() { if (VM_Version::supports_mmx()) { emms(); @@ -3207,7 +3208,7 @@ ////////////////////////////////////////////////////////////////////////////////// -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void MacroAssembler::g1_write_barrier_pre(Register obj, Register pre_val, @@ -3417,7 +3418,7 @@ bind(done); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS ////////////////////////////////////////////////////////////////////////////////// @@ -5690,7 +5691,7 @@ Address::ScaleFactor scale = Address::times_2; int stride = 8; - if (UseAVX >= 2) { + if (UseAVX >= 2 && UseSSE42Intrinsics) { Label COMPARE_WIDE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_WIDE_TAIL, COMPARE_SMALL_STR; Label COMPARE_WIDE_VECTORS_LOOP, COMPARE_16_CHARS, COMPARE_INDEX_CHAR; Label COMPARE_TAIL_LONG; diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/macroAssembler_x86.hpp --- a/src/cpu/x86/vm/macroAssembler_x86.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/macroAssembler_x86.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -26,6 +26,7 @@ #define CPU_X86_VM_MACROASSEMBLER_X86_HPP #include "asm/assembler.hpp" +#include "utilities/macros.hpp" // MacroAssembler extends Assembler by frequently used macros. @@ -294,7 +295,7 @@ void store_check(Register obj); // store check for obj - register is destroyed afterwards void store_check(Register obj, Address dst); // same as above, dst is exact store location (reg. is destroyed) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void g1_write_barrier_pre(Register obj, Register pre_val, @@ -309,7 +310,7 @@ Register tmp, Register tmp2); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // split store_check(Register obj) to enhance instruction interleaving void store_check_part_1(Register obj); diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/nativeInst_x86.hpp --- a/src/cpu/x86/vm/nativeInst_x86.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/nativeInst_x86.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -574,15 +574,18 @@ return false; } } else { - if (ubyte_at(0) == Assembler::REX_WR && ubyte_at(1) == NativeMovRegMem::instruction_code_mem2reg && ubyte_at(2) == 0x15) { // mov r10, rip[...] - address fault = addr_at(7) + int_at(3); - return os::is_poll_address(fault); - } else if (ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && ubyte_at(1) == 0x05) { // 00 rax 101 +#ifdef GRAAL + // Graal may allocate an arbitrary register for storing the polling address. + return true; +#else + if (ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && + ubyte_at(1) == 0x05) { // 00 rax 101 address fault = addr_at(6) + int_at(2); return os::is_poll_address(fault); } else { return false; } +#endif } #else return ( ubyte_at(0) == NativeMovRegMem::instruction_code_mem2reg || diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/sharedRuntime_x86_32.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1763,8 +1763,7 @@ int vep_offset = ((intptr_t)__ pc()) - start; -#if defined(COMPILER1) || defined(GRAAL) - +#ifdef COMPILER1 if (InlineObjectHash && method->intrinsic_id() == vmIntrinsics::_hashCode) { // Object.hashCode can pull the hashCode from the header word // instead of doing a full VM transition once it's been computed. @@ -1793,7 +1792,7 @@ __ ret(0); __ bind (slowCase); } -#endif // COMPILER1 || GRAAL +#endif // COMPILER1 // The instruction at the verified entry point must be 5 bytes or longer // because it can be patched on the fly by make_non_entrant. The stack bang diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1996,50 +1996,6 @@ int vep_offset = ((intptr_t)__ pc()) - start; -#ifdef GRAALVM - if (InlineObjectHash && (method->intrinsic_id() == vmIntrinsics::_hashCode || method->intrinsic_id() == vmIntrinsics::_identityHashCode)) { - // Object.hashCode can pull the hashCode from the header word - // instead of doing a full VM transition once it's been computed. - // Since hashCode is usually polymorphic at call sites we can't do - // this optimization at the call site without a lot of work. - Label slowCase; - Label nullCase; - Register result = rax; - - if (method->intrinsic_id() == vmIntrinsics::_identityHashCode) { - __ cmpptr(receiver, 0); - __ jcc(Assembler::equal, nullCase); - } - - __ movptr(result, Address(receiver, oopDesc::mark_offset_in_bytes())); - - // check if locked - __ testptr(result, markOopDesc::unlocked_value); - __ jcc (Assembler::zero, slowCase); - - if (UseBiasedLocking) { - // Check if biased and fall through to runtime if so - __ testptr(result, markOopDesc::biased_lock_bit_in_place); - __ jcc (Assembler::notZero, slowCase); - } - - // get hash - __ shrptr(result, markOopDesc::hash_shift); - __ andptr(result, markOopDesc::hash_mask); - // test if hashCode exists - __ jcc (Assembler::zero, slowCase); - __ ret(0); - - if (method->intrinsic_id() == vmIntrinsics::_identityHashCode) { - __ bind(nullCase); - __ movl(result, 0); - __ ret(0); - } - - __ bind (slowCase); - } -#endif // GRAALVM - // The instruction at the verified entry point must be 5 bytes or longer // because it can be patched on the fly by make_non_entrant. The stack bang // instruction fits that requirement. @@ -3452,8 +3408,8 @@ __ 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()))); - __ movptr(rscratch1, Address(r15_thread, in_bytes(JavaThread::ScratchB_offset()))); int uncommon_trap_offset = __ pc() - start; @@ -3462,8 +3418,8 @@ // fetch_unroll_info needs to call last_java_frame() __ set_last_Java_frame(noreg, noreg, NULL); - assert(r10 == rscratch1, "scratch register should be r10"); - __ movl(c_rarg1, Address(rsp, RegisterSaver::r10_offset_in_bytes())); + __ 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); diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/templateInterpreter_x86.hpp --- a/src/cpu/x86/vm/templateInterpreter_x86.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/templateInterpreter_x86.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -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 = 200 * 1024; + const static int InterpreterCodeSize = 220 * 1024; #else const static int InterpreterCodeSize = 168 * 1024; #endif // AMD64 diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/templateInterpreter_x86_32.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -44,6 +44,7 @@ #include "runtime/timer.hpp" #include "runtime/vframeArray.hpp" #include "utilities/debug.hpp" +#include "utilities/macros.hpp" #define __ _masm-> @@ -761,7 +762,7 @@ // Method entry for java.lang.ref.Reference.get. address InterpreterGenerator::generate_Reference_get_entry(void) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Code: _aload_0, _getfield, _areturn // parameter size = 1 // @@ -844,7 +845,7 @@ return entry; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/templateInterpreter_x86_64.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -45,6 +45,7 @@ #include "runtime/timer.hpp" #include "runtime/vframeArray.hpp" #include "utilities/debug.hpp" +#include "utilities/macros.hpp" #define __ _masm-> @@ -203,13 +204,26 @@ } -address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, +address InterpreterGenerator::generate_deopt_entry_for(TosState state, int step) { address entry = __ pc(); // NULL last_sp until next java call __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); __ restore_bcp(); __ restore_locals(); + // Check if we need to take lock at entry of synchronized method. + { + Label L; + __ cmpb(Address(r15_thread, Thread::pending_monitorenter_offset()), 0); + __ jcc(Assembler::zero, L); + // Clear flag. + __ movb(Address(r15_thread, Thread::pending_monitorenter_offset()), 0); + // Satisfy calling convention for lock_method(). + __ get_method(rbx); + // Take lock. + lock_method(); + __ bind(L); + } // handle exceptions { Label L; @@ -773,7 +787,7 @@ // Method entry for java.lang.ref.Reference.get. address InterpreterGenerator::generate_Reference_get_entry(void) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Code: _aload_0, _getfield, _areturn // parameter size = 1 // @@ -852,7 +866,7 @@ return entry; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/templateTable_x86_32.cpp --- a/src/cpu/x86/vm/templateTable_x86_32.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/templateTable_x86_32.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -35,6 +35,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/synchronizer.hpp" +#include "utilities/macros.hpp" #ifndef CC_INTERP #define __ _masm-> @@ -125,7 +126,7 @@ bool precise) { assert(val == noreg || val == rax, "parameter is just for looks"); switch (barrier) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case BarrierSet::G1SATBCT: case BarrierSet::G1SATBCTLogging: { @@ -164,7 +165,7 @@ } break; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS case BarrierSet::CardTableModRef: case BarrierSet::CardTableExtension: { diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/x86/vm/templateTable_x86_64.cpp --- a/src/cpu/x86/vm/templateTable_x86_64.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/x86/vm/templateTable_x86_64.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -35,6 +35,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/synchronizer.hpp" +#include "utilities/macros.hpp" #ifndef CC_INTERP @@ -136,7 +137,7 @@ bool precise) { assert(val == noreg || val == rax, "parameter is just for looks"); switch (barrier) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case BarrierSet::G1SATBCT: case BarrierSet::G1SATBCTLogging: { @@ -167,7 +168,7 @@ } break; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS case BarrierSet::CardTableModRef: case BarrierSet::CardTableExtension: { diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/zero/vm/assembler_zero.cpp --- a/src/cpu/zero/vm/assembler_zero.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/zero/vm/assembler_zero.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -36,11 +36,12 @@ #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/heapRegion.hpp" -#endif +#endif // INCLUDE_ALL_GCS int AbstractAssembler::code_fill_byte() { return 0; diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/zero/vm/cppInterpreter_zero.cpp --- a/src/cpu/zero/vm/cppInterpreter_zero.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/zero/vm/cppInterpreter_zero.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -47,6 +47,7 @@ #include "runtime/vframeArray.hpp" #include "stack_zero.inline.hpp" #include "utilities/debug.hpp" +#include "utilities/macros.hpp" #ifdef SHARK #include "shark/shark_globals.hpp" #endif @@ -791,7 +792,7 @@ } address InterpreterGenerator::generate_Reference_get_entry(void) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseG1GC) { // We need to generate have a routine that generates code to: // * load the value in the referent field @@ -803,7 +804,7 @@ // field as live. Unimplemented(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor diff -r dee7c8b578c7 -r c3657d00e343 src/cpu/zero/vm/shark_globals_zero.hpp --- a/src/cpu/zero/vm/shark_globals_zero.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/cpu/zero/vm/shark_globals_zero.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright 2008, 2009, 2010 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -51,7 +51,7 @@ define_pd_global(intx, OnStackReplacePercentage, 933 ); define_pd_global(intx, FreqInlineSize, 325 ); define_pd_global(intx, InlineSmallCode, 1000 ); -define_pd_global(intx, NewRatio, 12 ); +define_pd_global(uintx, NewRatio, 12 ); define_pd_global(intx, NewSizeThreadIncrease, 4*K ); define_pd_global(intx, InitialCodeCacheSize, 160*K); define_pd_global(intx, ReservedCodeCacheSize, 32*M ); diff -r dee7c8b578c7 -r c3657d00e343 src/os/bsd/vm/osThread_bsd.hpp --- a/src/os/bsd/vm/osThread_bsd.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/os/bsd/vm/osThread_bsd.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -49,6 +49,11 @@ // (e.g. pthread_kill). pthread_t _pthread_id; + // This is the "thread_id" from struct thread_identifier_info. According to a + // comment in thread_info.h, this is a "system-wide unique 64-bit thread id". + // The value is used by SA to correlate threads. + uint64_t _unique_thread_id; + sigset_t _caller_sigmask; // Caller's signal mask public: @@ -77,6 +82,10 @@ _pthread_id = tid; } + void set_unique_thread_id(uint64_t id) { + _unique_thread_id = id; + } + // *************************************************************** // suspension support. // *************************************************************** diff -r dee7c8b578c7 -r c3657d00e343 src/os/bsd/vm/os_bsd.cpp --- a/src/os/bsd/vm/os_bsd.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/os/bsd/vm/os_bsd.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -657,6 +657,18 @@ objc_registerThreadWithCollector_t objc_registerThreadWithCollectorFunction = NULL; #endif +#ifdef __APPLE__ +static uint64_t locate_unique_thread_id() { + // Additional thread_id used to correlate threads in SA + thread_identifier_info_data_t m_ident_info; + mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; + + thread_info(::mach_thread_self(), THREAD_IDENTIFIER_INFO, + (thread_info_t) &m_ident_info, &count); + return m_ident_info.thread_id; +} +#endif + // Thread start routine for all newly created threads static void *java_start(Thread *thread) { // Try to randomize the cache line index of hot stack frames. @@ -685,6 +697,7 @@ #ifdef __APPLE__ // thread_id is mach thread on macos osthread->set_thread_id(::mach_thread_self()); + osthread->set_unique_thread_id(locate_unique_thread_id()); #else // thread_id is pthread_id on BSD osthread->set_thread_id(::pthread_self()); @@ -847,6 +860,7 @@ // Store pthread info into the OSThread #ifdef __APPLE__ osthread->set_thread_id(::mach_thread_self()); + osthread->set_unique_thread_id(locate_unique_thread_id()); #else osthread->set_thread_id(::pthread_self()); #endif @@ -2873,7 +2887,9 @@ void signalHandler(int sig, siginfo_t* info, void* uc) { assert(info != NULL && uc != NULL, "it must be old kernel"); + int orig_errno = errno; // Preserve errno value over signal handler. JVM_handle_bsd_signal(sig, info, uc, true); + errno = orig_errno; } @@ -3619,9 +3635,9 @@ // able to use structured exception handling (thread-local exception filters) // on, e.g., Win32. void -os::os_exception_wrapper(java_call_t f, JavaValue* value, methodHandle* method, nmethod* nm, +os::os_exception_wrapper(java_call_t f, JavaValue* value, methodHandle* method, JavaCallArguments* args, Thread* thread) { - f(value, method, nm, args, thread); + f(value, method, args, thread); } void os::print_statistics() { diff -r dee7c8b578c7 -r c3657d00e343 src/os/linux/vm/os_linux.cpp --- a/src/os/linux/vm/os_linux.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/os/linux/vm/os_linux.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1155,13 +1155,9 @@ // for initial thread if its stack size exceeds 6M. Cap it at 2M, // in case other parts in glibc still assumes 2M max stack size. // FIXME: alt signal stack is gone, maybe we can relax this constraint? -#ifndef IA64 - if (stack_size > 2 * K * K) stack_size = 2 * K * K; -#else // Problem still exists RH7.2 (IA64 anyway) but 2MB is a little small - if (stack_size > 4 * K * K) stack_size = 4 * K * K; -#endif - + if (stack_size > 2 * K * K IA64_ONLY(*2)) + stack_size = 2 * K * K IA64_ONLY(*2); // Try to figure out where the stack base (top) is. This is harder. // // When an application is started, glibc saves the initial stack pointer in @@ -3657,14 +3653,9 @@ void signalHandler(int sig, siginfo_t* info, void* uc) { assert(info != NULL && uc != NULL, "it must be old kernel"); - ResourceMark rm; - if (TraceSignals) { - tty->print_cr(err_msg("signal received: code=%d errno=%d signo=%d thread=%s address=%x", info->si_code, info->si_errno, info->si_signo, Thread::current()->name(), info->si_addr)); - } + int orig_errno = errno; // Preserve errno value over signal handler. JVM_handle_linux_signal(sig, info, uc, true); - if (TraceSignals) { - tty->print_cr("signal handled"); - } + errno = orig_errno; } @@ -4374,16 +4365,12 @@ if (is_NPTL()) { return pthread_cond_timedwait(_cond, _mutex, _abstime); } else { -#ifndef IA64 // 6292965: LinuxThreads pthread_cond_timedwait() resets FPU control // word back to default 64bit precision if condvar is signaled. Java // wants 53bit precision. Save and restore current value. int fpu = get_fpu_control_word(); -#endif // IA64 int status = pthread_cond_timedwait(_cond, _mutex, _abstime); -#ifndef IA64 set_fpu_control_word(fpu); -#endif // IA64 return status; } } @@ -4447,9 +4434,9 @@ // able to use structured exception handling (thread-local exception filters) // on, e.g., Win32. void -os::os_exception_wrapper(java_call_t f, JavaValue* value, methodHandle* method, nmethod* nm, +os::os_exception_wrapper(java_call_t f, JavaValue* value, methodHandle* method, JavaCallArguments* args, Thread* thread) { - f(value, method, nm, args, thread); + f(value, method, args, thread); } void os::print_statistics() { @@ -4756,49 +4743,26 @@ // static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { - static bool proc_pid_cpu_avail = true; static bool proc_task_unchecked = true; static const char *proc_stat_path = "/proc/%d/stat"; pid_t tid = thread->osthread()->thread_id(); - int i; char *s; char stat[2048]; int statlen; char proc_name[64]; int count; long sys_time, user_time; - char string[64]; char cdummy; int idummy; long ldummy; FILE *fp; - // We first try accessing /proc//cpu since this is faster to - // process. If this file is not present (linux kernels 2.5 and above) - // then we open /proc//stat. - if ( proc_pid_cpu_avail ) { - sprintf(proc_name, "/proc/%d/cpu", tid); - fp = fopen(proc_name, "r"); - if ( fp != NULL ) { - count = fscanf( fp, "%s %lu %lu\n", string, &user_time, &sys_time); - fclose(fp); - if ( count != 3 ) return -1; - - if (user_sys_cpu_time) { - return ((jlong)sys_time + (jlong)user_time) * (1000000000 / clock_tics_per_sec); - } else { - return (jlong)user_time * (1000000000 / clock_tics_per_sec); - } - } - else proc_pid_cpu_avail = false; - } - // The /proc//stat aggregates per-process usage on // new Linux kernels 2.6+ where NPTL is supported. // The /proc/self/task//stat still has the per-thread usage. // See bug 6328462. - // There can be no directory /proc/self/task on kernels 2.4 with NPTL - // and possibly in some other cases, so we check its availability. + // There possibly can be cases where there is no directory + // /proc/self/task, so we check its availability. if (proc_task_unchecked && os::Linux::is_NPTL()) { // This is executed only once proc_task_unchecked = false; @@ -4823,7 +4787,6 @@ // We don't really need to know the command string, just find the last // occurrence of ")" and then start parsing from there. See bug 4726580. s = strrchr(stat, ')'); - i = 0; if (s == NULL ) return -1; // Skip blank chars diff -r dee7c8b578c7 -r c3657d00e343 src/os/solaris/vm/os_solaris.cpp --- a/src/os/solaris/vm/os_solaris.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/os/solaris/vm/os_solaris.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1865,7 +1865,7 @@ // Die immediately, no exit hook, no abort hook, no cleanup. void os::die() { - _exit(-1); + ::abort(); // dump core (for debugging) } // unused @@ -4280,8 +4280,8 @@ // This does not do anything on Solaris. This is basically a hook for being // able to use structured exception handling (thread-local exception filters) on, e.g., Win32. -void os::os_exception_wrapper(java_call_t f, JavaValue* value, methodHandle* method, nmethod* nm, JavaCallArguments* args, Thread* thread) { - f(value, method, nm, args, thread); +void os::os_exception_wrapper(java_call_t f, JavaValue* value, methodHandle* method, JavaCallArguments* args, Thread* thread) { + f(value, method, args, thread); } // This routine may be used by user applications as a "hook" to catch signals. @@ -4317,7 +4317,9 @@ void signalHandler(int sig, siginfo_t* info, void* ucVoid) { + int orig_errno = errno; // Preserve errno value over signal handler. JVM_handle_solaris_signal(sig, info, ucVoid, true); + errno = orig_errno; } /* Do not delete - if guarantee is ever removed, a signal handler (even empty) diff -r dee7c8b578c7 -r c3657d00e343 src/os/windows/vm/os_windows.cpp --- a/src/os/windows/vm/os_windows.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/os/windows/vm/os_windows.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -349,6 +349,33 @@ #ifdef _M_IA64 // IA64 has memory and register stacks + // + // This is the stack layout you get on NT/IA64 if you specify 1MB stack limit + // at thread creation (1MB backing store growing upwards, 1MB memory stack + // growing downwards, 2MB summed up) + // + // ... + // ------- top of stack (high address) ----- + // | + // | 1MB + // | Backing Store (Register Stack) + // | + // | / \ + // | | + // | | + // | | + // ------------------------ stack base ----- + // | 1MB + // | Memory Stack + // | + // | | + // | | + // | | + // | \ / + // | + // ----- bottom of stack (low address) ----- + // ... + stack_size = stack_size / 2; #endif return stack_bottom + stack_size; @@ -1913,7 +1940,7 @@ // a counter for each possible signal value, including signal_thread exit signal static volatile jint pending_signals[NSIG+1] = { 0 }; -static HANDLE sig_sem; +static HANDLE sig_sem = NULL; void os::signal_init_pd() { // Initialize signal structures @@ -1943,10 +1970,11 @@ void os::signal_notify(int signal_number) { BOOL ret; - - Atomic::inc(&pending_signals[signal_number]); - ret = ::ReleaseSemaphore(sig_sem, 1, NULL); - assert(ret != 0, "ReleaseSemaphore() failed"); + if (sig_sem != NULL) { + Atomic::inc(&pending_signals[signal_number]); + ret = ::ReleaseSemaphore(sig_sem, 1, NULL); + assert(ret != 0, "ReleaseSemaphore() failed"); + } } static int check_pending_signals(bool wait_for_signal) { @@ -2005,17 +2033,34 @@ JavaThread* thread = JavaThread::current(); // Save pc in thread #ifdef _M_IA64 - thread->set_saved_exception_pc((address)exceptionInfo->ContextRecord->StIIP); + // Do not blow up if no thread info available. + if (thread) { + // Saving PRECISE pc (with slot information) in thread. + uint64_t precise_pc = (uint64_t) exceptionInfo->ExceptionRecord->ExceptionAddress; + // Convert precise PC into "Unix" format + precise_pc = (precise_pc & 0xFFFFFFFFFFFFFFF0) | ((precise_pc & 0xF) >> 2); + thread->set_saved_exception_pc((address)precise_pc); + } // Set pc to handler exceptionInfo->ContextRecord->StIIP = (DWORD64)handler; + // Clear out psr.ri (= Restart Instruction) in order to continue + // at the beginning of the target bundle. + exceptionInfo->ContextRecord->StIPSR &= 0xFFFFF9FFFFFFFFFF; + assert(((DWORD64)handler & 0xF) == 0, "Target address must point to the beginning of a bundle!"); #elif _M_AMD64 - thread->set_saved_exception_pc((address)exceptionInfo->ContextRecord->Rip); + // Do not blow up if no thread info available. + if (thread) { + thread->set_saved_exception_pc((address)(DWORD_PTR)exceptionInfo->ContextRecord->Rip); + } // Set pc to handler exceptionInfo->ContextRecord->Rip = (DWORD64)handler; #else - thread->set_saved_exception_pc((address)exceptionInfo->ContextRecord->Eip); + // Do not blow up if no thread info available. + if (thread) { + thread->set_saved_exception_pc((address)(DWORD_PTR)exceptionInfo->ContextRecord->Eip); + } // Set pc to handler - exceptionInfo->ContextRecord->Eip = (LONG)handler; + exceptionInfo->ContextRecord->Eip = (DWORD)(DWORD_PTR)handler; #endif // Continue the execution @@ -2040,6 +2085,14 @@ // included or copied here. #define EXCEPTION_INFO_EXEC_VIOLATION 0x08 +// Handle NAT Bit consumption on IA64. +#ifdef _M_IA64 +#define EXCEPTION_REG_NAT_CONSUMPTION STATUS_REG_NAT_CONSUMPTION +#endif + +// Windows Vista/2008 heap corruption check +#define EXCEPTION_HEAP_CORRUPTION 0xC0000374 + #define def_excpt(val) #val, val struct siglabel { @@ -2082,6 +2135,10 @@ def_excpt(EXCEPTION_GUARD_PAGE), def_excpt(EXCEPTION_INVALID_HANDLE), def_excpt(EXCEPTION_UNCAUGHT_CXX_EXCEPTION), + def_excpt(EXCEPTION_HEAP_CORRUPTION), +#ifdef _M_IA64 + def_excpt(EXCEPTION_REG_NAT_CONSUMPTION), +#endif NULL, 0 }; @@ -2222,7 +2279,14 @@ if (InterceptOSException) return EXCEPTION_CONTINUE_SEARCH; DWORD exception_code = exceptionInfo->ExceptionRecord->ExceptionCode; #ifdef _M_IA64 - address pc = (address) exceptionInfo->ContextRecord->StIIP; + // On Itanium, we need the "precise pc", which has the slot number coded + // into the least 4 bits: 0000=slot0, 0100=slot1, 1000=slot2 (Windows format). + address pc = (address) exceptionInfo->ExceptionRecord->ExceptionAddress; + // Convert the pc to "Unix format", which has the slot number coded + // into the least 2 bits: 0000=slot0, 0001=slot1, 0010=slot2 + // This is needed for IA64 because "relocation" / "implicit null check" / "poll instruction" + // information is saved in the Unix format. + address pc_unix_format = (address) ((((uint64_t)pc) & 0xFFFFFFFFFFFFFFF0) | ((((uint64_t)pc) & 0xF) >> 2)); #elif _M_AMD64 address pc = (address) exceptionInfo->ContextRecord->Rip; #else @@ -2337,29 +2401,40 @@ if (exception_code == EXCEPTION_STACK_OVERFLOW) { if (os::uses_stack_guard_pages()) { #ifdef _M_IA64 - // - // If it's a legal stack address continue, Windows will map it in. - // + // Use guard page for register stack. PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; address addr = (address) exceptionRecord->ExceptionInformation[1]; - if (addr > thread->stack_yellow_zone_base() && addr < thread->stack_base() ) - return EXCEPTION_CONTINUE_EXECUTION; - - // The register save area is the same size as the memory stack - // and starts at the page just above the start of the memory stack. - // If we get a fault in this area, we've run out of register - // stack. If we are in java, try throwing a stack overflow exception. - if (addr > thread->stack_base() && - addr <= (thread->stack_base()+thread->stack_size()) ) { - char buf[256]; - jio_snprintf(buf, sizeof(buf), - "Register stack overflow, addr:%p, stack_base:%p\n", - addr, thread->stack_base() ); - tty->print_raw_cr(buf); - // If not in java code, return and hope for the best. - return in_java ? Handle_Exception(exceptionInfo, - SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW)) - : EXCEPTION_CONTINUE_EXECUTION; + // Check for a register stack overflow on Itanium + if (thread->addr_inside_register_stack_red_zone(addr)) { + // Fatal red zone violation happens if the Java program + // catches a StackOverflow error and does so much processing + // that it runs beyond the unprotected yellow guard zone. As + // a result, we are out of here. + fatal("ERROR: Unrecoverable stack overflow happened. JVM will exit."); + } else if(thread->addr_inside_register_stack(addr)) { + // Disable the yellow zone which sets the state that + // we've got a stack overflow problem. + if (thread->stack_yellow_zone_enabled()) { + thread->disable_stack_yellow_zone(); + } + // Give us some room to process the exception. + thread->disable_register_stack_guard(); + // Tracing with +Verbose. + if (Verbose) { + tty->print_cr("SOF Compiled Register Stack overflow at " INTPTR_FORMAT " (SIGSEGV)", pc); + tty->print_cr("Register Stack access at " INTPTR_FORMAT, addr); + tty->print_cr("Register Stack base " INTPTR_FORMAT, thread->register_stack_base()); + tty->print_cr("Register Stack [" INTPTR_FORMAT "," INTPTR_FORMAT "]", + thread->register_stack_base(), + thread->register_stack_base() + thread->stack_size()); + } + + // Reguard the permanent register stack red zone just to be sure. + // We saw Windows silently disabling this without telling us. + thread->enable_register_stack_red_zone(); + + return Handle_Exception(exceptionInfo, + SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW)); } #endif if (thread->stack_yellow_zone_enabled()) { @@ -2434,50 +2509,33 @@ { // Null pointer exception. #ifdef _M_IA64 - // We catch register stack overflows in compiled code by doing - // an explicit compare and executing a st8(G0, G0) if the - // BSP enters into our guard area. We test for the overflow - // condition and fall into the normal null pointer exception - // code if BSP hasn't overflowed. - if ( in_java ) { - if(thread->register_stack_overflow()) { - assert((address)exceptionInfo->ContextRecord->IntS3 == - thread->register_stack_limit(), - "GR7 doesn't contain register_stack_limit"); - // Disable the yellow zone which sets the state that - // we've got a stack overflow problem. - if (thread->stack_yellow_zone_enabled()) { - thread->disable_stack_yellow_zone(); + // Process implicit null checks in compiled code. Note: Implicit null checks + // can happen even if "ImplicitNullChecks" is disabled, e.g. in vtable stubs. + if (CodeCache::contains((void*) pc_unix_format) && !MacroAssembler::needs_explicit_null_check((intptr_t) addr)) { + CodeBlob *cb = CodeCache::find_blob_unsafe(pc_unix_format); + // Handle implicit null check in UEP method entry + if (cb && (cb->is_frame_complete_at(pc) || + (cb->is_nmethod() && ((nmethod *)cb)->inlinecache_check_contains(pc)))) { + if (Verbose) { + intptr_t *bundle_start = (intptr_t*) ((intptr_t) pc_unix_format & 0xFFFFFFFFFFFFFFF0); + tty->print_cr("trap: null_check at " INTPTR_FORMAT " (SIGSEGV)", pc_unix_format); + tty->print_cr(" to addr " INTPTR_FORMAT, addr); + tty->print_cr(" bundle is " INTPTR_FORMAT " (high), " INTPTR_FORMAT " (low)", + *(bundle_start + 1), *bundle_start); } - // Give us some room to process the exception - thread->disable_register_stack_guard(); - // Update GR7 with the new limit so we can continue running - // compiled code. - exceptionInfo->ContextRecord->IntS3 = - (ULONGLONG)thread->register_stack_limit(); return Handle_Exception(exceptionInfo, - SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW)); - } else { - // - // Check for implicit null - // We only expect null pointers in the stubs (vtable) - // the rest are checked explicitly now. - // - if (((uintptr_t)addr) < os::vm_page_size() ) { - // an access to the first page of VM--assume it is a null pointer - address stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL); - if (stub != NULL) return Handle_Exception(exceptionInfo, stub); - } + SharedRuntime::continuation_for_implicit_exception(thread, pc_unix_format, SharedRuntime::IMPLICIT_NULL)); } - } // in_java - - // IA64 doesn't use implicit null checking yet. So we shouldn't - // get here. - tty->print_raw_cr("Access violation, possible null pointer exception"); + } + + // Implicit null checks were processed above. Hence, we should not reach + // here in the usual case => die! + if (Verbose) tty->print_raw_cr("Access violation, possible null pointer exception"); report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord, exceptionInfo->ContextRecord); return EXCEPTION_CONTINUE_SEARCH; -#else /* !IA64 */ + +#else // !IA64 // Windows 98 reports faulting addresses incorrectly if (!MacroAssembler::needs_explicit_null_check((intptr_t)addr) || @@ -2509,7 +2567,24 @@ report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord, exceptionInfo->ContextRecord); return EXCEPTION_CONTINUE_SEARCH; - } + } // /EXCEPTION_ACCESS_VIOLATION + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +#if defined _M_IA64 + else if ((exception_code == EXCEPTION_ILLEGAL_INSTRUCTION || + exception_code == EXCEPTION_ILLEGAL_INSTRUCTION_2)) { + M37 handle_wrong_method_break(0, NativeJump::HANDLE_WRONG_METHOD, PR0); + + // Compiled method patched to be non entrant? Following conditions must apply: + // 1. must be first instruction in bundle + // 2. must be a break instruction with appropriate code + if((((uint64_t) pc & 0x0F) == 0) && + (((IPF_Bundle*) pc)->get_slot0() == handle_wrong_method_break.bits())) { + return Handle_Exception(exceptionInfo, + (address)SharedRuntime::get_handle_wrong_method_stub()); + } + } // /EXCEPTION_ILLEGAL_INSTRUCTION +#endif + if (in_java) { switch (exception_code) { diff -r dee7c8b578c7 -r c3657d00e343 src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp --- a/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ #endif // AMD64 define_pd_global(intx, CompilerThreadStackSize, 0); -define_pd_global(intx, SurvivorRatio, 8); +define_pd_global(uintx, SurvivorRatio, 8); define_pd_global(uintx, JVMInvokeMethodSlack, 8192); diff -r dee7c8b578c7 -r c3657d00e343 src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp --- a/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -372,7 +372,7 @@ CAST_FROM_FN_PTR(address, os::current_frame)); if (os::is_first_C_frame(&myframe)) { // stack is not walkable - return frame(NULL, NULL, NULL); + return frame(); } else { return os::get_sender_for_C_frame(&myframe); } diff -r dee7c8b578c7 -r c3657d00e343 src/os_cpu/bsd_x86/vm/vmStructs_bsd_x86.hpp --- a/src/os_cpu/bsd_x86/vm/vmStructs_bsd_x86.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/os_cpu/bsd_x86/vm/vmStructs_bsd_x86.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -35,17 +35,16 @@ /* Threads (NOTE: incomplete) */ \ /******************************/ \ nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) + nonstatic_field(OSThread, _unique_thread_id, uint64_t) #define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ \ /**********************/ \ - /* Posix Thread IDs */ \ + /* Thread IDs */ \ /**********************/ \ \ - declare_unsigned_integer_type(OSThread::thread_id_t) \ - declare_unsigned_integer_type(pthread_t) + declare_unsigned_integer_type(OSThread::thread_id_t) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff -r dee7c8b578c7 -r c3657d00e343 src/os_cpu/linux_x86/vm/os_linux_x86.cpp --- a/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -189,7 +189,7 @@ CAST_FROM_FN_PTR(address, os::current_frame)); if (os::is_first_C_frame(&myframe)) { // stack is not walkable - return frame(NULL, NULL, NULL); + return frame(); } else { return os::get_sender_for_C_frame(&myframe); } @@ -282,17 +282,6 @@ } #endif // AMD64 - if (TraceSignals) { - CodeBlob* cb = CodeCache::find_blob(pc); - if (cb != NULL && cb->is_nmethod()) { - nmethod* nm = (nmethod*)cb; - int rel = pc - nm->code_begin(); - tty->print_cr(err_msg("Implicit exception at %d of method %s", rel, nm->method()->name()->as_C_string())); - } else { - tty->print_cr("No code blob found for %x", pc); - } - } - // Handle ALL stack overflow variations here if (sig == SIGSEGV) { address addr = (address) info->si_addr; @@ -306,7 +295,6 @@ if (thread->thread_state() == _thread_in_Java) { // Throw a stack overflow exception. Guard pages will be reenabled // while unwinding the stack. - if (WizardMode) tty->print("implicit: %08x%08x\n", ((long long)pc) >> 32, pc); stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW); } else { // Thread was in the vm or native code. Return and try to finish. @@ -392,15 +380,8 @@ #endif // AMD64 } else if (sig == SIGSEGV && !MacroAssembler::needs_explicit_null_check((intptr_t)info->si_addr)) { - if (TraceSignals) { - tty->print_cr("Implicit exception continuation"); - } // Determination of interpreter/vtable stub/compiled code null exception stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL); - } else if (sig == SIGSEGV) { - if (TraceSignals) { - tty->print_cr("would have needed explicit null check %d", (intptr_t)info->si_addr); - } } } else if (thread->thread_state() == _thread_in_vm && sig == SIGBUS && /* info->si_code == BUS_OBJERR && */ diff -r dee7c8b578c7 -r c3657d00e343 src/os_cpu/windows_x86/vm/os_windows_x86.cpp --- a/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -70,7 +70,7 @@ extern LONG WINAPI topLevelExceptionFilter(_EXCEPTION_POINTERS* ); // Install a win32 structured exception handler around thread. -void os::os_exception_wrapper(java_call_t f, JavaValue* value, methodHandle* method, nmethod* nm, JavaCallArguments* args, Thread* thread) { +void os::os_exception_wrapper(java_call_t f, JavaValue* value, methodHandle* method, JavaCallArguments* args, Thread* thread) { __try { #ifndef AMD64 @@ -110,7 +110,7 @@ #endif // ASSERT #endif // !AMD64 - f(value, method, nm, args, thread); + f(value, method, args, thread); } __except(topLevelExceptionFilter((_EXCEPTION_POINTERS*)_exception_info())) { // Nothing to do. } @@ -399,7 +399,7 @@ typedef intptr_t* get_fp_func (); get_fp_func* func = CAST_TO_FN_PTR(get_fp_func*, StubRoutines::x86::get_previous_fp_entry()); - if (func == NULL) return frame(NULL, NULL, NULL); + if (func == NULL) return frame(); intptr_t* fp = (*func)(); #else intptr_t* fp = _get_previous_fp(); @@ -410,7 +410,7 @@ CAST_FROM_FN_PTR(address, os::current_frame)); if (os::is_first_C_frame(&myframe)) { // stack is not walkable - return frame(NULL, NULL, NULL); + return frame(); } else { return os::get_sender_for_C_frame(&myframe); } diff -r dee7c8b578c7 -r c3657d00e343 src/os_cpu/windows_x86/vm/threadLS_windows_x86.cpp --- a/src/os_cpu/windows_x86/vm/threadLS_windows_x86.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/os_cpu/windows_x86/vm/threadLS_windows_x86.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -39,7 +39,7 @@ // up the offset from FS of the thread pointer. void ThreadLocalStorage::generate_code_for_get_thread() { os::os_exception_wrapper( (java_call_t)call_wrapper_dummy, - NULL, NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL); } void ThreadLocalStorage::pd_init() { } diff -r dee7c8b578c7 -r c3657d00e343 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/GraphNode.java --- a/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/GraphNode.java Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/GraphNode.java Thu Mar 21 14:11:13 2013 +0100 @@ -23,8 +23,10 @@ */ package com.sun.hotspot.igv.coordinator; +import com.sun.hotspot.igv.coordinator.actions.CloneGraphAction; import com.sun.hotspot.igv.coordinator.actions.DiffGraphAction; import com.sun.hotspot.igv.coordinator.actions.DiffGraphCookie; +import com.sun.hotspot.igv.coordinator.actions.GraphCloneCookie; import com.sun.hotspot.igv.coordinator.actions.GraphOpenCookie; import com.sun.hotspot.igv.coordinator.actions.GraphRemoveCookie; import com.sun.hotspot.igv.data.InputGraph; @@ -72,6 +74,9 @@ // Action for diffing to the current graph content.add(new DiffGraphCookie(graph)); + + // Action for cloning to the current graph + content.add(new GraphCloneCookie(viewer, graph)); } @Override @@ -97,7 +102,7 @@ @Override public Action[] getActions(boolean b) { - return new Action[]{(Action) DiffGraphAction.findObject(DiffGraphAction.class, true), (Action) OpenAction.findObject(OpenAction.class, true)}; + return new Action[]{(Action) DiffGraphAction.findObject(DiffGraphAction.class, true), (Action) CloneGraphAction.findObject(CloneGraphAction.class, true), (Action) OpenAction.findObject(OpenAction.class, true)}; } @Override diff -r dee7c8b578c7 -r c3657d00e343 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/CloneGraphAction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/CloneGraphAction.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,89 @@ +/* + * 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.sun.hotspot.igv.coordinator.actions; + +import org.openide.nodes.Node; +import org.openide.util.HelpCtx; +import org.openide.util.actions.CookieAction; + +/** + * + * @author Thomas Wuerthinger + */ +public final class CloneGraphAction extends CookieAction { + + @Override + protected void performAction(Node[] activatedNodes) { + GraphCloneCookie c = activatedNodes[0].getCookie(GraphCloneCookie.class); + assert c != null; + c.openClone(); + } + + @Override + protected int mode() { + return CookieAction.MODE_EXACTLY_ONE; + } + + @Override + protected boolean enable(Node[] activatedNodes) { + boolean b = super.enable(activatedNodes); + if (b) { + assert activatedNodes.length == 1; + GraphCloneCookie c = activatedNodes[0].getCookie(GraphCloneCookie.class); + assert c != null; + return true; + } + + return false; + } + + @Override + public String getName() { + return "Open clone"; + } + + @Override + protected Class[] cookieClasses() { + return new Class[]{ + GraphCloneCookie.class + }; + } + + @Override + protected String iconResource() { + return "com/sun/hotspot/igv/coordinator/images/graph.png"; + } + + @Override + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + + @Override + protected boolean asynchronous() { + return false; + } +} + diff -r dee7c8b578c7 -r c3657d00e343 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/DiffGraphCookie.java --- a/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/DiffGraphCookie.java Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/DiffGraphCookie.java Thu Mar 21 14:11:13 2013 +0100 @@ -60,7 +60,7 @@ final GraphViewer viewer = Lookup.getDefault().lookup(GraphViewer.class); if (viewer != null) { InputGraph diffGraph = Difference.createDiffGraph(other, graph); - viewer.view(diffGraph); + viewer.view(diffGraph, true); } } } diff -r dee7c8b578c7 -r c3657d00e343 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/GraphCloneCookie.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/GraphCloneCookie.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,43 @@ +/* + * 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.sun.hotspot.igv.coordinator.actions; + +import com.sun.hotspot.igv.data.InputGraph; +import com.sun.hotspot.igv.data.services.GraphViewer; +import org.openide.nodes.Node; + +public class GraphCloneCookie implements Node.Cookie { + + private final GraphViewer viewer; + private final InputGraph graph; + + public GraphCloneCookie(GraphViewer viewer, InputGraph graph) { + this.viewer = viewer; + this.graph = graph; + } + + public void openClone() { + viewer.view(graph, true); + } +} diff -r dee7c8b578c7 -r c3657d00e343 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/GraphOpenCookie.java --- a/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/GraphOpenCookie.java Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/GraphOpenCookie.java Thu Mar 21 14:11:13 2013 +0100 @@ -39,6 +39,6 @@ @Override public void open() { - viewer.view(graph); + viewer.view(graph, false); } } diff -r dee7c8b578c7 -r c3657d00e343 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/services/GraphViewer.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/services/GraphViewer.java Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/services/GraphViewer.java Thu Mar 21 14:11:13 2013 +0100 @@ -31,5 +31,5 @@ */ public interface GraphViewer { - public void view(InputGraph graph); + public void view(InputGraph graph, boolean clone); } diff -r dee7c8b578c7 -r c3657d00e343 src/share/tools/IdealGraphVisualizer/Difference/src/com/sun/hotspot/igv/difference/Difference.java --- a/src/share/tools/IdealGraphVisualizer/Difference/src/com/sun/hotspot/igv/difference/Difference.java Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Difference/src/com/sun/hotspot/igv/difference/Difference.java Thu Mar 21 14:11:13 2013 +0100 @@ -207,12 +207,16 @@ InputNode nodeTo = inputNodeMap.get(a.getNode(to)); char fromIndex = e.getFromIndex(); char toIndex = e.getToIndex(); - - InputEdge newEdge = new InputEdge(fromIndex, toIndex, nodeFrom.getId(), nodeTo.getId()); - if (!newEdges.contains(newEdge)) { - markAsDeleted(newEdge); - newEdges.add(newEdge); - graph.addEdge(newEdge); + + if (nodeFrom == null || nodeTo == null) { + System.out.println("Unexpected edge : " + from + " -> " + to); + } else { + InputEdge newEdge = new InputEdge(fromIndex, toIndex, nodeFrom.getId(), nodeTo.getId()); + if (!newEdges.contains(newEdge)) { + markAsDeleted(newEdge); + newEdges.add(newEdge); + graph.addEdge(newEdge); + } } } @@ -224,17 +228,21 @@ char fromIndex = e.getFromIndex(); char toIndex = e.getToIndex(); - InputEdge newEdge = new InputEdge(fromIndex, toIndex, nodeFrom.getId(), nodeTo.getId()); - if (!newEdges.contains(newEdge)) { - markAsNew(newEdge); - newEdges.add(newEdge); - graph.addEdge(newEdge); + if (nodeFrom == null || nodeTo == null) { + System.out.println("Unexpected edge : " + from + " -> " + to); } else { - newEdges.remove(newEdge); - graph.removeEdge(newEdge); - markAsSame(newEdge); - newEdges.add(newEdge); - graph.addEdge(newEdge); + InputEdge newEdge = new InputEdge(fromIndex, toIndex, nodeFrom.getId(), nodeTo.getId()); + if (!newEdges.contains(newEdge)) { + markAsNew(newEdge); + newEdges.add(newEdge); + graph.addEdge(newEdge); + } else { + newEdges.remove(newEdge); + graph.removeEdge(newEdge); + markAsSame(newEdge); + newEdges.add(newEdge); + graph.addEdge(newEdge); + } } } diff -r dee7c8b578c7 -r c3657d00e343 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalCFGFilter.java --- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalCFGFilter.java Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalCFGFilter.java Thu Mar 21 14:11:13 2013 +0100 @@ -45,7 +45,6 @@ Set connectionsToRemove = new HashSet<>(); for (Figure f : d.getFigures()) { final String prop = f.getProperties().get("probability"); - if (prop == null) { figuresToRemove.add(f); } @@ -54,7 +53,15 @@ for (Figure f : d.getFigures()) { Properties p = f.getProperties(); - int predCount = Integer.parseInt(p.get("predecessorCount")); + int predCount; + String predCountString = p.get("predecessorCount"); + if (predCountString != null) { + predCount = Integer.parseInt(predCountString); + } else if (Boolean.parseBoolean(p.get("hasPredecessor"))) { + predCount = 1; + } else { + predCount = 0; + } for (InputSlot is : f.getInputSlots()) { if (is.getPosition() >= predCount && !"EndNode".equals(is.getProperties().get("class"))) { for (Connection c : is.getConnections()) { diff -r dee7c8b578c7 -r c3657d00e343 src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java --- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java Thu Mar 21 14:11:13 2013 +0100 @@ -58,7 +58,10 @@ for (Figure f : figures) { Properties p = f.getProperties(); int predCount; - if (Boolean.parseBoolean(p.get("hasPredecessor"))) { + String predCountString = p.get("predecessorCount"); + if (predCountString != null) { + predCount = Integer.parseInt(predCountString); + } else if (Boolean.parseBoolean(p.get("hasPredecessor"))) { predCount = 1; } else { predCount = 0; diff -r dee7c8b578c7 -r c3657d00e343 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java Thu Mar 21 14:11:13 2013 +0100 @@ -70,6 +70,10 @@ result.setData(this); return result; } + + public Group getGroup() { + return group; + } public void setData(DiagramViewModel newModel) { super.setData(newModel); diff -r dee7c8b578c7 -r c3657d00e343 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/GraphViewerImplementation.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/GraphViewerImplementation.java Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/GraphViewerImplementation.java Thu Mar 21 14:11:13 2013 +0100 @@ -27,6 +27,9 @@ import com.sun.hotspot.igv.data.services.GraphViewer; import com.sun.hotspot.igv.graph.Diagram; import com.sun.hotspot.igv.settings.Settings; +import org.openide.windows.Mode; +import org.openide.windows.TopComponent; +import org.openide.windows.WindowManager; /** * @@ -35,7 +38,24 @@ public class GraphViewerImplementation implements GraphViewer { @Override - public void view(InputGraph graph) { + public void view(InputGraph graph, boolean clone) { + + if (!clone) { + WindowManager manager = WindowManager.getDefault(); + for (Mode m : manager.getModes()) { + for (TopComponent t : manager.getOpenedTopComponents(m)) { + if (t instanceof EditorTopComponent) { + EditorTopComponent etc = (EditorTopComponent) t; + if (etc.getModel().getGroup().getGraphs().contains(graph)) { + etc.getModel().selectGraph(graph); + t.requestActive(); + return; + } + } + } + } + } + Diagram diagram = Diagram.createDiagram(graph, Settings.get().get(Settings.NODE_TEXT, Settings.NODE_TEXT_DEFAULT)); EditorTopComponent tc = new EditorTopComponent(diagram); tc.open(); diff -r dee7c8b578c7 -r c3657d00e343 src/share/tools/ProjectCreator/FileTreeCreatorVC10.java --- a/src/share/tools/ProjectCreator/FileTreeCreatorVC10.java Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/tools/ProjectCreator/FileTreeCreatorVC10.java Thu Mar 21 14:11:13 2013 +0100 @@ -50,7 +50,8 @@ if (addFile.equals(fileName)) { // supress any ignore // TODO - may need some adjustments - if (file.toAbsolutePath().toString().contains(cfg.get("Flavour"))) { + String relativePath = startDir.toUri().relativize(file.toUri()).getPath(); + if (relativePath.contains(cfg.get("Flavour"))) { currentFileAttr.removeFromIgnored(cfg); } } diff -r dee7c8b578c7 -r c3657d00e343 src/share/tools/whitebox/sun/hotspot/WhiteBox.java --- a/src/share/tools/whitebox/sun/hotspot/WhiteBox.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +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 sun.hotspot; -import java.security.BasicPermission; -import sun.hotspot.parser.DiagnosticCommand; - -public class WhiteBox { - - @SuppressWarnings("serial") - public static class WhiteBoxPermission extends BasicPermission { - public WhiteBoxPermission(String s) { - super(s); - } - } - - private WhiteBox() {} - private static final WhiteBox instance = new WhiteBox(); - private static native void registerNatives(); - - /** - * Returns the singleton WhiteBox instance. - * - * The returned WhiteBox object should be carefully guarded - * by the caller, since it can be used to read and write data - * at arbitrary memory addresses. It must never be passed to - * untrusted code. - */ - public synchronized static WhiteBox getWhiteBox() { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new WhiteBoxPermission("getInstance")); - } - return instance; - } - - static { - registerNatives(); - } - - // Memory - public native long getObjectAddress(Object o); - public native int getHeapOopSize(); - - // Runtime - // Make sure class name is in the correct format - public boolean isClassAlive(String name) { - return isClassAlive0(name.replace('.', '/')); - } - private native boolean isClassAlive0(String name); - - // G1 - public native boolean g1InConcurrentMark(); - public native boolean g1IsHumongous(Object o); - public native long g1NumFreeRegions(); - public native int g1RegionSize(); - public native Object[] parseCommandLine(String commandline, DiagnosticCommand[] args); -} diff -r dee7c8b578c7 -r c3657d00e343 src/share/tools/whitebox/sun/hotspot/parser/DiagnosticCommand.java --- a/src/share/tools/whitebox/sun/hotspot/parser/DiagnosticCommand.java Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -package sun.hotspot.parser; - -public class DiagnosticCommand { - - public enum DiagnosticArgumentType { - JLONG, BOOLEAN, STRING, NANOTIME, STRINGARRAY, MEMORYSIZE - } - - private String name; - private String desc; - private DiagnosticArgumentType type; - private boolean mandatory; - private String defaultValue; - - public DiagnosticCommand(String name, String desc, DiagnosticArgumentType type, - boolean mandatory, String defaultValue) { - this.name = name; - this.desc = desc; - this.type = type; - this.mandatory = mandatory; - this.defaultValue = defaultValue; - } - - public String getName() { - return name; - } - - public String getDesc() { - return desc; - } - - public DiagnosticArgumentType getType() { - return type; - } - - public boolean isMandatory() { - return mandatory; - } - - public String getDefaultValue() { - return defaultValue; - } -} diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/adlc/adlparse.cpp --- a/src/share/vm/adlc/adlparse.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/adlc/adlparse.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -168,7 +168,7 @@ // Check for block delimiter if ( (_curchar != '%') || ( next_char(), (_curchar != '{')) ) { - parse_err(SYNERR, "missing '%{' in instruction definition\n"); + parse_err(SYNERR, "missing '%%{' in instruction definition\n"); return; } next_char(); // Maintain the invariant @@ -253,7 +253,7 @@ } while(_curchar != '%'); next_char(); if (_curchar != '}') { - parse_err(SYNERR, "missing '%}' in instruction definition\n"); + parse_err(SYNERR, "missing '%%}' in instruction definition\n"); return; } // Check for "Set" form of chain rule @@ -423,7 +423,7 @@ skipws(); // Check for block delimiter if ((_curchar != '%') || (*(_ptr+1) != '{')) { // If not open block - parse_err(SYNERR, "missing '%c{' in operand definition\n","%"); + parse_err(SYNERR, "missing '%%{' in operand definition\n"); return; } next_char(); next_char(); // Skip over "%{" symbol @@ -483,7 +483,7 @@ } while(_curchar != '%'); next_char(); if (_curchar != '}') { - parse_err(SYNERR, "missing '%}' in operand definition\n"); + parse_err(SYNERR, "missing '%%}' in operand definition\n"); return; } // Add operand to tail of operand list @@ -1324,7 +1324,7 @@ // Check for block delimiter if ( (_curchar != '%') || ( next_char(), (_curchar != '{')) ) { - parse_err(SYNERR, "missing '%{' in pipeline definition\n"); + parse_err(SYNERR, "missing '%%{' in pipeline definition\n"); return; } next_char(); // Maintain the invariant @@ -1341,7 +1341,7 @@ skipws(); if ( (_curchar != '%') || ( next_char(), (_curchar != '{')) ) { - parse_err(SYNERR, "expected '%{'\n"); + parse_err(SYNERR, "expected '%%{'\n"); return; } next_char(); skipws(); @@ -1397,7 +1397,7 @@ skipws(); if ( (_curchar != '%') || ( next_char(), (_curchar != '{')) ) { - parse_err(SYNERR, "expected '%{'\n"); + parse_err(SYNERR, "expected '%%{'\n"); return; } next_char(); skipws(); @@ -1586,7 +1586,7 @@ if ( (_curchar != '%') || ( next_char(), (_curchar != '}')) ) { - parse_err(SYNERR, "expected '%}', found \"%c\"\n", _curchar); + parse_err(SYNERR, "expected '%%}', found \"%c\"\n", _curchar); } next_char(); skipws(); @@ -1612,7 +1612,7 @@ next_char(); if (_curchar != '}') { - parse_err(SYNERR, "missing \"%}\" in pipeline definition\n"); + parse_err(SYNERR, "missing \"%%}\" in pipeline definition\n"); return; } @@ -1775,7 +1775,7 @@ // Check for block delimiter if ( (_curchar != '%') || ( next_char(), (_curchar != '{')) ) { - parse_err(SYNERR, "missing \"%{\" in pipe_class definition\n"); + parse_err(SYNERR, "missing \"%%{\" in pipe_class definition\n"); return; } next_char(); @@ -2062,7 +2062,7 @@ next_char(); if (_curchar != '}') { - parse_err(SYNERR, "missing \"%}\" in pipe_class definition\n"); + parse_err(SYNERR, "missing \"%%}\" in pipe_class definition\n"); return; } @@ -3341,12 +3341,12 @@ char *disp = NULL; if (_curchar != '%') { - parse_err(SYNERR, "Missing '%{' for 'interface' block.\n"); + parse_err(SYNERR, "Missing '%%{' for 'interface' block.\n"); return NULL; } next_char(); // Skip '%' if (_curchar != '{') { - parse_err(SYNERR, "Missing '%{' for 'interface' block.\n"); + parse_err(SYNERR, "Missing '%%{' for 'interface' block.\n"); return NULL; } next_char(); // Skip '{' @@ -3354,7 +3354,7 @@ do { char *field = get_ident(); if (field == NULL) { - parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%}' ending interface.\n"); + parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n"); return NULL; } if ( strcmp(field,"base") == 0 ) { @@ -3370,13 +3370,13 @@ disp = interface_field_parse(); } else { - parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%}' ending interface.\n"); + parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n"); return NULL; } } while( _curchar != '%' ); next_char(); // Skip '%' if ( _curchar != '}' ) { - parse_err(SYNERR, "Missing '%}' for 'interface' block.\n"); + parse_err(SYNERR, "Missing '%%}' for 'interface' block.\n"); return NULL; } next_char(); // Skip '}' @@ -3403,12 +3403,12 @@ const char *greater_format = "gt"; if (_curchar != '%') { - parse_err(SYNERR, "Missing '%{' for 'cond_interface' block.\n"); + parse_err(SYNERR, "Missing '%%{' for 'cond_interface' block.\n"); return NULL; } next_char(); // Skip '%' if (_curchar != '{') { - parse_err(SYNERR, "Missing '%{' for 'cond_interface' block.\n"); + parse_err(SYNERR, "Missing '%%{' for 'cond_interface' block.\n"); return NULL; } next_char(); // Skip '{' @@ -3416,7 +3416,7 @@ do { char *field = get_ident(); if (field == NULL) { - parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%}' ending interface.\n"); + parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n"); return NULL; } if ( strcmp(field,"equal") == 0 ) { @@ -3438,13 +3438,13 @@ greater = interface_field_parse(&greater_format); } else { - parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%}' ending interface.\n"); + parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n"); return NULL; } } while( _curchar != '%' ); next_char(); // Skip '%' if ( _curchar != '}' ) { - parse_err(SYNERR, "Missing '%}' for 'interface' block.\n"); + parse_err(SYNERR, "Missing '%%}' for 'interface' block.\n"); return NULL; } next_char(); // Skip '}' @@ -3543,7 +3543,7 @@ } else if ((cnstr = find_cpp_block("match constructor")) == NULL ) { parse_err(SYNERR, "invalid construction of match rule\n" - "Missing ';' or invalid '%{' and '%}' constructor\n"); + "Missing ';' or invalid '%%{' and '%%}' constructor\n"); return NULL; // No MatchRule to return } if (_AD._adl_debug > 1) @@ -3646,7 +3646,7 @@ // Check for closing '"' and '%}' in format description skipws(); // Move to closing '%}' if ( _curchar != '%' ) { - parse_err(SYNERR, "non-blank characters between closing '\"' and '%' in format"); + parse_err(SYNERR, "non-blank characters between closing '\"' and '%%' in format"); return NULL; } } // Done with format description inside @@ -3654,7 +3654,7 @@ skipws(); // Past format description, at '%' if ( _curchar != '%' || *(_ptr+1) != '}' ) { - parse_err(SYNERR, "missing '%}' at end of format block"); + parse_err(SYNERR, "missing '%%}' at end of format block"); return NULL; } next_char(); // Move past the '%' @@ -3785,7 +3785,7 @@ skipws(); // Past format description, at '%' if ( _curchar != '%' || *(_ptr+1) != '}' ) { - parse_err(SYNERR, "missing '%}' at end of format block"); + parse_err(SYNERR, "missing '%%}' at end of format block"); return NULL; } next_char(); // Move past the '%' @@ -3834,7 +3834,7 @@ skipws(); // Skip leading whitespace if ((_curchar != '%') || (next_char(), (_curchar != '{')) ) { // If not open block - parse_err(SYNERR, "missing '%{' in expand definition\n"); + parse_err(SYNERR, "missing '%%{' in expand definition\n"); return(NULL); } next_char(); // Maintain the invariant @@ -3933,7 +3933,7 @@ } while(_curchar != '%'); next_char(); if (_curchar != '}') { - parse_err(SYNERR, "missing '%}' in expand rule definition\n"); + parse_err(SYNERR, "missing '%%}' in expand rule definition\n"); return(NULL); } next_char(); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/adlc/formssel.cpp --- a/src/share/vm/adlc/formssel.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/adlc/formssel.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -753,10 +753,11 @@ !strcmp(_matrule->_rChild->_opType,"DecodeNKlass") || !strcmp(_matrule->_rChild->_opType,"EncodePKlass") || !strcmp(_matrule->_rChild->_opType,"LoadN") || - !strcmp(_matrule->_rChild->_opType,"GetAndSetN") || !strcmp(_matrule->_rChild->_opType,"LoadNKlass") || !strcmp(_matrule->_rChild->_opType,"CreateEx") || // type of exception - !strcmp(_matrule->_rChild->_opType,"CheckCastPP")) ) return true; + !strcmp(_matrule->_rChild->_opType,"CheckCastPP") || + !strcmp(_matrule->_rChild->_opType,"GetAndSetP") || + !strcmp(_matrule->_rChild->_opType,"GetAndSetN")) ) return true; else if ( is_ideal_load() == Form::idealP ) return true; else if ( is_ideal_store() != Form::none ) return true; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/asm/macroAssembler.hpp --- a/src/share/vm/asm/macroAssembler.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/asm/macroAssembler.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -37,10 +37,10 @@ # include "assembler_zero.hpp" #endif #ifdef TARGET_ARCH_arm -# include "assembler_arm.hpp" +# include "macroAssembler_arm.hpp" #endif #ifdef TARGET_ARCH_ppc -# include "assembler_ppc.hpp" +# include "macroAssembler_ppc.hpp" #endif #endif // SHARE_VM_ASM_MACROASSEMBLER_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/asm/macroAssembler.inline.hpp --- a/src/share/vm/asm/macroAssembler.inline.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/asm/macroAssembler.inline.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -37,10 +37,10 @@ # include "assembler_zero.inline.hpp" #endif #ifdef TARGET_ARCH_arm -# include "assembler_arm.inline.hpp" +# include "macroAssembler_arm.inline.hpp" #endif #ifdef TARGET_ARCH_ppc -# include "assembler_ppc.inline.hpp" +# include "macroAssembler_ppc.inline.hpp" #endif #endif // SHARE_VM_ASM_MACROASSEMBLER_INLINE_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/c1/c1_CodeStubs.hpp --- a/src/share/vm/c1/c1_CodeStubs.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/c1/c1_CodeStubs.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -31,6 +31,7 @@ #include "c1/c1_LIR.hpp" #include "c1/c1_Runtime1.hpp" #include "utilities/array.hpp" +#include "utilities/macros.hpp" class CodeEmitInfo; class LIR_Assembler; @@ -515,7 +516,7 @@ }; ////////////////////////////////////////////////////////////////////////////////////////// -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Code stubs for Garbage-First barriers. class G1PreBarrierStub: public CodeStub { @@ -608,7 +609,7 @@ #endif // PRODUCT }; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS ////////////////////////////////////////////////////////////////////////////////////////// #endif // SHARE_VM_C1_C1_CODESTUBS_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -3667,11 +3667,12 @@ } // now perform tests that are based on flag settings - if (callee->force_inline() || callee->should_inline()) { - // ignore heuristic controls on inlining - if (callee->force_inline()) - print_inlining(callee, "force inline by annotation"); + if (callee->force_inline()) { + print_inlining(callee, "force inline by annotation"); + } else if (callee->should_inline()) { + print_inlining(callee, "force inline by CompileOracle"); } else { + // use heuristic controls on inlining if (inline_level() > MaxInlineLevel ) INLINE_BAILOUT("inlining too deep"); if (recursive_inline_level(callee) > MaxRecursiveInlineLevel) INLINE_BAILOUT("recursive inlining too deep"); if (callee->code_size_for_inlining() > max_inline_size() ) INLINE_BAILOUT("callee is too large"); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/c1/c1_IR.hpp --- a/src/share/vm/c1/c1_IR.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/c1/c1_IR.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -240,8 +240,8 @@ // reexecute allowed only for the topmost frame bool reexecute = topmost ? should_reexecute() : false; bool return_oop = false; // This flag will be ignored since it used only for C2 with escape analysis. - methodHandle null_mh; - recorder->describe_scope(pc_offset, null_mh, scope()->method(), bci(), reexecute, false, is_method_handle_invoke, return_oop, locvals, expvals, monvals); + bool rethrow_exception = false; + recorder->describe_scope(pc_offset, methodHandle(), scope()->method(), bci(), reexecute, rethrow_exception, is_method_handle_invoke, return_oop, locvals, expvals, monvals); } }; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/c1/c1_Instruction.cpp --- a/src/share/vm/c1/c1_Instruction.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/c1/c1_Instruction.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -188,7 +188,7 @@ ciType* LoadIndexed::declared_type() const { ciType* array_type = array()->declared_type(); - if (array_type == NULL) { + if (array_type == NULL || !array_type->is_loaded()) { return NULL; } assert(array_type->is_array_klass(), "what else?"); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/c1/c1_LIR.cpp --- a/src/share/vm/c1/c1_LIR.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/c1/c1_LIR.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -814,7 +814,7 @@ // only visit register parameters int n = opJavaCall->_arguments->length(); - for (int i = 0; i < n; i++) { + for (int i = opJavaCall->_receiver->is_valid() ? 1 : 0; i < n; i++) { if (!opJavaCall->_arguments->at(i)->is_pointer()) { do_input(*opJavaCall->_arguments->adr_at(i)); } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/c1/c1_LIRGenerator.cpp --- a/src/share/vm/c1/c1_LIRGenerator.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -35,9 +35,10 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/bitMap.inline.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/heapRegion.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef ASSERT #define __ gen()->lir(__FILE__, __LINE__)-> @@ -1417,12 +1418,12 @@ bool do_load, bool patch, CodeEmitInfo* info) { // Do the pre-write barrier, if any. switch (_bs->kind()) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case BarrierSet::G1SATBCT: case BarrierSet::G1SATBCTLogging: G1SATBCardTableModRef_pre_barrier(addr_opr, pre_val, do_load, patch, info); break; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS case BarrierSet::CardTableModRef: case BarrierSet::CardTableExtension: // No pre barriers @@ -1439,12 +1440,12 @@ void LIRGenerator::post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val) { switch (_bs->kind()) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case BarrierSet::G1SATBCT: case BarrierSet::G1SATBCTLogging: G1SATBCardTableModRef_post_barrier(addr, new_val); break; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS case BarrierSet::CardTableModRef: case BarrierSet::CardTableExtension: CardTableModRef_post_barrier(addr, new_val); @@ -1459,7 +1460,7 @@ } //////////////////////////////////////////////////////////////////////// -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void LIRGenerator::G1SATBCardTableModRef_pre_barrier(LIR_Opr addr_opr, LIR_Opr pre_val, bool do_load, bool patch, CodeEmitInfo* info) { @@ -1575,7 +1576,7 @@ __ branch_destination(slow->continuation()); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS //////////////////////////////////////////////////////////////////////// void LIRGenerator::CardTableModRef_post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val) { @@ -2181,7 +2182,7 @@ get_Object_unsafe(value, src.result(), off.result(), type, x->is_volatile()); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // We might be reading the value of the referent field of a // Reference object in order to attach it back to the live // object graph. If G1 is enabled then we need to record @@ -2311,7 +2312,7 @@ __ branch_destination(Lcont->label()); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS if (x->is_volatile() && os::is_MP()) __ membar_acquire(); } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/ci/ciCallProfile.hpp --- a/src/share/vm/ci/ciCallProfile.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/ci/ciCallProfile.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -61,7 +61,6 @@ // Note: The following predicates return false for invalid profiles: bool has_receiver(int i) const { return _limit > i; } int morphism() const { return _morphism; } - int limit() const { return _limit; } int count() const { return _count; } int receiver_count(int i) { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/ci/ciEnv.cpp --- a/src/share/vm/ci/ciEnv.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/ci/ciEnv.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -52,6 +52,7 @@ #include "runtime/reflection.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/dtrace.hpp" +#include "utilities/macros.hpp" #ifdef COMPILER1 #include "c1/c1_Runtime1.hpp" #endif @@ -596,10 +597,6 @@ assert (klass->is_instance_klass() || klass->is_array_klass(), "must be an instance or array klass "); return ciConstant(T_OBJECT, klass->java_mirror()); - } else if (tag.is_object()) { - oop obj = cpool->object_at(index); - ciObject* ciobj = get_object(obj); - return ciConstant(T_OBJECT, ciobj); } else if (tag.is_method_type()) { // must execute Java code to link this CP entry into cache[i].f1 ciSymbol* signature = get_symbol(cpool->method_type_signature_at(index)); @@ -1168,7 +1165,7 @@ void ciEnv::dump_replay_data(outputStream* out) { ASSERT_IN_VM; - + ResourceMark rm; #if INCLUDE_JVMTI out->print_cr("JvmtiExport can_access_local_variables %d", _jvmti_can_access_local_variables); out->print_cr("JvmtiExport can_hotswap_or_post_breakpoint %d", _jvmti_can_hotswap_or_post_breakpoint); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/ci/ciField.hpp --- a/src/share/vm/ci/ciField.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/ci/ciField.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -166,8 +166,6 @@ // at each point of access. bool will_link(ciInstanceKlass* accessing_klass, Bytecodes::Code bc); - bool will_link_from_vm(ciInstanceKlass* accessing_klass, - Bytecodes::Code bc); // Java access flags bool is_public () { return flags().is_public(); } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/ci/ciInstanceKlass.cpp --- a/src/share/vm/ci/ciInstanceKlass.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/ci/ciInstanceKlass.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -580,6 +580,7 @@ } void do_field(fieldDescriptor* fd) { if (fd->is_final() && !fd->has_initial_value()) { + ResourceMark rm; oop mirror = fd->field_holder()->java_mirror(); _out->print("staticfield %s %s %s ", _holder, fd->name()->as_quoted_ascii(), fd->signature()->as_quoted_ascii()); switch (fd->field_type()) { @@ -643,6 +644,8 @@ void ciInstanceKlass::dump_replay_data(outputStream* out) { ASSERT_IN_VM; + ResourceMark rm; + InstanceKlass* ik = get_instanceKlass(); ConstantPool* cp = ik->constants(); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/ci/ciMethod.cpp --- a/src/share/vm/ci/ciMethod.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/ci/ciMethod.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -977,7 +977,7 @@ // ciMethod::set_not_compilable // // Tell the VM that this method cannot be compiled at all. -void ciMethod::set_not_compilable() { +void ciMethod::set_not_compilable(const char* reason) { check_is_loaded(); VM_ENTRY_MARK; ciEnv* env = CURRENT_ENV; @@ -986,7 +986,7 @@ } else { _is_c2_compilable = false; } - get_Method()->set_not_compilable(env->comp_level()); + get_Method()->set_not_compilable(env->comp_level(), true, reason); } // ------------------------------------------------------------------ @@ -1178,6 +1178,7 @@ void ciMethod::dump_replay_data(outputStream* st) { ASSERT_IN_VM; + ResourceMark rm; Method* method = get_Method(); Klass* holder = method->method_holder(); st->print_cr("ciMethod %s %s %s %d %d %d %d %d", diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/ci/ciMethod.hpp --- a/src/share/vm/ci/ciMethod.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/ci/ciMethod.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -252,7 +252,7 @@ bool has_option(const char *option); bool can_be_compiled(); bool can_be_osr_compiled(int entry_bci); - void set_not_compilable(); + void set_not_compilable(const char* reason = NULL); bool has_compiled_code(); void log_nmethod_identity(xmlStream* log); bool is_not_reached(int bci); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/ci/ciMethodData.cpp --- a/src/share/vm/ci/ciMethodData.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/ci/ciMethodData.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -374,6 +374,7 @@ void ciMethodData::dump_replay_data(outputStream* out) { ASSERT_IN_VM; + ResourceMark rm; MethodData* mdo = get_MethodData(); Method* method = mdo->method(); Klass* holder = method->method_holder(); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/ci/ciObject.hpp --- a/src/share/vm/ci/ciObject.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/ci/ciObject.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -65,14 +65,12 @@ ciObject(Handle h); ciObject(ciKlass* klass); -public: jobject handle() const { return _handle; } // Get the VM oop that this object holds. oop get_oop() const { assert(_handle != NULL, "null oop"); return JNIHandles::resolve_non_null(_handle); } -protected: void init_flags_from(oop x); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/ci/ciReplay.cpp --- a/src/share/vm/ci/ciReplay.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/ci/ciReplay.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -30,6 +30,7 @@ #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "utilities/copy.hpp" +#include "utilities/macros.hpp" #ifndef PRODUCT diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/ci/ciSymbol.hpp --- a/src/share/vm/ci/ciSymbol.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/ci/ciSymbol.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -48,7 +48,7 @@ private: const vmSymbols::SID _sid; - DEBUG_ONLY( bool sid_ok() { return true;/*vmSymbols::find_sid(get_symbol()) == _sid;*/ } ) + DEBUG_ONLY( bool sid_ok() { return vmSymbols::find_sid(get_symbol()) == _sid; } ) ciSymbol(Symbol* s); // normal case, for symbols not mentioned in vmSymbols ciSymbol(Symbol* s, vmSymbols::SID sid); // for use with vmSymbols diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/classfile/classFileParser.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1856,6 +1856,154 @@ #define MAX_CODE_SIZE 65535 #define INITIAL_MAX_LVT_NUMBER 256 +/* Copy class file LVT's/LVTT's into the HotSpot internal LVT. + * + * Rules for LVT's and LVTT's are: + * - There can be any number of LVT's and LVTT's. + * - If there are n LVT's, it is the same as if there was just + * one LVT containing all the entries from the n LVT's. + * - There may be no more than one LVT entry per local variable. + * Two LVT entries are 'equal' if these fields are the same: + * start_pc, length, name, slot + * - There may be no more than one LVTT entry per each LVT entry. + * Each LVTT entry has to match some LVT entry. + * - HotSpot internal LVT keeps natural ordering of class file LVT entries. + */ +void ClassFileParser::copy_localvariable_table(ConstMethod* cm, + int lvt_cnt, + u2* localvariable_table_length, + u2** localvariable_table_start, + int lvtt_cnt, + u2* localvariable_type_table_length, + u2** localvariable_type_table_start, + TRAPS) { + + LVT_Hash** lvt_Hash = NEW_RESOURCE_ARRAY(LVT_Hash*, HASH_ROW_SIZE); + initialize_hashtable(lvt_Hash); + + // To fill LocalVariableTable in + Classfile_LVT_Element* cf_lvt; + LocalVariableTableElement* lvt = cm->localvariable_table_start(); + + for (int tbl_no = 0; tbl_no < lvt_cnt; tbl_no++) { + cf_lvt = (Classfile_LVT_Element *) localvariable_table_start[tbl_no]; + for (int idx = 0; idx < localvariable_table_length[tbl_no]; idx++, lvt++) { + copy_lvt_element(&cf_lvt[idx], lvt); + // If no duplicates, add LVT elem in hashtable lvt_Hash. + if (LVT_put_after_lookup(lvt, lvt_Hash) == false + && _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(), + CHECK); + } + } + } + + // To merge LocalVariableTable and LocalVariableTypeTable + Classfile_LVT_Element* cf_lvtt; + LocalVariableTableElement lvtt_elem; + + for (int tbl_no = 0; tbl_no < lvtt_cnt; tbl_no++) { + cf_lvtt = (Classfile_LVT_Element *) localvariable_type_table_start[tbl_no]; + for (int idx = 0; idx < localvariable_type_table_length[tbl_no]; idx++) { + copy_lvt_element(&cf_lvtt[idx], &lvtt_elem); + int index = hash(&lvtt_elem); + LVT_Hash* entry = LVT_lookup(&lvtt_elem, index, lvt_Hash); + 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(), + 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(), + CHECK); + } else { + // to add generic signatures into LocalVariableTable + entry->_elem->signature_cp_index = lvtt_elem.descriptor_cp_index; + } + } + } + clear_hashtable(lvt_Hash); +} + + +void ClassFileParser::copy_method_annotations(ClassLoaderData* loader_data, + ConstMethod* cm, + u1* runtime_visible_annotations, + int runtime_visible_annotations_length, + u1* runtime_invisible_annotations, + int runtime_invisible_annotations_length, + u1* runtime_visible_parameter_annotations, + int runtime_visible_parameter_annotations_length, + u1* runtime_invisible_parameter_annotations, + int runtime_invisible_parameter_annotations_length, + u1* runtime_visible_type_annotations, + int runtime_visible_type_annotations_length, + u1* runtime_invisible_type_annotations, + int runtime_invisible_type_annotations_length, + u1* annotation_default, + int annotation_default_length, + TRAPS) { + + AnnotationArray* a; + + if (runtime_visible_annotations_length + + runtime_invisible_annotations_length > 0) { + a = assemble_annotations(loader_data, + runtime_visible_annotations, + runtime_visible_annotations_length, + runtime_invisible_annotations, + runtime_invisible_annotations_length, + CHECK); + cm->set_method_annotations(a); + } + + if (runtime_visible_parameter_annotations_length + + runtime_invisible_parameter_annotations_length > 0) { + a = assemble_annotations(loader_data, + runtime_visible_parameter_annotations, + runtime_visible_parameter_annotations_length, + runtime_invisible_parameter_annotations, + runtime_invisible_parameter_annotations_length, + CHECK); + cm->set_parameter_annotations(a); + } + + if (annotation_default_length > 0) { + a = assemble_annotations(loader_data, + annotation_default, + annotation_default_length, + NULL, + 0, + CHECK); + cm->set_default_annotations(a); + } + + if (runtime_visible_type_annotations_length + + runtime_invisible_type_annotations_length > 0) { + a = assemble_annotations(loader_data, + runtime_visible_type_annotations, + runtime_visible_type_annotations_length, + runtime_invisible_type_annotations, + runtime_invisible_type_annotations_length, + CHECK); + cm->set_type_annotations(a); + } +} + + // Note: the parse_method below is big and clunky because all parsing of the code and exceptions // attribute is inlined. This is cumbersome to avoid since we inline most of the parts in the // Method* to save footprint, so we only know the size of the resulting Method* when the @@ -1869,10 +2017,6 @@ constantPoolHandle cp, bool is_interface, AccessFlags *promoted_flags, - AnnotationArray** method_annotations, - AnnotationArray** method_parameter_annotations, - AnnotationArray** method_default_annotations, - AnnotationArray** method_type_annotations, TRAPS) { ClassFileStream* cfs = stream(); methodHandle nullHandle; @@ -1947,6 +2091,8 @@ u2** localvariable_type_table_start; u2 method_parameters_length = 0; u1* method_parameters_data = NULL; + bool method_parameters_seen = false; + bool method_parameters_four_byte_flags; bool parsed_code_attribute = false; bool parsed_checked_exceptions_attribute = false; bool parsed_stackmap_attribute = false; @@ -2157,21 +2303,31 @@ method_attribute_length, cp, CHECK_(nullHandle)); } else if (method_attribute_name == vmSymbols::tag_method_parameters()) { + // reject multiple method parameters + if (method_parameters_seen) { + classfile_parse_error("Multiple MethodParameters attributes in class file %s", CHECK_(nullHandle)); + } + method_parameters_seen = true; method_parameters_length = cfs->get_u1_fast(); // Track the actual size (note: this is written for clarity; a // decent compiler will CSE and constant-fold this into a single // expression) - u2 actual_size = 1; + // Use the attribute length to figure out the size of flags + if (method_attribute_length == (method_parameters_length * 6u) + 1u) { + method_parameters_four_byte_flags = true; + } else if (method_attribute_length == (method_parameters_length * 4u) + 1u) { + method_parameters_four_byte_flags = false; + } else { + classfile_parse_error( + "Invalid MethodParameters method attribute length %u in class file", + method_attribute_length, CHECK_(nullHandle)); + } method_parameters_data = cfs->get_u1_buffer(); - actual_size += 2 * method_parameters_length; cfs->skip_u2_fast(method_parameters_length); - actual_size += 4 * method_parameters_length; - cfs->skip_u4_fast(method_parameters_length); - // Enforce attribute length - if (method_attribute_length != actual_size) { - classfile_parse_error( - "Invalid MethodParameters method attribute length %u in class file %s", - method_attribute_length, CHECK_(nullHandle)); + if (method_parameters_four_byte_flags) { + cfs->skip_u4_fast(method_parameters_length); + } else { + cfs->skip_u2_fast(method_parameters_length); } // ignore this attribute if it cannot be reflected if (!SystemDictionary::Parameter_klass_loaded()) @@ -2261,10 +2417,24 @@ } // All sizing information for a Method* is finally available, now create it + InlineTableSizes sizes( + total_lvt_length, + linenumber_table_length, + exception_table_length, + checked_exceptions_length, + method_parameters_length, + generic_signature_index, + runtime_visible_annotations_length + + runtime_invisible_annotations_length, + runtime_visible_parameter_annotations_length + + runtime_invisible_parameter_annotations_length, + runtime_visible_type_annotations_length + + runtime_invisible_type_annotations_length, + annotation_default_length, + 0); + Method* m = Method::allocate( - loader_data, code_length, access_flags, linenumber_table_length, - total_lvt_length, exception_table_length, checked_exceptions_length, - method_parameters_length, generic_signature_index, + loader_data, code_length, access_flags, &sizes, ConstMethod::NORMAL, CHECK_(nullHandle)); ClassLoadingService::add_class_method_size(m->size()*HeapWordSize); @@ -2316,15 +2486,16 @@ // Copy method parameters if (method_parameters_length > 0) { MethodParametersElement* elem = m->constMethod()->method_parameters_start(); - for(int i = 0; i < method_parameters_length; i++) { - elem[i].name_cp_index = - Bytes::get_Java_u2(method_parameters_data); + for (int i = 0; i < method_parameters_length; i++) { + elem[i].name_cp_index = Bytes::get_Java_u2(method_parameters_data); method_parameters_data += 2; - u4 flags = Bytes::get_Java_u4(method_parameters_data); - // This caused an alignment fault on Sparc, if flags was a u4 - elem[i].flags_lo = extract_low_short_from_int(flags); - elem[i].flags_hi = extract_high_short_from_int(flags); - method_parameters_data += 4; + if (method_parameters_four_byte_flags) { + elem[i].flags = Bytes::get_Java_u4(method_parameters_data); + method_parameters_data += 4; + } else { + elem[i].flags = Bytes::get_Java_u2(method_parameters_data); + method_parameters_data += 2; + } } } @@ -2334,107 +2505,37 @@ copy_u2_with_conversion((u2*) m->checked_exceptions_start(), checked_exceptions_start, size); } - /* Copy class file LVT's/LVTT's into the HotSpot internal LVT. - * - * Rules for LVT's and LVTT's are: - * - There can be any number of LVT's and LVTT's. - * - If there are n LVT's, it is the same as if there was just - * one LVT containing all the entries from the n LVT's. - * - There may be no more than one LVT entry per local variable. - * Two LVT entries are 'equal' if these fields are the same: - * start_pc, length, name, slot - * - There may be no more than one LVTT entry per each LVT entry. - * Each LVTT entry has to match some LVT entry. - * - HotSpot internal LVT keeps natural ordering of class file LVT entries. - */ + // Copy class file LVT's/LVTT's into the HotSpot internal LVT. if (total_lvt_length > 0) { - int tbl_no, idx; - promoted_flags->set_has_localvariable_table(); - - LVT_Hash** lvt_Hash = NEW_RESOURCE_ARRAY(LVT_Hash*, HASH_ROW_SIZE); - initialize_hashtable(lvt_Hash); - - // To fill LocalVariableTable in - Classfile_LVT_Element* cf_lvt; - LocalVariableTableElement* lvt = m->localvariable_table_start(); - - for (tbl_no = 0; tbl_no < lvt_cnt; tbl_no++) { - cf_lvt = (Classfile_LVT_Element *) localvariable_table_start[tbl_no]; - for (idx = 0; idx < localvariable_table_length[tbl_no]; idx++, lvt++) { - copy_lvt_element(&cf_lvt[idx], lvt); - // If no duplicates, add LVT elem in hashtable lvt_Hash. - if (LVT_put_after_lookup(lvt, lvt_Hash) == false - && _need_verify - && _major_version >= JAVA_1_5_VERSION ) { - clear_hashtable(lvt_Hash); - classfile_parse_error("Duplicated LocalVariableTable attribute " - "entry for '%s' in class file %s", - cp->symbol_at(lvt->name_cp_index)->as_utf8(), - CHECK_(nullHandle)); - } - } - } - - // To merge LocalVariableTable and LocalVariableTypeTable - Classfile_LVT_Element* cf_lvtt; - LocalVariableTableElement lvtt_elem; - - for (tbl_no = 0; tbl_no < lvtt_cnt; tbl_no++) { - cf_lvtt = (Classfile_LVT_Element *) localvariable_type_table_start[tbl_no]; - for (idx = 0; idx < localvariable_type_table_length[tbl_no]; idx++) { - copy_lvt_element(&cf_lvtt[idx], &lvtt_elem); - int index = hash(&lvtt_elem); - LVT_Hash* entry = LVT_lookup(&lvtt_elem, index, lvt_Hash); - if (entry == NULL) { - if (_need_verify) { - clear_hashtable(lvt_Hash); - 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(), - CHECK_(nullHandle)); - } - } else if (entry->_elem->signature_cp_index != 0 && _need_verify) { - clear_hashtable(lvt_Hash); - classfile_parse_error("Duplicated LocalVariableTypeTable attribute " - "entry for '%s' in class file %s", - cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(), - CHECK_(nullHandle)); - } else { - // to add generic signatures into LocalVariableTable - entry->_elem->signature_cp_index = lvtt_elem.descriptor_cp_index; - } - } - } - clear_hashtable(lvt_Hash); + copy_localvariable_table(m->constMethod(), lvt_cnt, + localvariable_table_length, + localvariable_table_start, + lvtt_cnt, + localvariable_type_table_length, + localvariable_type_table_start, CHECK_NULL); } if (parsed_annotations.has_any_annotations()) parsed_annotations.apply_to(m); - *method_annotations = assemble_annotations(loader_data, - runtime_visible_annotations, - runtime_visible_annotations_length, - runtime_invisible_annotations, - runtime_invisible_annotations_length, - CHECK_(nullHandle)); - *method_parameter_annotations = assemble_annotations(loader_data, - runtime_visible_parameter_annotations, - runtime_visible_parameter_annotations_length, - runtime_invisible_parameter_annotations, - runtime_invisible_parameter_annotations_length, - CHECK_(nullHandle)); - *method_default_annotations = assemble_annotations(loader_data, - annotation_default, - annotation_default_length, - NULL, - 0, - CHECK_(nullHandle)); - *method_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_(nullHandle)); + + // Copy annotations + copy_method_annotations(loader_data, m->constMethod(), + runtime_visible_annotations, + runtime_visible_annotations_length, + runtime_invisible_annotations, + runtime_invisible_annotations_length, + runtime_visible_parameter_annotations, + runtime_visible_parameter_annotations_length, + runtime_invisible_parameter_annotations, + runtime_invisible_parameter_annotations_length, + runtime_visible_type_annotations, + runtime_visible_type_annotations_length, + runtime_invisible_type_annotations, + runtime_invisible_type_annotations_length, + annotation_default, + annotation_default_length, + CHECK_NULL); if (name == vmSymbols::finalize_method_name() && signature == vmSymbols::void_method_signature()) { @@ -2450,6 +2551,7 @@ _has_vanilla_constructor = true; } + NOT_PRODUCT(m->verify()); return m; } @@ -2463,17 +2565,9 @@ bool is_interface, AccessFlags* promoted_flags, bool* has_final_method, - Array** methods_annotations, - Array** methods_parameter_annotations, - Array** methods_default_annotations, - Array** methods_type_annotations, bool* has_default_methods, TRAPS) { ClassFileStream* cfs = stream(); - AnnotationArray* method_annotations = NULL; - AnnotationArray* method_parameter_annotations = NULL; - AnnotationArray* method_default_annotations = NULL; - AnnotationArray* method_type_annotations = NULL; cfs->guarantee_more(2, CHECK_NULL); // length u2 length = cfs->get_u2_fast(); if (length == 0) { @@ -2487,10 +2581,6 @@ methodHandle method = parse_method(loader_data, cp, is_interface, promoted_flags, - &method_annotations, - &method_parameter_annotations, - &method_default_annotations, - &method_type_annotations, CHECK_NULL); if (method->is_final()) { @@ -2501,38 +2591,6 @@ *has_default_methods = true; } methods->at_put(index, method()); - - if (method_annotations != NULL) { - if (*methods_annotations == NULL) { - *methods_annotations = - MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); - } - (*methods_annotations)->at_put(index, method_annotations); - } - - if (method_parameter_annotations != NULL) { - if (*methods_parameter_annotations == NULL) { - *methods_parameter_annotations = - MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); - } - (*methods_parameter_annotations)->at_put(index, method_parameter_annotations); - } - - if (method_default_annotations != NULL) { - if (*methods_default_annotations == NULL) { - *methods_default_annotations = - MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); - } - (*methods_default_annotations)->at_put(index, method_default_annotations); - } - - if (method_type_annotations != NULL) { - if (*methods_type_annotations == NULL) { - *methods_type_annotations = - MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL); - } - (*methods_type_annotations)->at_put(index, method_type_annotations); - } } if (_need_verify && length > 1) { @@ -2565,11 +2623,7 @@ Array* ClassFileParser::sort_methods(ClassLoaderData* loader_data, Array* methods, - Array* methods_annotations, - Array* methods_parameter_annotations, - Array* methods_default_annotations, - Array* methods_type_annotations, - TRAPS) { + TRAPS) { int length = methods->length(); // If JVMTI original method ordering or sharing is enabled we have to // remember the original class file ordering. @@ -2585,10 +2639,7 @@ } // Sort method array by ascending method name (for faster lookups & vtable construction) // Note that the ordering is not alphabetical, see Symbol::fast_compare - Method::sort_methods(methods, methods_annotations, - methods_parameter_annotations, - methods_default_annotations, - methods_type_annotations); + Method::sort_methods(methods); // If JVMTI original method ordering or sharing is enabled construct int // array remembering the original ordering @@ -3035,9 +3086,6 @@ k->set_source_debug_extension(_sde_buffer, _sde_length); } k->set_inner_classes(_inner_classes); - if (_annotations != NULL) { - k->annotations()->set_class_annotations(_annotations); - } } AnnotationArray* ClassFileParser::assemble_annotations(ClassLoaderData* loader_data, @@ -3348,19 +3396,10 @@ bool has_final_method = false; AccessFlags promoted_flags; promoted_flags.set_flags(0); - - Array* methods_annotations = NULL; - Array* methods_parameter_annotations = NULL; - Array* methods_default_annotations = NULL; - Array* methods_type_annotations = NULL; Array* methods = parse_methods(loader_data, cp, access_flags.is_interface(), &promoted_flags, &has_final_method, - &methods_annotations, - &methods_parameter_annotations, - &methods_default_annotations, - &methods_type_annotations, &has_default_methods, CHECK_(nullHandle)); @@ -3419,10 +3458,6 @@ // sort methods Array* method_ordering = sort_methods(loader_data, methods, - methods_annotations, - methods_parameter_annotations, - methods_default_annotations, - methods_type_annotations, CHECK_(nullHandle)); // promote flags from parse_methods() to the klass' flags @@ -4022,7 +4057,6 @@ const unsigned int total_oop_map_count = compute_oop_map_count(super_klass, nonstatic_oop_map_count, first_nonstatic_oop_offset); - // Compute reference type ReferenceType rt; if (super_klass() == NULL) { @@ -4044,7 +4078,7 @@ access_flags, name, super_klass(), - host_klass, + !host_klass.is_null(), CHECK_(nullHandle)); // Add all classes to our internal class loader list here, @@ -4090,31 +4124,15 @@ if (is_anonymous()) // I am well known to myself cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve - // Allocate an annotation type if needed. - if (fields_annotations != NULL || - methods_annotations != NULL || - methods_parameter_annotations != NULL || - methods_default_annotations != NULL || - fields_type_annotations != NULL || - methods_type_annotations != NULL) { - Annotations* anno = Annotations::allocate(loader_data, - fields_annotations, methods_annotations, - methods_parameter_annotations, - methods_default_annotations, CHECK_(nullHandle)); - this_klass->set_annotations(anno); - } else { - this_klass->set_annotations(NULL); - } - - if (fields_type_annotations != NULL || - methods_type_annotations != NULL) { - assert(this_klass->annotations() != NULL, "annotations should have been allocated"); - Annotations* anno = Annotations::allocate(loader_data, - fields_type_annotations, - methods_type_annotations, - NULL, - NULL, CHECK_(nullHandle)); - this_klass->annotations()->set_type_annotations(anno); + // 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); @@ -4140,27 +4158,8 @@ // Fill in field values obtained by parse_classfile_attributes if (parsed_annotations.has_any_annotations()) parsed_annotations.apply_to(this_klass); - - // Create annotations - if (_annotations != NULL && this_klass->annotations() == NULL) { - Annotations* anno = Annotations::allocate(loader_data, CHECK_NULL); - this_klass->set_annotations(anno); - } apply_parsed_class_attributes(this_klass); - // Create type annotations - if (_type_annotations != NULL) { - if (this_klass->annotations() == NULL) { - Annotations* anno = Annotations::allocate(loader_data, CHECK_NULL); - this_klass->set_annotations(anno); - } - if (this_klass->annotations()->type_annotations() == NULL) { - Annotations* anno = Annotations::allocate(loader_data, CHECK_NULL); - this_klass->annotations()->set_type_annotations(anno); - } - this_klass->annotations()->type_annotations()->set_class_annotations(_type_annotations); - } - // Miranda methods if ((num_miranda_methods > 0) || // if this class introduced new miranda methods or diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/classfile/classFileParser.hpp --- a/src/share/vm/classfile/classFileParser.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/classfile/classFileParser.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -199,29 +199,17 @@ constantPoolHandle cp, bool is_interface, AccessFlags* promoted_flags, - AnnotationArray** method_annotations, - AnnotationArray** method_parameter_annotations, - AnnotationArray** method_default_annotations, - AnnotationArray** method_type_annotations, TRAPS); Array* parse_methods(ClassLoaderData* loader_data, constantPoolHandle cp, bool is_interface, AccessFlags* promoted_flags, bool* has_final_method, - Array** methods_annotations, - Array** methods_parameter_annotations, - Array** methods_default_annotations, - Array** methods_type_annotations, bool* has_default_method, TRAPS); Array* sort_methods(ClassLoaderData* loader_data, Array* methods, - Array* methods_annotations, - Array* methods_parameter_annotations, - Array* methods_default_annotations, - Array* methods_type_annotations, - TRAPS); + TRAPS); u2* parse_exception_table(ClassLoaderData* loader_data, u4 code_length, u4 exception_table_length, constantPoolHandle cp, TRAPS); @@ -377,6 +365,32 @@ : cp->tag_at(index).is_klass_reference()); } + void copy_localvariable_table(ConstMethod* cm, int lvt_cnt, + u2* localvariable_table_length, + u2** localvariable_table_start, + int lvtt_cnt, + u2* localvariable_type_table_length, + u2** localvariable_type_table_start, + TRAPS); + + void copy_method_annotations(ClassLoaderData* loader_data, + ConstMethod* cm, + u1* runtime_visible_annotations, + int runtime_visible_annotations_length, + u1* runtime_invisible_annotations, + int runtime_invisible_annotations_length, + u1* runtime_visible_parameter_annotations, + int runtime_visible_parameter_annotations_length, + u1* runtime_invisible_parameter_annotations, + int runtime_invisible_parameter_annotations_length, + u1* runtime_visible_type_annotations, + int runtime_visible_type_annotations_length, + u1* runtime_invisible_type_annotations, + int runtime_invisible_type_annotations_length, + u1* annotation_default, + int annotation_default_length, + TRAPS); + public: // Constructor ClassFileParser(ClassFileStream* st) { set_stream(st); } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/classfile/classLoader.cpp --- a/src/share/vm/classfile/classLoader.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/classfile/classLoader.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -442,23 +442,10 @@ void ClassLoader::setup_bootstrap_search_path() { assert(_first_entry == NULL, "should not setup bootstrap class search path twice"); char* sys_class_path = os::strdup(Arguments::get_sysclasspath()); -#ifdef GRAAL - char* compiler_class_path = os::strdup(Arguments::get_compilerclasspath()); -#endif if (TraceClassLoading && Verbose) { tty->print_cr("[Bootstrap loader class path=%s]", sys_class_path); -#ifdef GRAAL - tty->print_cr("[Compiler loader class path=%s]", compiler_class_path); -#endif } - setup_bootstrap_search_path(sys_class_path); -#ifdef GRAAL - setup_bootstrap_search_path(compiler_class_path); -#endif -} - -void ClassLoader::setup_bootstrap_search_path(char* sys_class_path) { int len = (int)strlen(sys_class_path); int end = 0; @@ -908,23 +895,7 @@ PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(), ((JavaThread*) THREAD)->get_thread_stat()->perf_timers_addr(), PerfClassTraceTime::CLASS_LOAD); - ClassPathEntry* e = _first_entry; - while (e != NULL) { - stream = e->open_stream(name); - if (stream != NULL) { - break; - } - e = e->next(); - ++classpath_index; - } - } - - if (stream == NULL && !(THREAD->is_Compiler_thread())) { - classpath_index = 0; - PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(), - ((JavaThread*) THREAD)->get_thread_stat()->perf_timers_addr(), - PerfClassTraceTime::CLASS_LOAD); - ClassPathEntry* e = _first_entry; + ClassPathEntry* e = _first_entry; while (e != NULL) { stream = e->open_stream(name); if (stream != NULL) { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/classfile/classLoader.hpp --- a/src/share/vm/classfile/classLoader.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/classfile/classLoader.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -206,7 +206,6 @@ // Initialization static void setup_meta_index(); static void setup_bootstrap_search_path(); - static void setup_bootstrap_search_path(char* sys_class_path); static void load_zip_library(); static void create_class_path_entry(char *path, struct stat st, ClassPathEntry **new_entry, bool lazy); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/classfile/classLoaderData.cpp --- a/src/share/vm/classfile/classLoaderData.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/classfile/classLoaderData.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,11 +50,12 @@ #include "classfile/classLoaderData.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/metadataOnStackMark.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "memory/metadataFactory.hpp" #include "memory/metaspaceShared.hpp" -#include "prims/jvmtiRedefineClasses.hpp" +#include "memory/oopFactory.hpp" #include "runtime/jniHandles.hpp" #include "runtime/mutex.hpp" #include "runtime/safepoint.hpp" @@ -723,13 +724,13 @@ } MetaspaceAux::dump(out); } +#endif // PRODUCT void ClassLoaderData::print_value_on(outputStream* out) const { if (class_loader() == NULL) { - out->print_cr("NULL class_loader"); + out->print("NULL class_loader"); } else { out->print("class loader "PTR_FORMAT, this); class_loader()->print_value_on(out); } } -#endif // PRODUCT diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/classfile/classLoaderData.hpp --- a/src/share/vm/classfile/classLoaderData.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/classfile/classLoaderData.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -220,7 +220,7 @@ void set_jmethod_ids(JNIMethodBlock* new_block) { _jmethod_ids = new_block; } void print_value() { print_value_on(tty); } - void print_value_on(outputStream* out) const PRODUCT_RETURN; + void print_value_on(outputStream* out) const; void dump(outputStream * const out) PRODUCT_RETURN; void verify(); const char* loader_name(); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/classfile/defaultMethods.cpp --- a/src/share/vm/classfile/defaultMethods.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/classfile/defaultMethods.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1146,9 +1146,10 @@ address code_start = static_cast
(bytecodes->adr_at(0)); int code_length = bytecodes->length(); + InlineTableSizes sizes; Method* m = Method::allocate(cp->pool_holder()->class_loader_data(), - code_length, flags, 0, 0, 0, 0, 0, 0, + code_length, flags, &sizes, mt, CHECK_NULL); m->set_constants(NULL); // This will get filled in later @@ -1285,33 +1286,15 @@ enum { ANNOTATIONS, PARAMETERS, DEFAULTS, NUM_ARRAYS }; - Array* original_annots[NUM_ARRAYS] = { NULL }; - Array* original_methods = klass->methods(); - Annotations* annots = klass->annotations(); - if (annots != NULL) { - original_annots[ANNOTATIONS] = annots->methods_annotations(); - original_annots[PARAMETERS] = annots->methods_parameter_annotations(); - original_annots[DEFAULTS] = annots->methods_default_annotations(); - } - Array* original_ordering = klass->method_ordering(); Array* merged_ordering = Universe::the_empty_int_array(); int new_size = klass->methods()->length() + new_methods->length(); - Array* merged_annots[NUM_ARRAYS]; - Array* merged_methods = MetadataFactory::new_array( klass->class_loader_data(), new_size, NULL, CHECK); - for (int i = 0; i < NUM_ARRAYS; ++i) { - if (original_annots[i] != NULL) { - merged_annots[i] = MetadataFactory::new_array( - klass->class_loader_data(), new_size, CHECK); - } else { - merged_annots[i] = NULL; - } - } + if (original_ordering != NULL && original_ordering->length() > 0) { merged_ordering = MetadataFactory::new_array( klass->class_loader_data(), new_size, CHECK); @@ -1338,12 +1321,6 @@ (new_method == NULL || orig_method->name() < new_method->name())) { merged_methods->at_put(i, orig_method); original_methods->at_put(orig_idx, NULL); - for (int j = 0; j < NUM_ARRAYS; ++j) { - if (merged_annots[j] != NULL) { - merged_annots[j]->at_put(i, original_annots[j]->at(orig_idx)); - original_annots[j]->at_put(orig_idx, NULL); - } - } if (merged_ordering->length() > 0) { merged_ordering->at_put(i, original_ordering->at(orig_idx)); } @@ -1372,21 +1349,9 @@ // Replace klass methods with new merged lists klass->set_methods(merged_methods); - if (annots != NULL) { - annots->set_methods_annotations(merged_annots[ANNOTATIONS]); - annots->set_methods_parameter_annotations(merged_annots[PARAMETERS]); - annots->set_methods_default_annotations(merged_annots[DEFAULTS]); - } else { - assert(merged_annots[ANNOTATIONS] == NULL, "Must be"); - assert(merged_annots[PARAMETERS] == NULL, "Must be"); - assert(merged_annots[DEFAULTS] == NULL, "Must be"); - } ClassLoaderData* cld = klass->class_loader_data(); MetadataFactory::free_array(cld, original_methods); - for (int i = 0; i < NUM_ARRAYS; ++i) { - MetadataFactory::free_array(cld, original_annots[i]); - } if (original_ordering->length() > 0) { klass->set_method_ordering(merged_ordering); MetadataFactory::free_array(cld, original_ordering); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/classfile/metadataOnStackMark.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/classfile/metadataOnStackMark.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,69 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "classfile/metadataOnStackMark.hpp" +#include "code/codeCache.hpp" +#include "compiler/compileBroker.hpp" +#include "oops/metadata.hpp" +#include "runtime/synchronizer.hpp" +#include "runtime/thread.hpp" +#include "utilities/growableArray.hpp" + + +// Keep track of marked on-stack metadata so it can be cleared. +GrowableArray* _marked_objects = NULL; +NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;) + +// Walk metadata on the stack and mark it so that redefinition doesn't delete +// it. Class unloading also walks the previous versions and might try to +// delete it, so this class is used by class unloading also. +MetadataOnStackMark::MetadataOnStackMark() { + assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); + NOT_PRODUCT(_is_active = true;) + if (_marked_objects == NULL) { + _marked_objects = new (ResourceObj::C_HEAP, mtClass) GrowableArray(1000, true); + } + Threads::metadata_do(Metadata::mark_on_stack); + CodeCache::alive_nmethods_do(nmethod::mark_on_stack); + CompileBroker::mark_on_stack(); +} + +MetadataOnStackMark::~MetadataOnStackMark() { + assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); + // Unmark everything that was marked. Can't do the same walk because + // redefine classes messes up the code cache so the set of methods + // might not be the same. + for (int i = 0; i< _marked_objects->length(); i++) { + _marked_objects->at(i)->set_on_stack(false); + } + _marked_objects->clear(); // reuse growable array for next time. + NOT_PRODUCT(_is_active = false;) +} + +// Record which objects are marked so we can unmark the same objects. +void MetadataOnStackMark::record(Metadata* m) { + assert(_is_active, "metadata on stack marking is active"); + _marked_objects->push(m); +} diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/classfile/metadataOnStackMark.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/classfile/metadataOnStackMark.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_CLASSFILE_METADATAONSTACKMARK_HPP +#define SHARE_VM_CLASSFILE_METADATAONSTACKMARK_HPP + +#include "memory/allocation.hpp" + +class Metadata; + +// Helper class to mark and unmark metadata used on the stack as either handles +// or executing methods, so that it can't be deleted during class redefinition +// and class unloading. +// This is also used for other things that can be deallocated, like class +// metadata during parsing, relocated methods, and methods in backtraces. +class MetadataOnStackMark : public StackObj { + NOT_PRODUCT(static bool _is_active;) + public: + MetadataOnStackMark(); + ~MetadataOnStackMark(); + static void record(Metadata* m); +}; + +#endif // SHARE_VM_CLASSFILE_METADATAONSTACKMARK_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/classfile/stackMapFrame.hpp --- a/src/share/vm/classfile/stackMapFrame.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/classfile/stackMapFrame.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -178,7 +178,7 @@ #ifdef DEBUG // Put bogus type to indicate it's no longer valid. if (_stack_mark != -1) { - for (int i = _stack_mark; i >= _stack_size; --i) { + for (int i = _stack_mark - 1; i >= _stack_size; --i) { _stack[i] = VerificationType::bogus_type(); } } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/classfile/systemDictionary.cpp --- a/src/share/vm/classfile/systemDictionary.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/classfile/systemDictionary.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1199,66 +1199,6 @@ return ik; } -#ifdef KERNEL -// Some classes on the bootstrap class path haven't been installed on the -// system yet. Call the DownloadManager method to make them appear in the -// bootstrap class path and try again to load the named class. -// Note that with delegation class loaders all classes in another loader will -// first try to call this so it'd better be fast!! -static instanceKlassHandle download_and_retry_class_load( - Symbol* class_name, - TRAPS) { - - Klass* dlm = SystemDictionary::DownloadManager_klass(); - instanceKlassHandle nk; - - // If download manager class isn't loaded just return. - if (dlm == NULL) return nk; - - { HandleMark hm(THREAD); - ResourceMark rm(THREAD); - Handle s = java_lang_String::create_from_symbol(class_name, CHECK_(nk)); - Handle class_string = java_lang_String::externalize_classname(s, CHECK_(nk)); - - // return value - JavaValue result(T_OBJECT); - - // Call the DownloadManager. We assume that it has a lock because - // multiple classes could be not found and downloaded at the same time. - // class sun.misc.DownloadManager; - // public static String getBootClassPathEntryForClass(String className); - JavaCalls::call_static(&result, - KlassHandle(THREAD, dlm), - vmSymbols::getBootClassPathEntryForClass_name(), - vmSymbols::string_string_signature(), - class_string, - CHECK_(nk)); - - // Get result.string and add to bootclasspath - assert(result.get_type() == T_OBJECT, "just checking"); - oop obj = (oop) result.get_jobject(); - if (obj == NULL) { return nk; } - - Handle h_obj(THREAD, obj); - char* new_class_name = java_lang_String::as_platform_dependent_str(h_obj, - CHECK_(nk)); - - // lock the loader - // we use this lock because JVMTI does. - Handle loader_lock(THREAD, SystemDictionary::system_loader_lock()); - - ObjectLocker ol(loader_lock, THREAD); - // add the file to the bootclasspath - ClassLoader::update_class_path_entry_list(new_class_name, true); - } // end HandleMark - - if (TraceClassLoading) { - ClassLoader::print_bootclasspath(); - } - return ClassLoader::load_classfile(class_name, CHECK_(nk)); -} -#endif // KERNEL - instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) { instanceKlassHandle nh = instanceKlassHandle(); // null Handle @@ -1278,15 +1218,6 @@ k = ClassLoader::load_classfile(class_name, CHECK_(nh)); } -#ifdef KERNEL - // If the VM class loader has failed to load the class, call the - // DownloadManager class to make it magically appear on the classpath - // and try again. This is only configured with the Kernel VM. - if (k.is_null()) { - k = download_and_retry_class_load(class_name, CHECK_(nh)); - } -#endif // KERNEL - // find_or_define_instance_class may return a different InstanceKlass if (!k.is_null()) { k = find_or_define_instance_class(class_name, class_loader, k, CHECK_(nh)); @@ -1822,13 +1753,7 @@ Symbol* symbol = vmSymbols::symbol_at((vmSymbols::SID)sid); Klass** klassp = &_well_known_klasses[id]; bool must_load = (init_opt < SystemDictionary::Opt); - bool try_load = true; - if (init_opt == SystemDictionary::Opt_Kernel) { -#ifndef KERNEL - try_load = false; -#endif //KERNEL - } - if ((*klassp) == NULL && try_load) { + if ((*klassp) == NULL) { if (must_load) { (*klassp) = resolve_or_fail(symbol, true, CHECK_0); // load required class } else { @@ -1918,12 +1843,6 @@ //_box_klasses[T_OBJECT] = WK_KLASS(object_klass); //_box_klasses[T_ARRAY] = WK_KLASS(object_klass); -#ifdef KERNEL - if (DownloadManager_klass() == NULL) { - warning("Cannot find sun/jkernel/DownloadManager"); - } -#endif // KERNEL - { // Compute whether we should use loadClass or loadClassInternal when loading classes. Method* method = InstanceKlass::cast(ClassLoader_klass())->find_method(vmSymbols::loadClassInternal_name(), vmSymbols::string_class_signature()); _has_loadClassInternal = (method != NULL); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/classfile/systemDictionary.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -168,8 +168,6 @@ /* It's okay if this turns out to be NULL in non-1.4 JDKs. */ \ do_klass(nio_Buffer_klass, java_nio_Buffer, Opt ) \ \ - do_klass(DownloadManager_klass, sun_jkernel_DownloadManager, Opt_Kernel ) \ - \ do_klass(PostVMInitHook_klass, sun_misc_PostVMInitHook, Opt ) \ \ /* Preload boxing klasses */ \ @@ -186,6 +184,7 @@ do_klass(GraalBitMap_klass, java_util_BitSet, Opt) \ /* graal.hotspot */ \ do_klass(HotSpotCompilationResult_klass, com_oracle_graal_hotspot_HotSpotCompilationResult, Opt) \ + do_klass(HotSpotRuntimeCallTarget_klass, com_oracle_graal_hotspot_HotSpotRuntimeCallTarget, Opt) \ do_klass(HotSpotCodeInfo_klass, com_oracle_graal_hotspot_meta_HotSpotCodeInfo, Opt) \ do_klass(HotSpotInstalledCode_klass, com_oracle_graal_hotspot_meta_HotSpotInstalledCode, Opt) \ do_klass(HotSpotJavaType_klass, com_oracle_graal_hotspot_meta_HotSpotJavaType, Opt) \ @@ -252,7 +251,6 @@ Opt, // preload tried; NULL if not present Opt_Only_JDK14NewRef, // preload tried; use only with NewReflection Opt_Only_JDK15, // preload tried; use only with JDK1.5+ - Opt_Kernel, // preload tried only #ifdef KERNEL OPTION_LIMIT, CEIL_LG_OPTION_LIMIT = 4 // OPTION_LIMIT <= (1<major_version() < STATIC_METHOD_IN_INTERFACE_MAJOR_VERSION) ? + (1 << JVM_CONSTANT_Methodref) : + ((1 << JVM_CONSTANT_InterfaceMethodref) | (1 << JVM_CONSTANT_Methodref)); + break; default: types = 1 << JVM_CONSTANT_Methodref; } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/classfile/vmSymbols.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,7 +108,6 @@ template(java_lang_Compiler, "java/lang/Compiler") \ template(sun_misc_Signal, "sun/misc/Signal") \ template(java_lang_AssertionStatusDirectives, "java/lang/AssertionStatusDirectives") \ - template(sun_jkernel_DownloadManager, "sun/jkernel/DownloadManager") \ template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \ template(sun_misc_PostVMInitHook, "sun/misc/PostVMInitHook") \ template(sun_misc_Launcher_ExtClassLoader, "sun/misc/Launcher$ExtClassLoader") \ @@ -295,6 +294,7 @@ template(com_oracle_graal_hotspot_HotSpotKlassOop, "com/oracle/graal/hotspot/HotSpotKlassOop") \ template(com_oracle_graal_hotspot_HotSpotOptions, "com/oracle/graal/hotspot/HotSpotOptions") \ 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_meta_HotSpotCodeInfo, "com/oracle/graal/hotspot/meta/HotSpotCodeInfo") \ template(com_oracle_graal_hotspot_meta_HotSpotInstalledCode, "com/oracle/graal/hotspot/meta/HotSpotInstalledCode") \ diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/code/codeBlob.cpp --- a/src/share/vm/code/codeBlob.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/code/codeBlob.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -39,7 +39,6 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/vframe.hpp" #include "services/memoryService.hpp" -#include "utilities/machineCodePrinter.hpp" #ifdef TARGET_ARCH_x86 # include "nativeInst_x86.hpp" #endif @@ -134,11 +133,10 @@ cb->copy_code_and_locs_to(this); set_oop_maps(oop_maps); _frame_size = frame_size; -#if defined(COMPILER1) || defined(GRAAL) - +#ifdef COMPILER1 // probably wrong for tiered assert(_frame_size >= -1, "must use frame size or -1 for runtime stubs"); -#endif // COMPILER1 || GRAAL +#endif // COMPILER1 } @@ -345,10 +343,6 @@ trace_new_stub(stub, "RuntimeStub - ", stub_name); - if (PrintMachineCodeToFile) { - MachineCodePrinter::print(stub); - } - return stub; } @@ -384,7 +378,9 @@ _unpack_offset = unpack_offset; _unpack_with_exception = unpack_with_exception_offset; _unpack_with_reexecution = unpack_with_reexecution_offset; +#ifdef COMPILER1 _unpack_with_exception_in_tls = -1; +#endif } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/code/compiledIC.cpp --- a/src/share/vm/code/compiledIC.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/code/compiledIC.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -95,7 +95,7 @@ // Don't use ic_destination for this test since that forwards // through ICBuffer instead of returning the actual current state of // the CompiledIC. - if (is_icholder_entry(_ic_call->destination())) { + if (is_icholder_entry(_ic_call->destination()) GRAAL_ONLY(&& _value != NULL)) { // When patching for the ICStub case the cached value isn't // overwritten until the ICStub copied into the CompiledIC during // the next safepoint. Make sure that the CompiledICHolder* is @@ -126,6 +126,13 @@ _ic_call->set_destination_mt_safe(entry_point); } +#ifdef GRAAL + if (_value == NULL) { + // Can happen when Graal converted a virtual call into an invoke special based on static analysis. + return; + } +#endif + if (is_optimized() || is_icstub) { // Optimized call sites don't have a cache value and ICStub call // sites only change the entry point. Changing the value in that @@ -265,12 +272,14 @@ // Check if we are calling into our own codeblob (i.e., to a stub) CodeBlob* cb = CodeCache::find_blob(_ic_call->instruction_address()); address dest = ic_destination(); +#ifndef GRAAL #ifdef ASSERT { CodeBlob* db = CodeCache::find_blob_unsafe(dest); assert(!db->is_adapter_blob(), "must use stub!"); } #endif /* ASSERT */ +#endif is_call_to_interpreted = cb->contains(dest); } return is_call_to_interpreted; @@ -552,6 +561,12 @@ void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) { address stub=find_stub(); +#ifdef GRAAL + if (stub == NULL) { + set_destination_mt_safe(entry); + return; + } +#endif assert(stub!=NULL, "stub not found"); if (TraceICs) { @@ -702,9 +717,11 @@ // Verify stub address stub = find_stub(); +#ifndef GRAAL assert(stub != NULL, "no stub found for static call"); NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); // creation also verifies the object NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); +#endif // Verify state assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check"); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/code/debugInfo.cpp --- a/src/share/vm/code/debugInfo.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/code/debugInfo.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -77,11 +77,7 @@ enum { LOCATION_CODE = 0, CONSTANT_INT_CODE = 1, CONSTANT_OOP_CODE = 2, CONSTANT_LONG_CODE = 3, CONSTANT_DOUBLE_CODE = 4, - OBJECT_CODE = 5, OBJECT_ID_CODE = 6, -#ifdef GRAAL - DEFERRED_READ_CODE = 7, DEFERRED_WRITE_CODE = 8 -#endif // GRAAL -}; + OBJECT_CODE = 5, OBJECT_ID_CODE = 6 }; ScopeValue* ScopeValue::read_from(DebugInfoReadStream* stream) { ScopeValue* result = NULL; @@ -93,10 +89,6 @@ case CONSTANT_DOUBLE_CODE: result = new ConstantDoubleValue(stream); break; case OBJECT_CODE: result = stream->read_object_value(); break; case OBJECT_ID_CODE: result = stream->get_cached_object(); break; -#ifdef GRAAL - case DEFERRED_READ_CODE: result = new DeferredReadValue(stream); break; - case DEFERRED_WRITE_CODE: result = new DeferredWriteValue(stream); break; -#endif // GRAAL default: ShouldNotReachHere(); } return result; @@ -117,63 +109,6 @@ location().print_on(st); } -#ifdef GRAAL - -// DeferredLocationValue - -DeferredLocationValue::DeferredLocationValue(DebugInfoReadStream* stream) { - _base = read_from(stream); - _index = read_from(stream); - _scale = stream->read_int(); - _disp = stream->read_long(); -} - -void DeferredLocationValue::write_on(DebugInfoWriteStream* stream) { - _base->write_on(stream); - _index->write_on(stream); - stream->write_int(_scale); - stream->write_long(_disp); -} - -void DeferredLocationValue::print_on(outputStream* st) const { - _base->print_on(st); - _index->print_on(st); - st->print("%i %i", _scale, _disp); -} - -// DeferredReadValue - -DeferredReadValue::DeferredReadValue(DebugInfoReadStream* stream) -: DeferredLocationValue(stream) { -} - -void DeferredReadValue::write_on(DebugInfoWriteStream* st) { - DeferredLocationValue::write_on(st); -} - -void DeferredReadValue::print_on(outputStream* st) const { - DeferredLocationValue::print_on(st); -} - -// DeferredWriteValue - -DeferredWriteValue::DeferredWriteValue(DebugInfoReadStream* stream) -: DeferredLocationValue(stream) { - _value = read_from(stream); -} - -void DeferredWriteValue::write_on(DebugInfoWriteStream* st) { - DeferredLocationValue::write_on(st); - _value->write_on(st); -} - -void DeferredWriteValue::print_on(outputStream* st) const { - DeferredLocationValue::print_on(st); - _value->print_on(st); -} - -#endif // GRAAL - // ObjectValue void ObjectValue::read_object(DebugInfoReadStream* stream) { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/code/debugInfo.hpp --- a/src/share/vm/code/debugInfo.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/code/debugInfo.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -61,11 +61,6 @@ // Serialization of debugging information virtual void write_on(DebugInfoWriteStream* stream) = 0; static ScopeValue* read_from(DebugInfoReadStream* stream); - -#ifdef GRAAL - // Printing - virtual void print_on(outputStream* st) const = 0; -#endif // GRAAL }; @@ -88,64 +83,6 @@ void print_on(outputStream* st) const; }; -#ifdef GRAAL - -class DeferredLocationValue: public ScopeValue { -private: - ScopeValue* _base; - ScopeValue* _index; - jint _scale; - jlong _disp; -public: - DeferredLocationValue(ScopeValue* base, ScopeValue* index, jint scale, jlong disp) - : _base(base), _index(index), _scale(scale), _disp(disp) { } - - ScopeValue* base() { return _base; } - ScopeValue* index() { return _index; } - jint scale() { return _scale; } - jlong disp() { return _disp; } - - // Serialization of debugging information - DeferredLocationValue(DebugInfoReadStream* stream); - void write_on(DebugInfoWriteStream* stream); - - // Printing - void print_on(outputStream* st) const; -}; - - -class DeferredReadValue: public DeferredLocationValue { -public: - DeferredReadValue(ScopeValue* base, ScopeValue* index, jint scale, jint disp) - : DeferredLocationValue(base, index, scale, disp) { } - - // Serialization of debugging information - DeferredReadValue(DebugInfoReadStream* stream); - void write_on(DebugInfoWriteStream* stream); - - // Printing - void print_on(outputStream* st) const; -}; - -class DeferredWriteValue: public DeferredLocationValue { -private: - ScopeValue* _value; -public: - DeferredWriteValue(ScopeValue* base, ScopeValue* index, jint scale, jint disp, ScopeValue* value) - : DeferredLocationValue(base, index, scale, disp), _value(value) { } - - ScopeValue* value() { return _value; } - - // Serialization of debugging information - DeferredWriteValue(DebugInfoReadStream* stream); - void write_on(DebugInfoWriteStream* stream); - - // Printing - void print_on(outputStream* st) const; -}; - -#endif // GRAAL - // An ObjectValue describes an object eliminated by escape analysis. diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/code/debugInfoRec.cpp --- a/src/share/vm/code/debugInfoRec.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/code/debugInfoRec.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -213,29 +213,6 @@ return result; } -#ifdef GRAAL - -int DebugInformationRecorder::serialize_deferred_writes(GrowableArray* deferred_writes) { - if (deferred_writes == NULL || deferred_writes->is_empty()) return DebugInformationRecorder::serialized_null; - assert(_recording_state == rs_safepoint, "must be recording a safepoint"); - int result = stream()->position(); - assert(result != serialized_null, "sanity"); - stream()->write_int(deferred_writes->length()); - for (int index = 0; index < deferred_writes->length(); index++) { - deferred_writes->at(index)->write_on(stream()); - } - - // (See comment below on DebugInformationRecorder::describe_scope.) - int shared_result = find_sharable_decode_offset(result); - if (shared_result != serialized_null) { - stream()->set_position(result); - result = shared_result; - } - - return result; -} - -#endif // GRAAL #ifndef PRODUCT // These variables are put into one block to reduce relocations @@ -312,11 +289,7 @@ bool return_oop, DebugToken* locals, DebugToken* expressions, - DebugToken* monitors -#ifdef GRAAL - , DebugToken* deferred_writes -#endif // GRAAL - ) { + DebugToken* monitors) { assert(_recording_state != rs_null, "nesting of recording calls"); PcDesc* last_pd = last_pc(); assert(last_pd->pc_offset() == pc_offset, "must be last pc"); @@ -355,9 +328,6 @@ stream()->write_int((intptr_t) locals); stream()->write_int((intptr_t) expressions); stream()->write_int((intptr_t) monitors); -#ifdef GRAAL - stream()->write_int((intptr_t) deferred_writes); -#endif // GRAAL // Here's a tricky bit. We just wrote some bytes. // Wouldn't it be nice to find that we had already @@ -439,14 +409,6 @@ return (DebugToken*) (intptr_t) serialize_monitor_values(monitors); } -#ifdef GRAAL - -DebugToken* DebugInformationRecorder::create_deferred_writes(GrowableArray* deferred_writes) { - assert(!recorders_frozen(), "not frozen yet"); - return (DebugToken*) (intptr_t) serialize_deferred_writes(deferred_writes); -} - -#endif // GRAAL int DebugInformationRecorder::data_size() { debug_only(mark_recorders_frozen()); // mark it "frozen" for asserts diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/code/debugInfoRec.hpp --- a/src/share/vm/code/debugInfoRec.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/code/debugInfoRec.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -107,11 +107,7 @@ bool return_oop = false, DebugToken* locals = NULL, DebugToken* expressions = NULL, - DebugToken* monitors = NULL -#ifdef GRAAL - , DebugToken* deferred_writes = NULL -#endif // GRAAL - ); + DebugToken* monitors = NULL); void dump_object_pool(GrowableArray* objects); @@ -124,9 +120,6 @@ // helper fuctions for describe_scope to enable sharing DebugToken* create_scope_values(GrowableArray* values); DebugToken* create_monitor_values(GrowableArray* monitors); -#ifdef GRAAL - DebugToken* create_deferred_writes(GrowableArray* deferred_writes); -#endif // GRAAL // returns the size of the generated scopeDescs. int data_size(); @@ -201,9 +194,6 @@ int serialize_monitor_values(GrowableArray* monitors); int serialize_scope_values(GrowableArray* values); -#ifdef GRAAL - int serialize_deferred_writes(GrowableArray* deferred_writes); -#endif // GRAAL int find_sharable_decode_offset(int stream_offset); #ifndef PRODUCT diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/code/dependencies.cpp --- a/src/share/vm/code/dependencies.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/code/dependencies.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -563,6 +563,7 @@ _size_in_bytes = bytes.position(); } + const char* Dependencies::_dep_name[TYPE_LIMIT] = { "end_marker", "evol_method", diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/code/icBuffer.cpp --- a/src/share/vm/code/icBuffer.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/code/icBuffer.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -96,8 +96,8 @@ void ICStub::verify() { } -void ICStub::print_on(outputStream* st) { - st->print_cr("ICStub: site: " INTPTR_FORMAT, _ic_site); +void ICStub::print() { + tty->print_cr("ICStub: site: " INTPTR_FORMAT, _ic_site); } #endif diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/code/icBuffer.hpp --- a/src/share/vm/code/icBuffer.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/code/icBuffer.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -75,8 +75,8 @@ void* cached_value() const; // cached_value for stub // Debugging - void verify() PRODUCT_RETURN; - void print_on(outputStream* st) PRODUCT_RETURN; + void verify() PRODUCT_RETURN; + void print() PRODUCT_RETURN; // Creation friend ICStub* ICStub_from_destination_address(address destination_address); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/code/nmethod.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -42,8 +42,6 @@ #include "utilities/dtrace.hpp" #include "utilities/events.hpp" #include "utilities/xmlstream.hpp" -#include "utilities/debug.hpp" -#include "utilities/machineCodePrinter.hpp" #ifdef SHARK #include "shark/sharkCompiler.hpp" #endif @@ -126,6 +124,7 @@ // PrintC1Statistics, PrintOptoStatistics, LogVMOutput, and LogCompilation. // (In the latter two cases, they like other stats are printed to the log only.) +#ifndef PRODUCT // These variables are put into one block to reduce relocations // and make it simpler to print from the debugger. static @@ -215,6 +214,7 @@ pc_desc_tests, pc_desc_searches, pc_desc_adds); } } nmethod_stats; +#endif //PRODUCT //--------------------------------------------------------------------------------- @@ -490,6 +490,7 @@ _compiler = NULL; #ifdef GRAAL _graal_installed_code = NULL; + _triggered_deoptimizations = NULL; #endif #ifdef HAVE_DTRACE_H _trap_offset = 0; @@ -520,13 +521,9 @@ code_buffer, frame_size, basic_lock_owner_sp_offset, basic_lock_sp_offset, oop_maps); - if (nm != NULL) nmethod_stats.note_native_nmethod(nm); + NOT_PRODUCT(if (nm != NULL) nmethod_stats.note_native_nmethod(nm)); if (PrintAssembly && nm != NULL) Disassembler::decode(nm); - - if (PrintMachineCodeToFile) { - MachineCodePrinter::print(nm); - } } // verify nmethod debug_only(if (nm) nm->verify();) // might block @@ -558,7 +555,7 @@ nm = new (nmethod_size) nmethod(method(), nmethod_size, &offsets, code_buffer, frame_size); - if (nm != NULL) nmethod_stats.note_nmethod(nm); + NOT_PRODUCT(if (nm != NULL) nmethod_stats.note_nmethod(nm)); if (PrintAssembly && nm != NULL) Disassembler::decode(nm); } @@ -589,7 +586,8 @@ int comp_level, GrowableArray* leaf_graph_ids #ifdef GRAAL - , Handle installed_code + , Handle installed_code, + Handle triggered_deoptimizations #endif ) { @@ -617,7 +615,8 @@ comp_level, leaf_graph_ids #ifdef GRAAL - , installed_code + , installed_code, + triggered_deoptimizations #endif ); if (nm != NULL) { @@ -637,13 +636,9 @@ InstanceKlass::cast(klass)->add_dependent_nmethod(nm); } } - if (nm != NULL) nmethod_stats.note_nmethod(nm); + NOT_PRODUCT(if (nm != NULL) nmethod_stats.note_nmethod(nm)); if (PrintAssembly && nm != NULL) Disassembler::decode(nm); - - if (nm != NULL && PrintMachineCodeToFile) { - MachineCodePrinter::print(nm); - } } // verify nmethod @@ -847,7 +842,8 @@ int comp_level, GrowableArray* leaf_graph_ids #ifdef GRAAL - , Handle installed_code + , Handle installed_code, + Handle triggered_deoptimizations #endif ) : CodeBlob("nmethod", code_buffer, sizeof(nmethod), @@ -874,6 +870,7 @@ #ifdef GRAAL _graal_installed_code = installed_code(); + _triggered_deoptimizations = (typeArrayOop)triggered_deoptimizations(); #endif if (compiler->is_graal()) { // Graal might not produce any stub sections @@ -1693,8 +1690,16 @@ #ifdef GRAAL // Follow Graal method - if (_graal_installed_code != NULL && can_unload(is_alive, (oop*)&_graal_installed_code, unloading_occurred)) { - return; + if (_graal_installed_code != NULL) { + if (HotSpotInstalledCode::isDefault(_graal_installed_code)) { + if (!is_alive->do_object_b(_graal_installed_code)) { + _graal_installed_code = NULL; + } + } else { + if (can_unload(is_alive, (oop*)&_graal_installed_code, unloading_occurred)) { + return; + } + } } #endif @@ -1819,8 +1824,8 @@ // really alive. void nmethod::verify_metadata_loaders(address low_boundary, BoolObjectClosure* is_alive) { #ifdef ASSERT - RelocIterator iter(this, low_boundary); - while (iter.next()) { + RelocIterator iter(this, low_boundary); + while (iter.next()) { // static_stub_Relocations may have dangling references to // Method*s so trim them out here. Otherwise it looks like // compiled code is maintaining a link to dead metadata. @@ -1829,13 +1834,11 @@ CompiledIC* cic = CompiledIC_at(iter.reloc()); if (!cic->is_call_to_interpreted()) { static_call_addr = iter.addr(); - cic->set_to_clean(); } } else if (iter.type() == relocInfo::static_call_type) { CompiledStaticCall* csc = compiledStaticCall_at(iter.reloc()); if (!csc->is_call_to_interpreted()) { static_call_addr = iter.addr(); - csc->set_to_clean(); } } if (static_call_addr != NULL) { @@ -1923,6 +1926,9 @@ if (_graal_installed_code != NULL) { f->do_oop((oop*) &_graal_installed_code); } + if (_triggered_deoptimizations != NULL) { + f->do_oop((oop*) &_triggered_deoptimizations); + } #endif RelocIterator iter(this, low_boundary); @@ -2513,9 +2519,7 @@ // information in a table. break; } -#ifndef GRAAL assert(stub == NULL || stub_contains(stub), "static call stub outside stub section"); -#endif } } @@ -3007,8 +3011,6 @@ ImplicitExceptionTable(this).print(code_begin()); } -#endif // PRODUCT - void nmethod::print_statistics() { ttyLocker ttyl; if (xtty != NULL) xtty->head("statistics type='nmethod'"); @@ -3020,18 +3022,4 @@ if (xtty != NULL) xtty->tail("statistics"); } -#ifdef GRAAL -void DebugScopedNMethod::print_on(outputStream* st) { - if (_nm != NULL) { - st->print("nmethod@%p", _nm); - Method* method = _nm->method(); - if (method != NULL) { - char holder[O_BUFLEN]; - char nameAndSig[O_BUFLEN]; - method->method_holder()->name()->as_C_string(holder, O_BUFLEN); - method->name_and_sig_as_C_string(nameAndSig, O_BUFLEN); - st->print(" - %s::%s", holder, nameAndSig); - } - } -} -#endif +#endif // PRODUCT diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/code/nmethod.hpp --- a/src/share/vm/code/nmethod.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/code/nmethod.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -119,6 +119,7 @@ #ifdef GRAAL // Needed to keep nmethods alive that are not the default nmethod for the associated Method. oop _graal_installed_code; + typeArrayOop _triggered_deoptimizations; #endif // To support simple linked-list chaining of nmethods: @@ -271,7 +272,8 @@ int comp_level, GrowableArray* leaf_graph_ids #ifdef GRAAL - , Handle installed_code + , Handle installed_code, + Handle triggered_deoptimizations #endif ); @@ -291,7 +293,7 @@ // Inform external interfaces that a compiled method has been unloaded void post_compiled_method_unload(); - // Initialize fields to their default values + // Initailize fields to their default values void init_defaults(); public: @@ -312,7 +314,8 @@ int comp_level, GrowableArray* leaf_graph_ids = NULL #ifdef GRAAL - , Handle installed_code = NULL + , Handle installed_code = Handle(), + Handle triggered_deoptimizations = Handle() #endif ); @@ -357,9 +360,6 @@ bool is_compiled_by_c2() const; bool is_compiled_by_shark() const; - -#define CHECK_POSITIVE(val) assert(val, "should be positive") - // boundaries for different parts address consts_begin () const { return header_begin() + _consts_offset ; } address consts_end () const { return header_begin() + code_offset() ; } @@ -367,8 +367,8 @@ address insts_end () const { return header_begin() + _stub_offset ; } address stub_begin () const { return header_begin() + _stub_offset ; } address stub_end () const { return header_begin() + _oops_offset ; } - address exception_begin () const { assert(_exception_offset >= 0, "no exception handler"); return header_begin() + _exception_offset ; } - address deopt_handler_begin () const { assert(_deoptimize_offset >= 0, "no deopt handler"); return header_begin() + _deoptimize_offset ; } + address exception_begin () const { return header_begin() + _exception_offset ; } + address deopt_handler_begin () const { return header_begin() + _deoptimize_offset ; } address deopt_mh_handler_begin() const { return header_begin() + _deoptimize_mh_offset ; } address unwind_handler_begin () const { return _unwind_handler_offset != -1 ? (header_begin() + _unwind_handler_offset) : NULL; } oop* oops_begin () const { return (oop*) (header_begin() + _oops_offset) ; } @@ -689,7 +689,7 @@ // Prints a comment for one native instruction (reloc info, pc desc) void print_code_comment_on(outputStream* st, int column, address begin, address end); - static void print_statistics(); + static void print_statistics() PRODUCT_RETURN; // Compiler task identification. Note that all OSR methods // are numbered in an independent sequence if CICountOSR is true, @@ -774,19 +774,4 @@ } }; -#ifdef GRAAL -class DebugScopedNMethod : public DebugScopedValue { -private: - nmethod* _nm; -public: - DebugScopedNMethod(const char* file, int line, nmethod* nm) : DebugScopedValue(file, line), _nm(nm) {} - void print_on(outputStream* st); -}; -#define DS_NMETHOD(nm) DebugScopedNMethod __dsnm__(__FILE__, __LINE__, nm) -#define DS_NMETHOD1(name, nm) DebugScopedNMethod name(__FILE__, __LINE__, nm) -#else -#define DS_NMETHOD(nm) do {} while (0) -#define DS_NMETHOD1(name, nm) do {} while (0) -#endif - #endif // SHARE_VM_CODE_NMETHOD_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/code/pcDesc.hpp --- a/src/share/vm/code/pcDesc.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/code/pcDesc.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -81,8 +81,7 @@ bool is_same_info(const PcDesc* pd) { return _scope_decode_offset == pd->_scope_decode_offset && _obj_decode_offset == pd->_obj_decode_offset && - _flags == pd->_flags - ; + _flags == pd->_flags; } bool is_method_handle_invoke() const { return (_flags & PCDESC_is_method_handle_invoke) != 0; } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/code/scopeDesc.cpp --- a/src/share/vm/code/scopeDesc.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/code/scopeDesc.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -73,9 +73,6 @@ _locals_decode_offset = DebugInformationRecorder::serialized_null; _expressions_decode_offset = DebugInformationRecorder::serialized_null; _monitors_decode_offset = DebugInformationRecorder::serialized_null; -#ifdef GRAAL - _deferred_writes_decode_offset = DebugInformationRecorder::serialized_null; -#endif // GRAAL } else { // decode header DebugInfoReadStream* stream = stream_at(decode_offset()); @@ -88,9 +85,6 @@ _locals_decode_offset = stream->read_int(); _expressions_decode_offset = stream->read_int(); _monitors_decode_offset = stream->read_int(); -#ifdef GRAAL - _deferred_writes_decode_offset = stream->read_int(); -#endif // GRAAL } } @@ -132,25 +126,6 @@ return result; } -#ifdef GRAAL - -GrowableArray* ScopeDesc::decode_deferred_writes(int decode_offset) { - if (decode_offset == DebugInformationRecorder::serialized_null) return NULL; - DebugInfoReadStream* stream = stream_at(decode_offset); - int length = stream->read_int(); - GrowableArray* result = new GrowableArray (length); - for (int index = 0; index < length; index++) { - result->push(new DeferredWriteValue(stream)); - } - return result; -} - -GrowableArray* ScopeDesc::deferred_writes() { - return decode_deferred_writes(_deferred_writes_decode_offset); -} - -#endif // GRAAL - DebugInfoReadStream* ScopeDesc::stream_at(int decode_offset) const { return new DebugInfoReadStream(_code, decode_offset, _objects); } @@ -261,19 +236,6 @@ } } #endif // COMPILER2 || GRAAL -#ifdef GRAAL - // deferred writes - { GrowableArray* l = ((ScopeDesc*) this)->deferred_writes(); - if (l != NULL) { - st->print_cr(" Deferred writes"); - for (int index = 0; index < l->length(); index++) { - st->print(" - @%d: ", index); - l->at(index)->print_on(st); - st->cr(); - } - } - } -#endif } #endif diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/code/scopeDesc.hpp --- a/src/share/vm/code/scopeDesc.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/code/scopeDesc.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -78,9 +78,6 @@ GrowableArray* expressions(); GrowableArray* monitors(); GrowableArray* objects(); -#ifdef GRAAL - GrowableArray* deferred_writes(); -#endif // GRAAL // Stack walking, returns NULL if this is the outer most scope. ScopeDesc* sender() const; @@ -110,9 +107,6 @@ int _locals_decode_offset; int _expressions_decode_offset; int _monitors_decode_offset; -#ifdef GRAAL - int _deferred_writes_decode_offset; -#endif // GRAAL // Object pool GrowableArray* _objects; @@ -125,9 +119,6 @@ GrowableArray* decode_scope_values(int decode_offset); GrowableArray* decode_monitor_values(int decode_offset); GrowableArray* decode_object_values(int decode_offset); -#ifdef GRAAL - GrowableArray* decode_deferred_writes(int decode_offset); -#endif // GRAAL DebugInfoReadStream* stream_at(int decode_offset) const; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/code/stubs.cpp --- a/src/share/vm/code/stubs.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/code/stubs.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -254,9 +254,10 @@ guarantee(_queue_begin != _queue_end || n == 0, "buffer indices must be the same"); } -void StubQueue::print_on(outputStream* st) const { + +void StubQueue::print() { MutexLockerEx lock(_mutex); for (Stub* s = first(); s != NULL; s = next(s)) { - stub_print(s, st); + stub_print(s); } } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/code/stubs.hpp --- a/src/share/vm/code/stubs.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/code/stubs.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -107,21 +107,20 @@ public: // Initialization/finalization virtual void initialize(Stub* self, int size, - CodeComments& comments) = 0; // called after creation (called twice if allocated via (request, commit)) - virtual void finalize(Stub* self) = 0; // called before deallocation + CodeComments& comments) = 0; // called after creation (called twice if allocated via (request, commit)) + virtual void finalize(Stub* self) = 0; // called before deallocation // General info/converters - virtual int size(Stub* self) const = 0; // the total size of the stub in bytes (must be a multiple of CodeEntryAlignment) - virtual int code_size_to_size(int code_size) const = 0; // computes the total stub size in bytes given the code size in bytes + virtual int size(Stub* self) const = 0; // the total size of the stub in bytes (must be a multiple of CodeEntryAlignment) + virtual int code_size_to_size(int code_size) const = 0; // computes the total stub size in bytes given the code size in bytes // Code info - virtual address code_begin(Stub* self) const = 0; // points to the first code byte - virtual address code_end(Stub* self) const = 0; // points to the first byte after the code + virtual address code_begin(Stub* self) const = 0; // points to the first code byte + virtual address code_end(Stub* self) const = 0; // points to the first byte after the code // Debugging - virtual void verify(Stub* self) const = 0; // verifies the stub - NOT_PRODUCT(using AllocatedObj::print_on;) - virtual void print_on(Stub* self, outputStream* st) const = 0; // prints information about the stub + virtual void verify(Stub* self) = 0; // verifies the stub + virtual void print(Stub* self) = 0; // prints information about the stub }; @@ -129,29 +128,28 @@ // class, forwarding stub interface calls to the corresponding // stub calls. -#define DEF_STUB_INTERFACE(stub) \ - class stub##Interface: public StubInterface { \ - private: \ - static stub* cast(Stub* self) { return (stub*)self; } \ - \ - public: \ - /* Initialization/finalization */ \ - virtual void initialize(Stub* self, int size, \ - CodeComments& comments) { cast(self)->initialize(size, comments); } \ - virtual void finalize(Stub* self) { cast(self)->finalize(); } \ - \ - /* General info */ \ - virtual int size(Stub* self) const { return cast(self)->size(); } \ - virtual int code_size_to_size(int code_size) const { return stub::code_size_to_size(code_size); } \ - \ - /* Code info */ \ - virtual address code_begin(Stub* self) const { return cast(self)->code_begin(); } \ - virtual address code_end(Stub* self) const { return cast(self)->code_end(); } \ - \ - /* Debugging */ \ - virtual void verify(Stub* self) const { cast(self)->verify(); } \ - NOT_PRODUCT(using AllocatedObj::print_on;) \ - virtual void print_on(Stub* self, outputStream* st) const { cast(self)->print_on(st); } \ +#define DEF_STUB_INTERFACE(stub) \ + class stub##Interface: public StubInterface { \ + private: \ + static stub* cast(Stub* self) { return (stub*)self; } \ + \ + public: \ + /* Initialization/finalization */ \ + virtual void initialize(Stub* self, int size, \ + CodeComments& comments) { cast(self)->initialize(size, comments); } \ + virtual void finalize(Stub* self) { cast(self)->finalize(); } \ + \ + /* General info */ \ + virtual int size(Stub* self) const { return cast(self)->size(); } \ + virtual int code_size_to_size(int code_size) const { return stub::code_size_to_size(code_size); } \ + \ + /* Code info */ \ + virtual address code_begin(Stub* self) const { return cast(self)->code_begin(); } \ + virtual address code_end(Stub* self) const { return cast(self)->code_end(); } \ + \ + /* Debugging */ \ + virtual void verify(Stub* self) { cast(self)->verify(); } \ + virtual void print(Stub* self) { cast(self)->print(); } \ }; @@ -184,7 +182,7 @@ bool stub_contains(Stub* s, address pc) const { return _stub_interface->code_begin(s) <= pc && pc < _stub_interface->code_end(s); } int stub_code_size_to_size(int code_size) const { return _stub_interface->code_size_to_size(code_size); } void stub_verify(Stub* s) { _stub_interface->verify(s); } - void stub_print(Stub* s, outputStream* st) const { _stub_interface->print_on(s, st); } + void stub_print(Stub* s) { _stub_interface->print(s); } static void register_queue(StubQueue*); @@ -228,9 +226,8 @@ address stub_code_end(Stub* s) const { return _stub_interface->code_end(s); } // Debugging/printing - void verify(); // verifies the stub queue - virtual void print() const { print_on(tty); } - virtual void print_on(outputStream* st) const; + void verify(); // verifies the stub queue + void print(); // prints information about the stub queue }; #endif // SHARE_VM_CODE_STUBS_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/compiler/compileBroker.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -44,9 +44,6 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/sweeper.hpp" #include "utilities/dtrace.hpp" -#ifdef GRAAL -#include "graal/graalCompiler.hpp" -#endif #include "utilities/events.hpp" #ifdef COMPILER1 #include "c1/c1_Compiler.hpp" @@ -1421,7 +1418,7 @@ method->print_short_name(tty); tty->cr(); } - method->set_not_compilable_quietly(); + method->set_not_compilable(CompLevel_all, !quietly, "excluded by CompilerOracle"); } return false; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/compiler/oopMap.hpp --- a/src/share/vm/compiler/oopMap.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/compiler/oopMap.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -47,7 +47,7 @@ class OopMapValue: public StackObj { friend class VMStructs; private: - int _value; + short _value; int value() const { return _value; } void set_value(int value) { _value = value; } short _content_reg; @@ -55,7 +55,7 @@ public: // Constants enum { type_bits = 5, - register_bits = BitsPerJavaInteger - type_bits }; + register_bits = BitsPerShort - type_bits }; enum { type_shift = 0, register_shift = type_bits }; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -102,7 +102,7 @@ // temporarily disabled). switch (dictionaryChoice) { case FreeBlockDictionary::dictionaryBinaryTree: - _dictionary = new BinaryTreeDictionary(mr); + _dictionary = new AFLBinaryTreeDictionary(mr); break; case FreeBlockDictionary::dictionarySplayTree: case FreeBlockDictionary::dictionarySkipList: @@ -122,7 +122,8 @@ // moved to its new location before the klass is moved. // Set the _refillSize for the linear allocation blocks if (!use_adaptive_freelists) { - FreeChunk* fc = _dictionary->get_chunk(mr.word_size()); + FreeChunk* fc = _dictionary->get_chunk(mr.word_size(), + FreeBlockDictionary::atLeast); // The small linAB initially has all the space and will allocate // a chunk of any size. HeapWord* addr = (HeapWord*) fc; @@ -1647,7 +1648,8 @@ FreeChunk* CompactibleFreeListSpace::getChunkFromDictionary(size_t size) { assert_locked(); - FreeChunk* fc = _dictionary->get_chunk(size); + FreeChunk* fc = _dictionary->get_chunk(size, + FreeBlockDictionary::atLeast); if (fc == NULL) { return NULL; } @@ -1664,7 +1666,8 @@ FreeChunk* CompactibleFreeListSpace::getChunkFromDictionaryExact(size_t size) { assert_locked(); - FreeChunk* fc = _dictionary->get_chunk(size); + FreeChunk* fc = _dictionary->get_chunk(size, + FreeBlockDictionary::atLeast); if (fc == NULL) { return fc; } @@ -1677,7 +1680,8 @@ if (fc->size() < size + MinChunkSize) { // Return the chunk to the dictionary and go get a bigger one. returnChunkToDictionary(fc); - fc = _dictionary->get_chunk(size + MinChunkSize); + fc = _dictionary->get_chunk(size + MinChunkSize, + FreeBlockDictionary::atLeast); if (fc == NULL) { return NULL; } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -131,7 +131,7 @@ LinearAllocBlock _smallLinearAllocBlock; FreeBlockDictionary::DictionaryChoice _dictionaryChoice; - FreeBlockDictionary* _dictionary; // ptr to dictionary for large size blocks + AFLBinaryTreeDictionary* _dictionary; // ptr to dictionary for large size blocks AdaptiveFreeList _indexedFreeList[IndexSetSize]; // indexed array for small size blocks diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -274,8 +274,8 @@ // end of a collection, we let CMSTriggerRatio of the (purported) free // space be allocated before initiating a new collection cycle. // -void ConcurrentMarkSweepGeneration::init_initiating_occupancy(intx io, intx tr) { - assert(io <= 100 && tr >= 0 && tr <= 100, "Check the arguments"); +void ConcurrentMarkSweepGeneration::init_initiating_occupancy(intx io, uintx tr) { + assert(io <= 100 && tr <= 100, "Check the arguments"); if (io >= 0) { _initiating_occupancy = (double)io / 100.0; } else { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -1093,7 +1093,7 @@ // getter and initializer for _initiating_occupancy field. double initiating_occupancy() const { return _initiating_occupancy; } - void init_initiating_occupancy(intx io, intx tr); + void init_initiating_occupancy(intx io, uintx tr); public: ConcurrentMarkSweepGeneration(ReservedSpace rs, size_t initial_byte_size, diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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,6 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_VMSTRUCTS_CMS_HPP #define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_VMSTRUCTS_CMS_HPP -typedef BinaryTreeDictionary AFLBinaryTreeDictionary; - #define VM_STRUCTS_CMS(nonstatic_field, \ volatile_nonstatic_field, \ static_field) \ @@ -34,14 +32,15 @@ nonstatic_field(CompactibleFreeListSpace, _bt, BlockOffsetArrayNonContigSpace) \ \ nonstatic_field(CMSBitMap, _bmWordSize, size_t) \ - nonstatic_field(CMSBitMap, _shifter, const int) \ - nonstatic_field(CMSBitMap, _bm, BitMap) \ - nonstatic_field(CMSBitMap, _virtual_space, VirtualSpace) \ + nonstatic_field(CMSBitMap, _shifter, const int) \ + nonstatic_field(CMSBitMap, _bm, BitMap) \ + nonstatic_field(CMSBitMap, _virtual_space, VirtualSpace) \ nonstatic_field(CMSCollector, _markBitMap, CMSBitMap) \ nonstatic_field(ConcurrentMarkSweepGeneration, _cmsSpace, CompactibleFreeListSpace*) \ static_field(ConcurrentMarkSweepThread, _collector, CMSCollector*) \ nonstatic_field(LinearAllocBlock, _word_size, size_t) \ nonstatic_field(AFLBinaryTreeDictionary, _total_size, size_t) \ + nonstatic_field(CompactibleFreeListSpace, _dictionary, AFLBinaryTreeDictionary*) \ nonstatic_field(CompactibleFreeListSpace, _indexedFreeList[0], FreeList) \ nonstatic_field(CompactibleFreeListSpace, _smallLinearAllocBlock, LinearAllocBlock) @@ -62,10 +61,9 @@ declare_toplevel_type(SurrogateLockerThread*) \ declare_toplevel_type(CompactibleFreeListSpace*) \ declare_toplevel_type(CMSCollector*) \ - declare_toplevel_type(AFLBinaryTreeDictionary*) \ + declare_toplevel_type(AFLBinaryTreeDictionary) \ declare_toplevel_type(LinearAllocBlock) \ - declare_toplevel_type(FreeBlockDictionary) \ - declare_type(AFLBinaryTreeDictionary, FreeBlockDictionary) + declare_toplevel_type(FreeBlockDictionary) #define VM_INT_CONSTANTS_CMS(declare_constant) \ declare_constant(Generation::ConcurrentMarkSweep) \ diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -571,19 +571,14 @@ _sleep_factor = 0.0; _marking_task_overhead = 1.0; } else { - if (ConcGCThreads > 0) { - // notice that ConcGCThreads overwrites G1MarkingOverheadPercent + if (!FLAG_IS_DEFAULT(ConcGCThreads) && ConcGCThreads > 0) { + // Note: ConcGCThreads has precedence over G1MarkingOverheadPercent // if both are set - - _parallel_marking_threads = (uint) ConcGCThreads; - _max_parallel_marking_threads = _parallel_marking_threads; _sleep_factor = 0.0; _marking_task_overhead = 1.0; } else if (G1MarkingOverheadPercent > 0) { - // we will calculate the number of parallel marking threads - // based on a target overhead with respect to the soft real-time - // goal - + // We will calculate the number of parallel marking threads based + // on a target overhead with respect to the soft real-time goal double marking_overhead = (double) G1MarkingOverheadPercent / 100.0; double overall_cm_overhead = (double) MaxGCPauseMillis * marking_overhead / @@ -596,17 +591,22 @@ double sleep_factor = (1.0 - marking_task_overhead) / marking_task_overhead; - _parallel_marking_threads = (uint) marking_thread_num; - _max_parallel_marking_threads = _parallel_marking_threads; + FLAG_SET_ERGO(uintx, ConcGCThreads, (uint) marking_thread_num); _sleep_factor = sleep_factor; _marking_task_overhead = marking_task_overhead; } else { - _parallel_marking_threads = scale_parallel_threads((uint)ParallelGCThreads); - _max_parallel_marking_threads = _parallel_marking_threads; + // Calculate the number of parallel marking threads by scaling + // the number of parallel GC threads. + uint marking_thread_num = scale_parallel_threads((uint) ParallelGCThreads); + FLAG_SET_ERGO(uintx, ConcGCThreads, marking_thread_num); _sleep_factor = 0.0; _marking_task_overhead = 1.0; } + assert(ConcGCThreads > 0, "Should have been set"); + _parallel_marking_threads = (uint) ConcGCThreads; + _max_parallel_marking_threads = _parallel_marking_threads; + if (parallel_marking_threads() > 1) { _cleanup_task_overhead = 1.0; } else { @@ -1190,7 +1190,7 @@ uint active_workers = MAX2(1U, parallel_marking_threads()); CMRootRegionScanTask task(this); - if (parallel_marking_threads() > 0) { + if (use_parallel_marking_threads()) { _parallel_workers->set_active_workers((int) active_workers); _parallel_workers->run_task(&task); } else { @@ -1226,7 +1226,7 @@ set_phase(active_workers, true /* concurrent */); CMConcurrentMarkingTask markingTask(this, cmThread()); - if (parallel_marking_threads() > 0) { + if (use_parallel_marking_threads()) { _parallel_workers->set_active_workers((int)active_workers); // Don't set _n_par_threads because it affects MT in proceess_strong_roots() // and the decisions on that MT processing is made elsewhere. @@ -2167,7 +2167,8 @@ assert(tmp_free_list.is_empty(), "post-condition"); } -// Support closures for reference procssing in G1 +// Supporting Object and Oop closures for reference discovery +// and processing in during marking bool G1CMIsAliveClosure::do_object_b(oop obj) { HeapWord* addr = (HeapWord*)obj; @@ -2175,73 +2176,26 @@ (!_g1->is_in_g1_reserved(addr) || !_g1->is_obj_ill(obj)); } -class G1CMKeepAliveClosure: public ExtendedOopClosure { - G1CollectedHeap* _g1; - ConcurrentMark* _cm; - public: - G1CMKeepAliveClosure(G1CollectedHeap* g1, ConcurrentMark* cm) : - _g1(g1), _cm(cm) { - assert(Thread::current()->is_VM_thread(), "otherwise fix worker id"); - } - - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop( oop* p) { do_oop_work(p); } - - template void do_oop_work(T* p) { - oop obj = oopDesc::load_decode_heap_oop(p); - HeapWord* addr = (HeapWord*)obj; - - if (_cm->verbose_high()) { - gclog_or_tty->print_cr("\t[0] we're looking at location " - "*"PTR_FORMAT" = "PTR_FORMAT, - p, (void*) obj); - } - - if (_g1->is_in_g1_reserved(addr) && _g1->is_obj_ill(obj)) { - _cm->mark_and_count(obj); - _cm->mark_stack_push(obj); - } - } -}; - -class G1CMDrainMarkingStackClosure: public VoidClosure { - ConcurrentMark* _cm; - CMMarkStack* _markStack; - G1CMKeepAliveClosure* _oopClosure; - public: - G1CMDrainMarkingStackClosure(ConcurrentMark* cm, CMMarkStack* markStack, - G1CMKeepAliveClosure* oopClosure) : - _cm(cm), - _markStack(markStack), - _oopClosure(oopClosure) { } - - void do_void() { - _markStack->drain(_oopClosure, _cm->nextMarkBitMap(), false); - } -}; - -// 'Keep Alive' closure used by parallel reference processing. -// An instance of this closure is used in the parallel reference processing -// code rather than an instance of G1CMKeepAliveClosure. We could have used -// the G1CMKeepAliveClosure as it is MT-safe. Also reference objects are -// placed on to discovered ref lists once so we can mark and push with no -// need to check whether the object has already been marked. Using the -// G1CMKeepAliveClosure would mean, however, having all the worker threads -// operating on the global mark stack. This means that an individual -// worker would be doing lock-free pushes while it processes its own -// discovered ref list followed by drain call. If the discovered ref lists -// are unbalanced then this could cause interference with the other -// workers. Using a CMTask (and its embedded local data structures) -// avoids that potential interference. -class G1CMParKeepAliveAndDrainClosure: public OopClosure { +// 'Keep Alive' oop closure used by both serial parallel reference processing. +// Uses the CMTask associated with a worker thread (for serial reference +// processing the CMTask for worker 0 is used) to preserve (mark) and +// trace referent objects. +// +// Using the CMTask and embedded local queues avoids having the worker +// threads operating on the global mark stack. This reduces the risk +// of overflowing the stack - which we would rather avoid at this late +// state. Also using the tasks' local queues removes the potential +// of the workers interfering with each other that could occur if +// operating on the global stack. + +class G1CMKeepAliveAndDrainClosure: public OopClosure { ConcurrentMark* _cm; CMTask* _task; int _ref_counter_limit; int _ref_counter; public: - G1CMParKeepAliveAndDrainClosure(ConcurrentMark* cm, CMTask* task) : - _cm(cm), _task(task), - _ref_counter_limit(G1RefProcDrainInterval) { + G1CMKeepAliveAndDrainClosure(ConcurrentMark* cm, CMTask* task) : + _cm(cm), _task(task), _ref_counter_limit(G1RefProcDrainInterval) { assert(_ref_counter_limit > 0, "sanity"); _ref_counter = _ref_counter_limit; } @@ -2262,18 +2216,22 @@ _ref_counter--; if (_ref_counter == 0) { - // We have dealt with _ref_counter_limit references, pushing them and objects - // reachable from them on to the local stack (and possibly the global stack). - // Call do_marking_step() to process these entries. We call the routine in a - // loop, which we'll exit if there's nothing more to do (i.e. we're done - // with the entries that we've pushed as a result of the deal_with_reference - // calls above) or we overflow. - // Note: CMTask::do_marking_step() can set the CMTask::has_aborted() flag - // while there may still be some work to do. (See the comment at the - // beginning of CMTask::do_marking_step() for those conditions - one of which - // is reaching the specified time target.) It is only when - // CMTask::do_marking_step() returns without setting the has_aborted() flag - // that the marking has completed. + // We have dealt with _ref_counter_limit references, pushing them + // and objects reachable from them on to the local stack (and + // possibly the global stack). Call CMTask::do_marking_step() to + // process these entries. + // + // We call CMTask::do_marking_step() in a loop, which we'll exit if + // there's nothing more to do (i.e. we're done with the entries that + // were pushed as a result of the CMTask::deal_with_reference() calls + // above) or we overflow. + // + // Note: CMTask::do_marking_step() can set the CMTask::has_aborted() + // flag while there may still be some work to do. (See the comment at + // the beginning of CMTask::do_marking_step() for those conditions - + // one of which is reaching the specified time target.) It is only + // when CMTask::do_marking_step() returns without setting the + // has_aborted() flag that the marking step has completed. do { double mark_step_duration_ms = G1ConcMarkStepDurationMillis; _task->do_marking_step(mark_step_duration_ms, @@ -2290,36 +2248,59 @@ } }; -class G1CMParDrainMarkingStackClosure: public VoidClosure { +// 'Drain' oop closure used by both serial and parallel reference processing. +// Uses the CMTask associated with a given worker thread (for serial +// reference processing the CMtask for worker 0 is used). Calls the +// do_marking_step routine, with an unbelievably large timeout value, +// to drain the marking data structures of the remaining entries +// added by the 'keep alive' oop closure above. + +class G1CMDrainMarkingStackClosure: public VoidClosure { ConcurrentMark* _cm; - CMTask* _task; + CMTask* _task; + bool _do_stealing; + bool _do_termination; public: - G1CMParDrainMarkingStackClosure(ConcurrentMark* cm, CMTask* task) : - _cm(cm), _task(task) { } + 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; + } void do_void() { do { if (_cm->verbose_high()) { - gclog_or_tty->print_cr("\t[%u] Drain: Calling do marking_step", - _task->worker_id()); + 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)); } - // We call CMTask::do_marking_step() to completely drain the local and - // global marking stacks. The routine is called in a loop, which we'll - // exit if there's nothing more to do (i.e. we'completely drained the - // entries that were pushed as a result of applying the - // G1CMParKeepAliveAndDrainClosure to the entries on the discovered ref - // lists above) or we overflow the global marking stack. - // Note: CMTask::do_marking_step() can set the CMTask::has_aborted() flag - // while there may still be some work to do. (See the comment at the - // beginning of CMTask::do_marking_step() for those conditions - one of which - // is reaching the specified time target.) It is only when - // CMTask::do_marking_step() returns without setting the has_aborted() flag - // that the marking has completed. + // We call CMTask::do_marking_step() to completely drain the local + // and global marking stacks of entries pushed by the 'keep alive' + // oop closure (an instance of G1CMKeepAliveAndDrainClosure above). + // + // CMTask::do_marking_step() is called in a loop, which we'll exit + // if there's nothing more to do (i.e. we'completely drained the + // entries that were pushed as a a result of applying the 'keep alive' + // closure to the entries on the discovered ref lists) or we overflow + // the global marking stack. + // + // Note: CMTask::do_marking_step() can set the CMTask::has_aborted() + // flag while there may still be some work to do. (See the comment at + // the beginning of CMTask::do_marking_step() for those conditions - + // one of which is reaching the specified time target.) It is only + // when CMTask::do_marking_step() returns without setting the + // has_aborted() flag that the marking step has completed. _task->do_marking_step(1000000000.0 /* something very large */, - true /* do_stealing */, - true /* do_termination */); + _do_stealing, + _do_termination); } while (_task->has_aborted() && !_cm->has_overflown()); } }; @@ -2352,19 +2333,23 @@ ProcessTask& _proc_task; G1CollectedHeap* _g1h; ConcurrentMark* _cm; + bool _processing_is_mt; public: G1CMRefProcTaskProxy(ProcessTask& proc_task, G1CollectedHeap* g1h, ConcurrentMark* cm) : AbstractGangTask("Process reference objects in parallel"), - _proc_task(proc_task), _g1h(g1h), _cm(cm) { } + _proc_task(proc_task), _g1h(g1h), _cm(cm) { + ReferenceProcessor* rp = _g1h->ref_processor_cm(); + _processing_is_mt = rp->processing_is_mt(); + } virtual void work(uint worker_id) { CMTask* marking_task = _cm->task(worker_id); G1CMIsAliveClosure g1_is_alive(_g1h); - G1CMParKeepAliveAndDrainClosure g1_par_keep_alive(_cm, marking_task); - G1CMParDrainMarkingStackClosure g1_par_drain(_cm, marking_task); + G1CMKeepAliveAndDrainClosure g1_par_keep_alive(_cm, marking_task); + G1CMDrainMarkingStackClosure g1_par_drain(_cm, marking_task, _processing_is_mt); _proc_task.work(worker_id, g1_is_alive, g1_par_keep_alive, g1_par_drain); } @@ -2372,6 +2357,7 @@ void G1CMRefProcTaskExecutor::execute(ProcessTask& proc_task) { assert(_workers != NULL, "Need parallel worker threads."); + assert(_g1h->ref_processor_cm()->processing_is_mt(), "processing is not MT"); G1CMRefProcTaskProxy proc_task_proxy(proc_task, _g1h, _cm); @@ -2399,6 +2385,7 @@ void G1CMRefProcTaskExecutor::execute(EnqueueTask& enq_task) { assert(_workers != NULL, "Need parallel worker threads."); + assert(_g1h->ref_processor_cm()->processing_is_mt(), "processing is not MT"); G1CMRefEnqueueTaskProxy enq_task_proxy(enq_task); @@ -2429,59 +2416,58 @@ // See the comment in G1CollectedHeap::ref_processing_init() // about how reference processing currently works in G1. - // Process weak references. + // Set the soft reference policy rp->setup_policy(clear_all_soft_refs); assert(_markStack.isEmpty(), "mark stack should be empty"); - G1CMKeepAliveClosure g1_keep_alive(g1h, this); - G1CMDrainMarkingStackClosure - g1_drain_mark_stack(this, &_markStack, &g1_keep_alive); - - // We use the work gang from the G1CollectedHeap and we utilize all - // the worker threads. - uint active_workers = g1h->workers() ? g1h->workers()->active_workers() : 1U; + // 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); + active_workers = MAX2(MIN2(active_workers, _max_worker_id), 1U); G1CMRefProcTaskExecutor par_task_executor(g1h, this, g1h->workers(), active_workers); - if (rp->processing_is_mt()) { - // Set the degree of MT here. If the discovery is done MT, there - // may have been a different number of threads doing the discovery - // and a different number of discovered lists may have Ref objects. - // That is OK as long as the Reference lists are balanced (see - // balance_all_queues() and balance_queues()). - rp->set_active_mt_degree(active_workers); - - rp->process_discovered_references(&g1_is_alive, + AbstractRefProcTaskExecutor* executor = (rp->processing_is_mt() + ? &par_task_executor + : NULL); + + // Set the degree of MT processing here. If the discovery was done MT, + // the number of threads involved during discovery could differ from + // the number of active workers. This is OK as long as the discovered + // Reference lists are balanced (see balance_all_queues() and balance_queues()). + rp->set_active_mt_degree(active_workers); + + // Process the weak references. + rp->process_discovered_references(&g1_is_alive, &g1_keep_alive, &g1_drain_mark_stack, - &par_task_executor); - - // The work routines of the parallel keep_alive and drain_marking_stack - // will set the has_overflown flag if we overflow the global marking - // stack. - } else { - rp->process_discovered_references(&g1_is_alive, - &g1_keep_alive, - &g1_drain_mark_stack, - NULL); - } + executor); + + // The do_oop work routines of the keep_alive and drain_marking_stack + // oop closures will set the has_overflown flag if we overflow the + // global marking stack. assert(_markStack.overflow() || _markStack.isEmpty(), "mark stack should be empty (unless it overflowed)"); if (_markStack.overflow()) { - // Should have been done already when we tried to push an + // 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. set_has_overflown(); } - if (rp->processing_is_mt()) { - assert(rp->num_q() == active_workers, "why not"); - rp->enqueue_discovered_references(&par_task_executor); - } else { - rp->enqueue_discovered_references(); - } + assert(rp->num_q() == active_workers, "why not"); + + rp->enqueue_discovered_references(executor); rp->verify_no_references_recorded(); assert(!rp->discovery_enabled(), "Post condition"); @@ -3242,7 +3228,9 @@ } void ConcurrentMark::print_worker_threads_on(outputStream* st) const { - _parallel_workers->print_worker_threads_on(st); + if (use_parallel_marking_threads()) { + _parallel_workers->print_worker_threads_on(st); + } } // We take a break if someone is trying to stop the world. @@ -4074,15 +4062,36 @@ if (_cm->verbose_low()) { gclog_or_tty->print_cr("[%u] we're scanning part " "["PTR_FORMAT", "PTR_FORMAT") " - "of region "PTR_FORMAT, - _worker_id, _finger, _region_limit, _curr_region); + "of region "HR_FORMAT, + _worker_id, _finger, _region_limit, + HR_FORMAT_PARAMS(_curr_region)); } - // Let's iterate over the bitmap of the part of the - // region that is left. - if (mr.is_empty() || _nextMarkBitMap->iterate(&bitmap_closure, mr)) { - // We successfully completed iterating over the region. Now, - // let's give up the region. + assert(!_curr_region->isHumongous() || mr.start() == _curr_region->bottom(), + "humongous regions should go around loop once only"); + + // Some special cases: + // If the memory region is empty, we can just give up the region. + // If the current region is humongous then we only need to check + // the bitmap for the bit associated with the start of the object, + // scan the object if it's live, and give up the region. + // Otherwise, let's iterate over the bitmap of the part of the region + // that is left. + // If the iteration is successful, give up the region. + if (mr.is_empty()) { + giveup_current_region(); + regular_clock_call(); + } else if (_curr_region->isHumongous() && mr.start() == _curr_region->bottom()) { + if (_nextMarkBitMap->isMarked(mr.start())) { + // The object is marked - apply the closure + BitMap::idx_t offset = _nextMarkBitMap->heapWordToOffset(mr.start()); + bitmap_closure.do_bit(offset); + } + // Even if this task aborted while scanning the humongous object + // we can (and should) give up the current region. + giveup_current_region(); + regular_clock_call(); + } else if (_nextMarkBitMap->iterate(&bitmap_closure, mr)) { giveup_current_region(); regular_clock_call(); } else { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/g1/concurrentMark.hpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -371,8 +371,8 @@ friend class CalcLiveObjectsClosure; friend class G1CMRefProcTaskProxy; friend class G1CMRefProcTaskExecutor; - friend class G1CMParKeepAliveAndDrainClosure; - friend class G1CMParDrainMarkingStackClosure; + friend class G1CMKeepAliveAndDrainClosure; + friend class G1CMDrainMarkingStackClosure; protected: ConcurrentMarkThread* _cmThread; // the thread doing the work @@ -499,17 +499,26 @@ } // accessor methods - uint parallel_marking_threads() { return _parallel_marking_threads; } - uint max_parallel_marking_threads() { return _max_parallel_marking_threads;} - double sleep_factor() { return _sleep_factor; } - double marking_task_overhead() { return _marking_task_overhead;} - double cleanup_sleep_factor() { return _cleanup_sleep_factor; } - double cleanup_task_overhead() { return _cleanup_task_overhead;} + uint parallel_marking_threads() const { return _parallel_marking_threads; } + uint max_parallel_marking_threads() const { return _max_parallel_marking_threads;} + double sleep_factor() { return _sleep_factor; } + double marking_task_overhead() { return _marking_task_overhead;} + double cleanup_sleep_factor() { return _cleanup_sleep_factor; } + double cleanup_task_overhead() { return _cleanup_task_overhead;} - HeapWord* finger() { return _finger; } - bool concurrent() { return _concurrent; } - uint active_tasks() { return _active_tasks; } - ParallelTaskTerminator* terminator() { return &_terminator; } + bool use_parallel_marking_threads() const { + assert(parallel_marking_threads() <= + max_parallel_marking_threads(), "sanity"); + assert((_parallel_workers == NULL && parallel_marking_threads() == 0) || + parallel_marking_threads() > 0, + "parallel workers not set up correctly"); + return _parallel_workers != NULL; + } + + HeapWord* finger() { return _finger; } + bool concurrent() { return _concurrent; } + uint active_tasks() { return _active_tasks; } + ParallelTaskTerminator* terminator() { return &_terminator; } // It claims the next available region to be scanned by a marking // task/thread. It might return NULL if the next region is empty or diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp --- a/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -117,7 +117,7 @@ if (G1Log::fine()) { gclog_or_tty->date_stamp(PrintGCDateStamps); gclog_or_tty->stamp(PrintGCTimeStamps); - gclog_or_tty->print_cr("[GC concurrent-root-region-scan-end, %1.7lf]", + gclog_or_tty->print_cr("[GC concurrent-root-region-scan-end, %1.7lf secs]", scan_end - scan_start); } } @@ -150,7 +150,7 @@ if (G1Log::fine()) { gclog_or_tty->date_stamp(PrintGCDateStamps); gclog_or_tty->stamp(PrintGCTimeStamps); - gclog_or_tty->print_cr("[GC concurrent-mark-end, %1.7lf sec]", + gclog_or_tty->print_cr("[GC concurrent-mark-end, %1.7lf secs]", mark_end_sec - mark_start_sec); } @@ -234,7 +234,7 @@ if (G1Log::fine()) { gclog_or_tty->date_stamp(PrintGCDateStamps); gclog_or_tty->stamp(PrintGCTimeStamps); - gclog_or_tty->print_cr("[GC concurrent-cleanup-end, %1.7lf]", + gclog_or_tty->print_cr("[GC concurrent-cleanup-end, %1.7lf secs]", cleanup_end_sec - cleanup_start_sec); } } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1893,7 +1893,6 @@ _ref_processor_stw(NULL), _process_strong_tasks(new SubTasksDone(G1H_PS_NumElements)), _bot_shared(NULL), - _objs_with_preserved_marks(NULL), _preserved_marks_of_objs(NULL), _evac_failure_scan_stack(NULL) , _mark_in_progress(false), _cg1r(NULL), _summary_bytes_used(0), @@ -4225,22 +4224,15 @@ assert(check_cset_heap_region_claim_values(HeapRegion::InitialClaimValue), "sanity"); // Now restore saved marks, if any. - if (_objs_with_preserved_marks != NULL) { - assert(_preserved_marks_of_objs != NULL, "Both or none."); - guarantee(_objs_with_preserved_marks->length() == - _preserved_marks_of_objs->length(), "Both or none."); - for (int i = 0; i < _objs_with_preserved_marks->length(); i++) { - oop obj = _objs_with_preserved_marks->at(i); - markOop m = _preserved_marks_of_objs->at(i); - obj->set_mark(m); - } - - // Delete the preserved marks growable arrays (allocated on the C heap). - delete _objs_with_preserved_marks; - delete _preserved_marks_of_objs; - _objs_with_preserved_marks = NULL; - _preserved_marks_of_objs = NULL; - } + assert(_objs_with_preserved_marks.size() == + _preserved_marks_of_objs.size(), "Both or none."); + while (!_objs_with_preserved_marks.is_empty()) { + oop obj = _objs_with_preserved_marks.pop(); + markOop m = _preserved_marks_of_objs.pop(); + obj->set_mark(m); + } + _objs_with_preserved_marks.clear(true); + _preserved_marks_of_objs.clear(true); } void G1CollectedHeap::push_on_evac_failure_scan_stack(oop obj) { @@ -4323,15 +4315,8 @@ // We want to call the "for_promotion_failure" version only in the // case of a promotion failure. if (m->must_be_preserved_for_promotion_failure(obj)) { - if (_objs_with_preserved_marks == NULL) { - assert(_preserved_marks_of_objs == NULL, "Both or none."); - _objs_with_preserved_marks = - new (ResourceObj::C_HEAP, mtGC) GrowableArray(40, true); - _preserved_marks_of_objs = - new (ResourceObj::C_HEAP, mtGC) GrowableArray(40, true); - } - _objs_with_preserved_marks->push(obj); - _preserved_marks_of_objs->push(m); + _objs_with_preserved_marks.push(obj); + _preserved_marks_of_objs.push(m); } } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -37,6 +37,7 @@ #include "memory/barrierSet.hpp" #include "memory/memRegion.hpp" #include "memory/sharedHeap.hpp" +#include "utilities/stack.hpp" // A "G1CollectedHeap" is an implementation of a java heap for HotSpot. // It uses the "Garbage First" heap organization and algorithm, which @@ -883,10 +884,9 @@ // forwarding pointers to themselves. Reset them. void remove_self_forwarding_pointers(); - // When one is non-null, so is the other. Together, they each pair is - // an object with a preserved mark, and its mark value. - GrowableArray* _objs_with_preserved_marks; - GrowableArray* _preserved_marks_of_objs; + // Together, these store an object with a preserved mark, and its mark value. + Stack _objs_with_preserved_marks; + Stack _preserved_marks_of_objs; // Preserve the mark of "obj", if necessary, in preparation for its mark // word being overwritten with a self-forwarding-pointer. diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -267,7 +267,15 @@ double max_gc_time = (double) MaxGCPauseMillis / 1000.0; double time_slice = (double) GCPauseIntervalMillis / 1000.0; _mmu_tracker = new G1MMUTrackerQueue(time_slice, max_gc_time); - _sigma = (double) G1ConfidencePercent / 100.0; + + uintx confidence_perc = G1ConfidencePercent; + // Put an artificial ceiling on this so that it's not set to a silly value. + if (confidence_perc > 100) { + confidence_perc = 100; + warning("G1ConfidencePercent is set to a value that is too large, " + "it's been updated to %u", confidence_perc); + } + _sigma = (double) confidence_perc / 100.0; // start conservatively (around 50ms is about right) _concurrent_mark_remark_times_ms->add(0.05); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp --- a/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -28,8 +28,9 @@ #include "memory/cardTableModRefBS.hpp" #include "memory/memRegion.hpp" #include "oops/oop.inline.hpp" +#include "utilities/macros.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS class DirtyCardQueueSet; @@ -120,6 +121,6 @@ }; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1SATBCARDTABLEMODREFBS_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/g1/g1_globals.hpp --- a/src/share/vm/gc_implementation/g1/g1_globals.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -32,7 +32,7 @@ #define G1_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct, manageable, product_rw) \ \ - product(intx, G1ConfidencePercent, 50, \ + product(uintx, G1ConfidencePercent, 50, \ "Confidence level for MMU/pause predictions") \ \ develop(intx, G1MarkingOverheadPercent, 0, \ @@ -101,9 +101,6 @@ "to-space, we will allow regions whose survival rate is up to " \ "S + (1 - S)*X, where X is this parameter (as a fraction.)") \ \ - develop(intx, G1InitYoungSurvRatio, 50, \ - "Expected Survival Rate for newly allocated bytes") \ - \ develop(bool, G1SATBPrintStubs, false, \ "If true, print generated stubs for the SATB barrier") \ \ diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/g1/heapRegion.hpp --- a/src/share/vm/gc_implementation/g1/heapRegion.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/g1/heapRegion.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -32,8 +32,9 @@ #include "gc_implementation/shared/spaceDecorator.hpp" #include "memory/space.inline.hpp" #include "memory/watermark.hpp" +#include "utilities/macros.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // A HeapRegion is the smallest piece of a G1CollectedHeap that // can be collected independently. @@ -837,6 +838,6 @@ bool complete() { return _complete; } }; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGION_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/shared/allocationStats.cpp --- a/src/share/vm/gc_implementation/shared/allocationStats.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/allocationStats.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -23,10 +23,11 @@ */ #include "precompiled.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/allocationStats.hpp" #include "utilities/ostream.hpp" -#endif +#endif // INCLUDE_ALL_GCS // Technically this should be derived from machine speed, and // ideally it would be dynamically adjusted. diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/shared/allocationStats.hpp --- a/src/share/vm/gc_implementation/shared/allocationStats.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/allocationStats.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -25,11 +25,12 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_ALLOCATIONSTATS_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_ALLOCATIONSTATS_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/gcUtil.hpp" #include "memory/allocation.hpp" #include "utilities/globalDefinitions.hpp" -#endif +#endif // INCLUDE_ALL_GCS class AllocationStats VALUE_OBJ_CLASS_SPEC { // A duration threshold (in ms) used to filter diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/shared/concurrentGCThread.hpp --- a/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -25,9 +25,10 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_CONCURRENTGCTHREAD_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_CONCURRENTGCTHREAD_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "runtime/thread.hpp" -#endif +#endif // INCLUDE_ALL_GCS class VoidClosure; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/shared/gSpaceCounters.cpp --- a/src/share/vm/gc_implementation/shared/gSpaceCounters.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/gSpaceCounters.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -23,11 +23,12 @@ */ #include "precompiled.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/gSpaceCounters.hpp" #include "memory/generation.hpp" #include "memory/resourceArea.hpp" -#endif +#endif // INCLUDE_ALL_GCS GSpaceCounters::GSpaceCounters(const char* name, int ordinal, size_t max_size, Generation* g, GenerationCounters* gc, diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/shared/gSpaceCounters.hpp --- a/src/share/vm/gc_implementation/shared/gSpaceCounters.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/gSpaceCounters.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -25,11 +25,12 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_GSPACECOUNTERS_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_GSPACECOUNTERS_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/generationCounters.hpp" #include "memory/generation.hpp" #include "runtime/perfData.hpp" -#endif +#endif // INCLUDE_ALL_GCS // A GSpaceCounter is a holder class for performance counters // that track a space; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/shared/gcAdaptivePolicyCounters.hpp --- a/src/share/vm/gc_implementation/shared/gcAdaptivePolicyCounters.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/gcAdaptivePolicyCounters.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -25,10 +25,11 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_GCADAPTIVEPOLICYCOUNTERS_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_GCADAPTIVEPOLICYCOUNTERS_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/adaptiveSizePolicy.hpp" #include "gc_implementation/shared/gcPolicyCounters.hpp" -#endif +#endif // INCLUDE_ALL_GCS // This class keeps statistical information and computes the // size of the heap. diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/shared/hSpaceCounters.hpp --- a/src/share/vm/gc_implementation/shared/hSpaceCounters.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/hSpaceCounters.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -25,11 +25,12 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_HSPACECOUNTERS_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_HSPACECOUNTERS_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/generationCounters.hpp" #include "memory/generation.hpp" #include "runtime/perfData.hpp" -#endif +#endif // INCLUDE_ALL_GCS // A HSpaceCounter is a holder class for performance counters // that track a collections (logical spaces) in a heap; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/shared/immutableSpace.cpp --- a/src/share/vm/gc_implementation/shared/immutableSpace.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/immutableSpace.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -23,11 +23,12 @@ */ #include "precompiled.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/immutableSpace.hpp" #include "memory/universe.hpp" #include "oops/oop.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS void ImmutableSpace::initialize(MemRegion mr) { HeapWord* bottom = mr.start(); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/shared/isGCActiveMark.hpp --- a/src/share/vm/gc_implementation/shared/isGCActiveMark.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/isGCActiveMark.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -25,9 +25,10 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_ISGCACTIVEMARK_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_ISGCACTIVEMARK_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" -#endif +#endif // INCLUDE_ALL_GCS // This class provides a method for block structured setting of the // _is_gc_active state without requiring accessors in CollectedHeap diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/shared/markSweep.inline.hpp --- a/src/share/vm/gc_implementation/shared/markSweep.inline.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/markSweep.inline.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -28,9 +28,10 @@ #include "gc_implementation/shared/markSweep.hpp" #include "gc_interface/collectedHeap.hpp" #include "utilities/stack.inline.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/psParallelCompact.hpp" -#endif +#endif // INCLUDE_ALL_GCS inline void MarkSweep::mark_object(oop obj) { // some marks may contain information we need to preserve so we store them away diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp --- a/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -25,10 +25,11 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_MUTABLENUMASPACE_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_MUTABLENUMASPACE_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/gcUtil.hpp" #include "gc_implementation/shared/mutableSpace.hpp" -#endif +#endif // INCLUDE_ALL_GCS /* * The NUMA-aware allocator (MutableNUMASpace) is basically a modification diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/shared/mutableSpace.cpp --- a/src/share/vm/gc_implementation/shared/mutableSpace.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/mutableSpace.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -23,13 +23,14 @@ */ #include "precompiled.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/mutableSpace.hpp" #include "gc_implementation/shared/spaceDecorator.hpp" #include "oops/oop.inline.hpp" #include "runtime/safepoint.hpp" #include "runtime/thread.hpp" -#endif +#endif // INCLUDE_ALL_GCS MutableSpace::MutableSpace(size_t alignment): ImmutableSpace(), _top(NULL), _alignment(alignment) { assert(MutableSpace::alignment() >= 0 && diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/shared/spaceCounters.cpp --- a/src/share/vm/gc_implementation/shared/spaceCounters.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/spaceCounters.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -23,10 +23,11 @@ */ #include "precompiled.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/spaceCounters.hpp" #include "memory/resourceArea.hpp" -#endif +#endif // INCLUDE_ALL_GCS SpaceCounters::SpaceCounters(const char* name, int ordinal, size_t max_size, MutableSpace* m, GenerationCounters* gc) : diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/shared/spaceCounters.hpp --- a/src/share/vm/gc_implementation/shared/spaceCounters.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/spaceCounters.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -25,12 +25,13 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_SPACECOUNTERS_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_SPACECOUNTERS_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/generationCounters.hpp" #include "gc_implementation/shared/immutableSpace.hpp" #include "gc_implementation/shared/mutableSpace.hpp" #include "runtime/perfData.hpp" -#endif +#endif // INCLUDE_ALL_GCS // A SpaceCounter is a holder class for performance counters // that track a space; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/shared/vmGCOperations.cpp --- a/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,9 +36,10 @@ #include "runtime/interfaceSupport.hpp" #include "utilities/dtrace.hpp" #include "utilities/preserveException.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifndef USDT2 HS_DTRACE_PROBE_DECL1(hotspot, gc__begin, bool); @@ -167,7 +168,9 @@ ch->collect_as_vm_thread(GCCause::_heap_inspection); } } - HeapInspection::heap_inspection(_out, _need_prologue /* need_prologue */); + HeapInspection inspect(_csv_format, _print_help, _print_class_stats, + _columns); + inspect.heap_inspection(_out, _need_prologue /* need_prologue */); } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/gc_implementation/shared/vmGCOperations.hpp --- a/src/share/vm/gc_implementation/shared/vmGCOperations.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/gc_implementation/shared/vmGCOperations.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -130,6 +130,10 @@ outputStream* _out; bool _full_gc; bool _need_prologue; + bool _csv_format; // "comma separated values" format for spreadsheet. + bool _print_help; + bool _print_class_stats; + const char* _columns; public: VM_GC_HeapInspection(outputStream* out, bool request_full_gc, bool need_prologue) : @@ -140,6 +144,10 @@ _out = out; _full_gc = request_full_gc; _need_prologue = need_prologue; + _csv_format = false; + _print_help = false; + _print_class_stats = false; + _columns = NULL; } ~VM_GC_HeapInspection() {} @@ -147,6 +155,10 @@ virtual bool skip_operation() const; virtual bool doit_prologue(); virtual void doit(); + void set_csv_format(bool value) {_csv_format = value;} + void set_print_help(bool value) {_print_help = value;} + void set_print_class_stats(bool value) {_print_class_stats = value;} + void set_columns(const char* value) {_columns = value;} }; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -29,7 +29,6 @@ #include "graal/graalCodeInstaller.hpp" #include "graal/graalJavaAccess.hpp" #include "graal/graalCompilerToVM.hpp" -#include "graal/graalVmIds.hpp" #include "graal/graalRuntime.hpp" #include "asm/register.hpp" #include "classfile/vmSymbols.hpp" @@ -127,6 +126,10 @@ assert((Klass*) prim == klass, err_msg("%s @ %p != %p", klass->name()->as_C_string(), klass, prim)); int index = oop_recorder->find_index(klass); TRACE_graal_3("metadata[%d of %d] = %s", index, oop_recorder->metadata_count(), klass->name()->as_C_string()); + } else if (obj->is_a(HotSpotResolvedJavaMethod::klass())) { + Method* method = (Method*) (address) HotSpotResolvedJavaMethod::metaspaceMethod(obj); + int index = oop_recorder->find_index(method); + TRACE_graal_3("metadata[%d of %d] = %s", index, oop_recorder->metadata_count(), method->name()->as_C_string()); } else { assert(java_lang_String::is_instance(obj), err_msg("unexpected annotation type (%s) for constant %ld (%p) of kind %c", obj->klass()->name()->as_C_string(), prim, prim, kind)); @@ -209,7 +212,7 @@ return new ConstantOopWriteValue(JNIHandles::make_local(obj)); } } else if (type == T_ADDRESS) { - return new ConstantLongValue(prim); + ShouldNotReachHere(); } tty->print("%i", type); } else if (value->is_a(VirtualObject::klass())) { @@ -323,7 +326,7 @@ } // constructor used to create a method -CodeInstaller::CodeInstaller(Handle& comp_result, methodHandle method, GraalEnv::CodeInstallResult& result, nmethod*& nm, Handle installed_code) { +CodeInstaller::CodeInstaller(Handle& comp_result, methodHandle method, GraalEnv::CodeInstallResult& result, nmethod*& nm, Handle installed_code, Handle triggered_deoptimizations) { GraalCompiler::initialize_buffer_blob(); CodeBuffer buffer(JavaThread::current()->get_buffer_blob()); jobject comp_result_obj = JNIHandles::make_local(comp_result()); @@ -341,7 +344,7 @@ GrowableArray* leaf_graph_ids = get_leaf_graph_ids(comp_result); result = GraalEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table, - &_implicit_exception_table, GraalCompiler::instance(), _debug_recorder, _dependencies, NULL, -1, true, false, leaf_graph_ids, installed_code); + GraalCompiler::instance(), _debug_recorder, _dependencies, NULL, -1, true, false, leaf_graph_ids, installed_code, triggered_deoptimizations); method->clear_queued_for_compilation(); } @@ -362,7 +365,7 @@ const char* cname = java_lang_String::as_utf8_string(_name); blob = BufferBlob::create(strdup(cname), &buffer); // this is leaking strings... but only a limited number of stubs will be created IF_TRACE_graal_3 Disassembler::decode((CodeBlob*) blob); - id = VmIds::addStub(blob->code_begin()); + id = (jlong)blob->code_begin(); } void CodeInstaller::initialize_fields(oop comp_result, methodHandle method) { @@ -383,7 +386,6 @@ // (very) conservative estimate: each site needs a constant section entry _constants_size = _sites->length() * (BytesPerLong*2); - _total_size = align_size_up(_code_size, HeapWordSize) + _constants_size; _next_call_type = MARK_INVOKE_INVALID; } @@ -572,13 +574,9 @@ DebugToken* expressions_token = _debug_recorder->create_scope_values(expressions); DebugToken* monitors_token = _debug_recorder->create_monitor_values(monitors); - GrowableArray* deferred_writes = new GrowableArray (); -// deferred_writes->append(new DeferredWriteValue(new LocationValue(Location::new_reg_loc(Location::lng, rax->as_VMReg())), new ConstantIntValue(0), 0, 100, new ConstantIntValue(123))); - DebugToken* deferred_writes_token = _debug_recorder->create_deferred_writes(deferred_writes); - bool throw_exception = BytecodeFrame::rethrowException(frame) == JNI_TRUE; - _debug_recorder->describe_scope(pc_offset, method, NULL, bci, reexecute, throw_exception, false, false, locals_token, expressions_token, monitors_token, deferred_writes_token); + _debug_recorder->describe_scope(pc_offset, method, NULL, bci, reexecute, throw_exception, false, false, locals_token, expressions_token, monitors_token); } void CodeInstaller::site_Safepoint(CodeBuffer& buffer, jint pc_offset, oop site) { @@ -606,7 +604,7 @@ oop hotspot_method = NULL; // JavaMethod oop global_stub = NULL; - if (target_klass->is_subclass_of(SystemDictionary::Long_klass())) { + if (target_klass->is_subclass_of(SystemDictionary::HotSpotRuntimeCallTarget_klass())) { global_stub = target; } else { hotspot_method = target; @@ -618,7 +616,6 @@ NativeInstruction* inst = nativeInstruction_at(_instructions->start() + pc_offset); jint next_pc_offset = 0x0; - bool is_call_reg = false; if (inst->is_call() || inst->is_jump()) { assert(NativeCall::instruction_size == (int)NativeJump::instruction_size, "unexpected size"); next_pc_offset = pc_offset + NativeCall::instruction_size; @@ -631,10 +628,8 @@ } else if (inst->is_call_reg()) { // the inlined vtable stub contains a "call register" instruction assert(hotspot_method != NULL, "only valid for virtual calls"); - is_call_reg = true; next_pc_offset = pc_offset + ((NativeCallReg *) inst)->next_instruction_offset(); } else { - tty->print_cr("at pc_offset %d", pc_offset); fatal("unsupported type of instruction for call site"); } @@ -659,21 +654,20 @@ } if (global_stub != NULL) { - assert(java_lang_boxing_object::is_instance(global_stub, T_LONG), "global_stub needs to be of type Long"); - + jlong global_stub_destination = HotSpotRuntimeCallTarget::address(global_stub); if (inst->is_call()) { // NOTE: for call without a mov, the offset must fit a 32-bit immediate // see also CompilerToVM.getMaxCallTargetOffset() NativeCall* call = nativeCall_at((address) (inst)); - call->set_destination(VmIds::getStub(global_stub)); + call->set_destination((address) global_stub_destination); _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); } else if (inst->is_mov_literal64()) { NativeMovConstReg* mov = nativeMovConstReg_at((address) (inst)); - mov->set_data((intptr_t) VmIds::getStub(global_stub)); + mov->set_data((intptr_t) global_stub_destination); _instructions->relocate(mov->instruction_address(), runtime_call_Relocation::spec(), Assembler::imm_operand); } else { NativeJump* jump = nativeJump_at((address) (inst)); - jump->set_jump_destination(VmIds::getStub(global_stub)); + jump->set_jump_destination((address) global_stub_destination); _instructions->relocate((address)inst, runtime_call_Relocation::spec(), Assembler::call32_operand); } TRACE_graal_3("relocating (stub) at %p", inst); @@ -690,9 +684,8 @@ TRACE_graal_3("method call"); switch (_next_call_type) { - case MARK_INLINE_INVOKEVIRTUAL: { + case MARK_INLINE_INVOKE: break; - } case MARK_INVOKEVIRTUAL: case MARK_INVOKEINTERFACE: { assert(method == NULL || !method->is_static(), "cannot call static method with invokeinterface"); @@ -712,13 +705,11 @@ } case MARK_INVOKESPECIAL: { assert(method == NULL || !method->is_static(), "cannot call static method with invokespecial"); - NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub()); _instructions->relocate(call->instruction_address(), relocInfo::opt_virtual_call_type, Assembler::call32_operand); break; } - case MARK_INVOKE_INVALID: default: fatal("invalid _next_call_type value"); break; @@ -818,14 +809,6 @@ case MARK_DEOPT_HANDLER_ENTRY: _offsets.set_value(CodeOffsets::Deopt, pc_offset); break; - case MARK_STATIC_CALL_STUB: { - _instructions->relocate(instruction, metadata_Relocation::spec_for_immediate()); - assert(references->length() == 1, "static call stub needs one reference"); - oop ref = ((oop*) references->base(T_OBJECT))[0]; - address call_pc = _instructions->start() + CompilationResult_Site::pcOffset(ref); - _instructions->relocate(instruction, static_stub_Relocation::spec(call_pc)); - break; - } case MARK_INVOKEVIRTUAL: case MARK_INVOKEINTERFACE: { // Convert the initial value of the Klass* slot in an inline cache @@ -834,16 +817,12 @@ assert(n_copy->data() == 0, "inline cache Klass* initial value should be 0L"); n_copy->set_data((intptr_t)Universe::non_oop_word()); } - case MARK_INLINE_INVOKEVIRTUAL: - case MARK_INVOKE_INVALID: + case MARK_INLINE_INVOKE: + case MARK_INVOKESTATIC: case MARK_INVOKESPECIAL: - case MARK_INVOKESTATIC: _next_call_type = (MarkId) id; _invoke_mark_pc = instruction; break; - case MARK_IMPLICIT_NULL: - _implicit_exception_table.append(pc_offset, pc_offset); - break; case MARK_POLL_NEAR: { NativeInstruction* ni = nativeInstruction_at(instruction); int32_t* disp = (int32_t*) Assembler::locate_operand(instruction, Assembler::disp32_operand); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/graal/graalCodeInstaller.hpp --- a/src/share/vm/graal/graalCodeInstaller.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/graal/graalCodeInstaller.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -31,24 +31,21 @@ private: // these need to correspond to Marks.java enum MarkId { - MARK_VERIFIED_ENTRY = 0x0001, - MARK_UNVERIFIED_ENTRY = 0x0002, - MARK_OSR_ENTRY = 0x0003, - //MARK_UNWIND_ENTRY = 0x0004, - MARK_EXCEPTION_HANDLER_ENTRY = 0x0005, - MARK_DEOPT_HANDLER_ENTRY = 0x0006, - MARK_STATIC_CALL_STUB = 0x1000, - MARK_INVOKE_INVALID = 0x2000, - MARK_INVOKEINTERFACE = 0x2001, - MARK_INVOKESTATIC = 0x2002, - MARK_INVOKESPECIAL = 0x2003, - MARK_INVOKEVIRTUAL = 0x2004, - MARK_INLINE_INVOKEVIRTUAL = 0x2005, - MARK_IMPLICIT_NULL = 0x3000, - MARK_POLL_NEAR = 0x3001, - MARK_POLL_RETURN_NEAR = 0x3002, - MARK_POLL_FAR = 0x3003, - MARK_POLL_RETURN_FAR = 0x3004 + MARK_VERIFIED_ENTRY = 1, + MARK_UNVERIFIED_ENTRY = 2, + MARK_OSR_ENTRY = 3, + MARK_EXCEPTION_HANDLER_ENTRY = 4, + MARK_DEOPT_HANDLER_ENTRY = 5, + MARK_INVOKEINTERFACE = 6, + MARK_INVOKEVIRTUAL = 7, + MARK_INVOKESTATIC = 8, + MARK_INVOKESPECIAL = 9, + MARK_INLINE_INVOKE = 10, + MARK_POLL_NEAR = 11, + MARK_POLL_RETURN_NEAR = 12, + MARK_POLL_FAR = 13, + MARK_POLL_RETURN_FAR = 14, + MARK_INVOKE_INVALID = -1 }; Arena _arena; @@ -65,7 +62,6 @@ jint _custom_stack_area_offset; jint _parameter_count; jint _constants_size; - jint _total_size; MarkId _next_call_type; address _invoke_mark_pc; @@ -77,12 +73,11 @@ DebugInformationRecorder* _debug_recorder; Dependencies* _dependencies; ExceptionHandlerTable _exception_handler_table; - ImplicitExceptionTable _implicit_exception_table; public: // constructor used to create a method - CodeInstaller(Handle& comp_result, methodHandle method, GraalEnv::CodeInstallResult& result, nmethod*& nm, Handle installed_code); + CodeInstaller(Handle& comp_result, methodHandle method, GraalEnv::CodeInstallResult& result, nmethod*& nm, Handle installed_code, Handle triggered_deoptimizations); // constructor used to create a stub CodeInstaller(Handle& target_method, BufferBlob*& blob, jlong& id); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/graal/graalCompiler.cpp --- a/src/share/vm/graal/graalCompiler.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/graal/graalCompiler.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -28,7 +28,6 @@ #include "graal/graalJavaAccess.hpp" #include "graal/graalVMToCompiler.hpp" #include "graal/graalCompilerToVM.hpp" -#include "graal/graalVmIds.hpp" #include "graal/graalEnv.hpp" #include "graal/graalRuntime.hpp" #include "runtime/arguments.hpp" @@ -160,11 +159,10 @@ assert(_initialized, "must already be initialized"); ResourceMark rm; - assert(JavaThread::current()->env() == NULL, "ciEnv should be null"); - JavaThread::current()->set_compiling(true); + JavaThread::current()->set_is_compiling(true); Handle holder = GraalCompiler::createHotSpotResolvedObjectType(method, CHECK); jboolean success = VMToCompiler::compileMethod(method(), holder, entry_bci, blocking, method->graal_priority()); - JavaThread::current()->set_compiling(false); + JavaThread::current()->set_is_compiling(false); if (success != JNI_TRUE) { method->clear_queued_for_compilation(); CompilationPolicy::policy()->delay_compilation(method()); @@ -188,7 +186,7 @@ } Handle GraalCompiler::get_JavaType(Symbol* klass_name, TRAPS) { - return VMToCompiler::createUnresolvedJavaType(VmIds::toString(klass_name, THREAD), THREAD); + return VMToCompiler::createUnresolvedJavaType(java_lang_String::create_from_symbol(klass_name, THREAD), THREAD); } Handle GraalCompiler::get_JavaTypeFromSignature(Symbol* signature, KlassHandle loading_klass, TRAPS) { @@ -255,12 +253,12 @@ } Handle GraalCompiler::get_JavaType(KlassHandle klass, TRAPS) { - Handle name = VmIds::toString(klass->name(), THREAD); + Handle name = java_lang_String::create_from_symbol(klass->name(), THREAD); return createHotSpotResolvedObjectType(klass, name, CHECK_NULL); } Handle GraalCompiler::get_JavaField(int offset, int flags, Symbol* field_name, Handle field_holder, Handle field_type, TRAPS) { - Handle name = VmIds::toString(field_name, CHECK_NULL); + Handle name = java_lang_String::create_from_symbol(field_name, CHECK_NULL); return VMToCompiler::createJavaField(field_holder, name, field_type, offset, flags, false, CHECK_NULL); } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -37,7 +37,6 @@ #include "graal/graalJavaAccess.hpp" #include "graal/graalCodeInstaller.hpp" #include "graal/graalVMToCompiler.hpp" -#include "graal/graalVmIds.hpp" #include "gc_implementation/g1/heapRegion.hpp" @@ -87,7 +86,7 @@ memcpy(reconstituted_code, (jbyte *) method->code_base(), code_size); } BytecodeStream s(method); - while(!s.is_last_bytecode()) { + while (!s.is_last_bytecode()) { s.next(); Bytecodes::Code opcode = s.raw_code(); if (!Bytecodes::is_java_code(opcode)) { @@ -121,7 +120,7 @@ C2V_VMENTRY(jstring, getSignature, (JNIEnv *env, jobject, jlong metaspace_method)) Method* method = asMethod(metaspace_method); assert(method != NULL && method->signature() != NULL, "signature required"); - return VmIds::toString(method->signature(), THREAD); + return (jstring)JNIHandles::make_local(java_lang_String::create_from_symbol(method->signature(), THREAD)()); C2V_END C2V_VMENTRY(jobjectArray, initializeExceptionHandlers, (JNIEnv *, jobject, jlong metaspace_method, jobjectArray java_handlers)) @@ -272,7 +271,7 @@ C2V_VMENTRY(void, initializeMethod,(JNIEnv *, jobject, jlong metaspace_method, jobject hotspot_method)) methodHandle method = asMethod(metaspace_method); - Handle name = VmIds::toString(method->name(), CHECK); + Handle name = java_lang_String::create_from_symbol(method->name(), CHECK); InstanceKlass::cast(HotSpotResolvedJavaMethod::klass())->initialize(CHECK); HotSpotResolvedJavaMethod::set_name(hotspot_method, name()); HotSpotResolvedJavaMethod::set_codeSize(hotspot_method, method->code_size()); @@ -324,8 +323,8 @@ C2V_VMENTRY(jobject, lookupType, (JNIEnv *env, jobject, jstring jname, jobject accessingClass, jboolean eagerResolve)) ResourceMark rm; - Symbol* nameSymbol = VmIds::toSymbol(jname); Handle name = JNIHandles::resolve(jname); + Symbol* nameSymbol = java_lang_String::as_symbol(name, THREAD); assert(nameSymbol != NULL, "name to symbol creation failed"); oop result = NULL; @@ -409,10 +408,6 @@ } else if (tag.is_klass() || tag.is_unresolved_klass()) { Handle type = GraalCompiler::get_JavaType(cp, index, cp->pool_holder(), CHECK_NULL); result = type(); - } else if (tag.is_object()) { - oop obj = cp->object_at(index); - assert(obj->is_instance(), "must be an instance"); - result = VMToCompiler::createConstantObject(obj, CHECK_NULL); } else { tty->print("unknown constant pool tag (%s) at cpi %d in %s: ", tag.internal_name(), index, cp->pool_holder()->name()->as_C_string()); ShouldNotReachHere(); @@ -433,8 +428,8 @@ return JNIHandles::make_local(THREAD, VMToCompiler::createResolvedJavaMethod(holder, method(), THREAD)); } else { // Get the method's name and signature. - Handle name = VmIds::toString(cp->name_ref_at(index), CHECK_NULL); - Handle signature = VmIds::toString(cp->signature_ref_at(index), CHECK_NULL); + 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); return JNIHandles::make_local(THREAD, VMToCompiler::createUnresolvedJavaMethod(name, signature, type, THREAD)); @@ -515,8 +510,8 @@ assert(JNIHandles::resolve(resolved_type) != NULL, ""); Klass* klass = java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(resolved_type)); - Symbol* name_symbol = VmIds::toSymbol(name); - Symbol* signature_symbol = VmIds::toSymbol(signature); + Symbol* name_symbol = java_lang_String::as_symbol(JNIHandles::resolve(name), THREAD); + Symbol* signature_symbol = java_lang_String::as_symbol(JNIHandles::resolve(signature), THREAD); methodHandle method = klass->lookup_method(name_symbol, signature_symbol); if (method.is_null()) { if (TraceGraal >= 3) { @@ -552,7 +547,7 @@ Handle type = GraalCompiler::get_JavaTypeFromSignature(fs.signature(), k, Thread::current()); int flags = fs.access_flags().as_int(); bool internal = fs.access_flags().is_internal(); - Handle name = VmIds::toString(fs.name(), Thread::current()); + Handle name = java_lang_String::create_from_symbol(fs.name(), Thread::current()); Handle field = VMToCompiler::createJavaField(JNIHandles::resolve(klass), name, type, fs.offset(), flags, internal, Thread::current()); fields.append(field()); } @@ -599,6 +594,7 @@ #define set_boolean(name, value) do { env->SetBooleanField(config, getFieldID(env, config, name, "Z"), value); } while (0) #define set_int(name, value) do { env->SetIntField(config, getFieldID(env, config, name, "I"), value); } while (0) #define set_long(name, value) do { env->SetLongField(config, getFieldID(env, config, name, "J"), value); } while (0) +#define set_stub(name, value) do { set_long(name, (jlong) value); } while (0) #define set_object(name, value) do { env->SetObjectField(config, getFieldID(env, config, name, "Ljava/lang/Object;"), value); } while (0) #define set_int_array(name, value) do { env->SetObjectField(config, getFieldID(env, config, name, "[I"), value); } while (0) @@ -617,7 +613,6 @@ set_boolean("useTLAB", UseTLAB); set_boolean("useG1GC", UseG1GC); set_int("codeEntryAlignment", CodeEntryAlignment); - set_int("vmPageSize", os::vm_page_size()); set_int("stackShadowPages", StackShadowPages); set_int("hubOffset", oopDesc::klass_offset_in_bytes()); set_int("markOffset", oopDesc::mark_offset_in_bytes()); @@ -669,6 +664,9 @@ 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())); + set_int("metaspaceArrayLengthOffset", Array::length_offset_in_bytes()); set_int("metaspaceArrayBaseOffset", Array::base_offset_in_bytes()); set_int("methodDataOopDataOffset", in_bytes(MethodData::data_offset())); @@ -709,44 +707,42 @@ set_int("layoutHelperHeaderSizeMask", Klass::_lh_header_size_mask); set_int("layoutHelperOffset", in_bytes(Klass::layout_helper_offset())); - set_long("debugStub", VmIds::addStub((address)warning)); - set_long("instanceofStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_slow_subtype_check_id))); - set_long("newInstanceStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_new_instance_id))); - set_long("newArrayStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_new_array_id))); - set_long("newMultiArrayStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_new_multi_array_id))); - set_long("identityHashCodeStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_identity_hash_code_id))); - set_long("threadIsInterruptedStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_thread_is_interrupted_id))); - set_long("inlineCacheMissStub", VmIds::addStub(SharedRuntime::get_ic_miss_stub())); - set_long("handleExceptionStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_handle_exception_nofpu_id))); - set_long("handleDeoptStub", VmIds::addStub(SharedRuntime::deopt_blob()->unpack())); - set_long("monitorEnterStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_monitorenter_id))); - set_long("monitorExitStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_monitorexit_id))); - set_long("wbPreCallStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_wb_pre_call_id))); - set_long("wbPostCallStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_wb_post_call_id))); + + set_stub("wbPreCallStub", GraalRuntime::entry_for(GraalRuntime::wb_pre_call_id)); + set_stub("wbPostCallStub", GraalRuntime::entry_for(GraalRuntime::wb_post_call_id)); - set_long("verifyOopStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_verify_oop_id))); - set_long("vmErrorStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_vm_error_id))); - set_long("deoptimizeStub", VmIds::addStub(SharedRuntime::deopt_blob()->uncommon_trap())); - set_long("unwindExceptionStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_unwind_exception_call_id))); - set_long("osrMigrationEndStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_OSR_migration_end_id))); - set_long("registerFinalizerStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_register_finalizer_id))); - set_long("setDeoptInfoStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_set_deopt_info_id))); - set_long("createNullPointerExceptionStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_create_null_pointer_exception_id))); - set_long("createOutOfBoundsExceptionStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_create_out_of_bounds_exception_id))); - set_long("javaTimeMillisStub", VmIds::addStub(CAST_FROM_FN_PTR(address, os::javaTimeMillis))); - set_long("javaTimeNanosStub", VmIds::addStub(CAST_FROM_FN_PTR(address, os::javaTimeNanos))); - set_long("arithmeticFremStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_arithmetic_frem_id))); - set_long("arithmeticDremStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_arithmetic_drem_id))); - set_long("arithmeticSinStub", VmIds::addStub(CAST_FROM_FN_PTR(address, SharedRuntime::dsin))); - set_long("arithmeticCosStub", VmIds::addStub(CAST_FROM_FN_PTR(address, SharedRuntime::dcos))); - set_long("arithmeticTanStub", VmIds::addStub(CAST_FROM_FN_PTR(address, SharedRuntime::dtan))); - set_long("logPrimitiveStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_log_primitive_id))); - set_long("logObjectStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_log_object_id))); - set_long("logPrintfStub", VmIds::addStub(GraalRuntime::entry_for(GraalRuntime::graal_log_printf_id))); - set_long("aescryptEncryptBlockStub", VmIds::addStub(StubRoutines::aescrypt_encryptBlock())); - set_long("aescryptDecryptBlockStub", VmIds::addStub(StubRoutines::aescrypt_decryptBlock())); - set_long("cipherBlockChainingEncryptAESCryptStub", VmIds::addStub(StubRoutines::cipherBlockChaining_encryptAESCrypt())); - set_long("cipherBlockChainingDecryptAESCryptStub", VmIds::addStub(StubRoutines::cipherBlockChaining_decryptAESCrypt())); + set_stub("newInstanceStub", GraalRuntime::entry_for(GraalRuntime::new_instance_id)); + set_stub("newArrayStub", GraalRuntime::entry_for(GraalRuntime::new_array_id)); + set_stub("newMultiArrayStub", GraalRuntime::entry_for(GraalRuntime::new_multi_array_id)); + set_stub("identityHashCodeStub", GraalRuntime::entry_for(GraalRuntime::identity_hash_code_id)); + set_stub("threadIsInterruptedStub", GraalRuntime::entry_for(GraalRuntime::thread_is_interrupted_id)); + set_stub("inlineCacheMissStub", SharedRuntime::get_ic_miss_stub()); + set_stub("handleExceptionStub", GraalRuntime::entry_for(GraalRuntime::handle_exception_nofpu_id)); + set_stub("handleDeoptStub", SharedRuntime::deopt_blob()->unpack()); + set_stub("monitorEnterStub", GraalRuntime::entry_for(GraalRuntime::monitorenter_id)); + set_stub("monitorExitStub", GraalRuntime::entry_for(GraalRuntime::monitorexit_id)); + set_stub("verifyOopStub", GraalRuntime::entry_for(GraalRuntime::verify_oop_id)); + set_stub("vmErrorStub", GraalRuntime::entry_for(GraalRuntime::vm_error_id)); + set_stub("deoptimizeStub", SharedRuntime::deopt_blob()->uncommon_trap()); + set_stub("unwindExceptionStub", GraalRuntime::entry_for(GraalRuntime::unwind_exception_call_id)); + set_stub("osrMigrationEndStub", GraalRuntime::entry_for(GraalRuntime::OSR_migration_end_id)); + set_stub("registerFinalizerStub", GraalRuntime::entry_for(GraalRuntime::register_finalizer_id)); + set_stub("createNullPointerExceptionStub", GraalRuntime::entry_for(GraalRuntime::create_null_pointer_exception_id)); + set_stub("createOutOfBoundsExceptionStub", GraalRuntime::entry_for(GraalRuntime::create_out_of_bounds_exception_id)); + set_stub("javaTimeMillisStub", CAST_FROM_FN_PTR(address, os::javaTimeMillis)); + set_stub("javaTimeNanosStub", CAST_FROM_FN_PTR(address, os::javaTimeNanos)); + set_stub("arithmeticFremStub", GraalRuntime::entry_for(GraalRuntime::arithmetic_frem_id)); + set_stub("arithmeticDremStub", GraalRuntime::entry_for(GraalRuntime::arithmetic_drem_id)); + set_stub("arithmeticSinStub", CAST_FROM_FN_PTR(address, SharedRuntime::dsin)); + set_stub("arithmeticCosStub", CAST_FROM_FN_PTR(address, SharedRuntime::dcos)); + set_stub("arithmeticTanStub", CAST_FROM_FN_PTR(address, SharedRuntime::dtan)); + set_stub("logPrimitiveStub", GraalRuntime::entry_for(GraalRuntime::log_primitive_id)); + set_stub("logObjectStub", GraalRuntime::entry_for(GraalRuntime::log_object_id)); + set_stub("logPrintfStub", GraalRuntime::entry_for(GraalRuntime::log_printf_id)); + set_stub("aescryptEncryptBlockStub", StubRoutines::aescrypt_encryptBlock()); + set_stub("aescryptDecryptBlockStub", StubRoutines::aescrypt_decryptBlock()); + set_stub("cipherBlockChainingEncryptAESCryptStub", StubRoutines::cipherBlockChaining_encryptAESCrypt()); + set_stub("cipherBlockChainingDecryptAESCryptStub", StubRoutines::cipherBlockChaining_decryptAESCrypt()); set_int("deoptReasonNone", Deoptimization::Reason_none); set_int("deoptReasonNullCheck", Deoptimization::Reason_null_check); @@ -807,49 +803,43 @@ C2V_END -C2V_VMENTRY(jint, installCode0, (JNIEnv *jniEnv, jobject, jobject compResult, jobject installed_code, jobject info)) +C2V_VMENTRY(jint, installCode0, (JNIEnv *jniEnv, jobject, jobject compResult, jobject installed_code, jobject triggered_deoptimizations)) ResourceMark rm; HandleMark hm; Handle compResultHandle = JNIHandles::resolve(compResult); nmethod* nm = NULL; methodHandle method = getMethodFromHotSpotMethod(HotSpotCompilationResult::method(compResult)); Handle installed_code_handle = JNIHandles::resolve(installed_code); + Handle triggered_deoptimizations_handle = JNIHandles::resolve(triggered_deoptimizations); GraalEnv::CodeInstallResult result; - CodeInstaller installer(compResultHandle, method, result, nm, installed_code_handle); + CodeInstaller installer(compResultHandle, method, result, nm, installed_code_handle, triggered_deoptimizations_handle); if (result != GraalEnv::ok) { assert(nm == NULL, "should be"); } else { - if (info != NULL) { - arrayOop codeCopy = oopFactory::new_byteArray(nm->code_size(), CHECK_0); - memcpy(codeCopy->base(T_BYTE), nm->code_begin(), nm->code_size()); - HotSpotCodeInfo::set_code(info, codeCopy); - HotSpotCodeInfo::set_start(info, (jlong) nm->code_begin()); - } - if (!installed_code_handle.is_null()) { assert(installed_code_handle->is_a(HotSpotInstalledCode::klass()), "wrong type"); HotSpotInstalledCode::set_nmethod(installed_code_handle, (jlong) nm); HotSpotInstalledCode::set_method(installed_code_handle, HotSpotCompilationResult::method(compResult)); + HotSpotInstalledCode::set_start(installed_code_handle, (jlong) nm->code_begin()); assert(nm == NULL || !installed_code_handle->is_scavengable() || nm->on_scavenge_root_list(), "nm should be scavengable if installed_code is scavengable"); } } return result; C2V_END -C2V_VMENTRY(jobject, disassembleNative, (JNIEnv *jniEnv, jobject, jbyteArray code, jlong start_address)) +C2V_VMENTRY(jobject, getCode, (JNIEnv *jniEnv, jobject, jlong metaspace_nmethod)) ResourceMark rm; HandleMark hm; - stringStream(st); - arrayOop code_oop = (arrayOop) JNIHandles::resolve(code); - int len = code_oop->length(); - address begin = (address) code_oop->base(T_BYTE); - address end = begin + len; - Disassembler::decode(begin, end, &st); - - Handle result = java_lang_String::create_from_platform_dependent_str(st.as_string(), CHECK_NULL); - return JNIHandles::make_local(result()); + nmethod* nm = (nmethod*) (address) metaspace_nmethod; + if (nm == NULL || !nm->is_alive()) { + return NULL; + } + int length = nm->code_size(); + arrayOop codeCopy = oopFactory::new_byteArray(length, CHECK_0); + memcpy(codeCopy->base(T_BYTE), nm->code_begin(), length); + return JNIHandles::make_local(codeCopy); C2V_END C2V_VMENTRY(jobject, disassembleNMethod, (JNIEnv *jniEnv, jobject, jlong metaspace_nmethod)) @@ -893,7 +883,8 @@ THROW_0(vmSymbols::MethodInvalidatedException()); } - JavaCalls::call(&result, mh, nm, &jca, CHECK_NULL); + jca.set_alternative_target(nm); + JavaCalls::call(&result, mh, &jca, CHECK_NULL); if (jap.get_ret_type() == T_VOID) { return NULL; @@ -922,7 +913,8 @@ THROW_0(vmSymbols::MethodInvalidatedException()); } - JavaCalls::call(&result, method, nm, &args, CHECK_NULL); + args.set_alternative_target(nm); + JavaCalls::call(&result, method, &args, CHECK_NULL); return JNIHandles::make_local((oop) result.get_jobject()); C2V_END @@ -952,30 +944,9 @@ return JNIHandles::make_local(array); C2V_END -C2V_VMENTRY(jobject, decodePC, (JNIEnv *, jobject, jlong pc)) - stringStream(st); - CodeBlob* blob = CodeCache::find_blob_unsafe((void*) pc); - if (blob == NULL) { - st.print("[unidentified pc]"); - } else { - st.print(blob->name()); - - nmethod* nm = blob->as_nmethod_or_null(); - if (nm != NULL && nm->method() != NULL) { - st.print(" %s.", nm->method()->method_holder()->external_name()); - nm->method()->name()->print_symbol_on(&st); - st.print(" @ %d", pc - (jlong) nm->entry_point()); - } - } - Handle result = java_lang_String::create_from_platform_dependent_str(st.as_string(), CHECK_NULL); - return JNIHandles::make_local(result()); -C2V_END - C2V_ENTRY(jlongArray, getLineNumberTable, (JNIEnv *env, jobject, jobject hotspot_method)) -// XXX: Attention: it seEms that the line number table of a method just contains lines that are important, means that -// empty lines are left out or lines that can't have a breakpoint on it; eg int a; or try { Method* method = getMethodFromHotSpotMethod(JNIHandles::resolve(hotspot_method)); - if(!method->has_linenumber_table()) { + if (!method->has_linenumber_table()) { return NULL; } u2 num_entries = 0; @@ -1004,7 +975,7 @@ ResourceMark rm; Method* method = getMethodFromHotSpotMethod(JNIHandles::resolve(hotspot_method)); - if(!method->has_localvariable_table()) { + if (!method->has_localvariable_table()) { return NULL; } int localvariable_table_length = method->localvariable_table_length(); @@ -1074,7 +1045,6 @@ #define HS_CONFIG "Lcom/oracle/graal/hotspot/HotSpotVMConfig;" #define HS_METHOD "Lcom/oracle/graal/hotspot/meta/HotSpotMethod;" #define HS_INSTALLED_CODE "Lcom/oracle/graal/hotspot/meta/HotSpotInstalledCode;" -#define HS_CODE_INFO "Lcom/oracle/graal/hotspot/meta/HotSpotCodeInfo;" #define METHOD_DATA "Lcom/oracle/graal/hotspot/meta/HotSpotMethodData;" #define METASPACE_METHOD "J" #define METASPACE_METHOD_DATA "J" @@ -1110,13 +1080,12 @@ {CC"getMetaspaceConstructor", CC"("REFLECT_CONSTRUCTOR"["HS_RESOLVED_TYPE")"METASPACE_METHOD, FN_PTR(getMetaspaceConstructor)}, {CC"getJavaField", CC"("REFLECT_FIELD")"HS_RESOLVED_FIELD, FN_PTR(getJavaField)}, {CC"initializeConfiguration", CC"("HS_CONFIG")V", FN_PTR(initializeConfiguration)}, - {CC"installCode0", CC"("HS_COMP_RESULT HS_INSTALLED_CODE HS_CODE_INFO")I", FN_PTR(installCode0)}, - {CC"disassembleNative", CC"([BJ)"STRING, FN_PTR(disassembleNative)}, + {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"getDeoptedLeafGraphIds", CC"()[J", FN_PTR(getDeoptedLeafGraphIds)}, - {CC"decodePC", CC"(J)"STRING, FN_PTR(decodePC)}, {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)}, diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/graal/graalEnv.cpp --- a/src/share/vm/graal/graalEnv.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/graal/graalEnv.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -43,6 +43,7 @@ #include "runtime/sharedRuntime.hpp" #include "utilities/dtrace.hpp" #include "graal/graalRuntime.hpp" +#include "graal/graalJavaAccess.hpp" // ------------------------------------------------------------------ // Note: the logic of this method should mirror the logic of @@ -410,7 +411,6 @@ int frame_words, OopMapSet* oop_map_set, ExceptionHandlerTable* handler_table, - ImplicitExceptionTable* inc_table, AbstractCompiler* compiler, DebugInformationRecorder* debug_info, Dependencies* dependencies, @@ -419,7 +419,8 @@ bool has_debug_info, bool has_unsafe_access, GrowableArray* leaf_graph_ids, - Handle installed_code) { + Handle installed_code, + Handle triggered_deoptimizations) { GRAAL_EXCEPTION_CONTEXT; NMethodSweeper::possibly_sweep(); nm = NULL; @@ -455,7 +456,7 @@ //code_buffer->free_blob(); return GraalEnv::dependencies_failed; } - + ImplicitExceptionTable implicit_tbl; nm = nmethod::new_nmethod(method, compile_id, entry_bci, @@ -463,8 +464,8 @@ orig_pc_offset, debug_info, dependencies, code_buffer, frame_words, oop_map_set, - handler_table, inc_table, - compiler, comp_level, leaf_graph_ids, installed_code); + handler_table, &implicit_tbl, + compiler, comp_level, leaf_graph_ids, installed_code, triggered_deoptimizations); // Free codeBlobs //code_buffer->free_blob(); @@ -493,7 +494,7 @@ // (Put nm into the task handle *before* publishing to the Java heap.) if (task != NULL) task->set_code(nm); - if (installed_code.is_null()) { + if (HotSpotInstalledCode::isDefault(installed_code())) { if (entry_bci == InvocationEntryBci) { if (TieredCompilation) { // If there is an old version we're done with it diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/graal/graalEnv.hpp --- a/src/share/vm/graal/graalEnv.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/graal/graalEnv.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -138,7 +138,6 @@ int frame_words, OopMapSet* oop_map_set, ExceptionHandlerTable* handler_table, - ImplicitExceptionTable* inc_table, AbstractCompiler* compiler, DebugInformationRecorder* debug_info, Dependencies* dependencies, @@ -147,7 +146,8 @@ bool has_debug_info, bool has_unsafe_access, GrowableArray* leaf_graph_ids, - Handle installed_code); + Handle installed_code, + Handle triggered_deoptimizations); // converts the Klass* representing the holder of a method into a // InstanceKlass*. This is needed since the holder of a method in diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/graal/graalGlobals.hpp --- a/src/share/vm/graal/graalGlobals.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/graal/graalGlobals.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -52,9 +52,6 @@ product(bool, BootstrapGraal, GRAALVM_ONLY(true) NOT_GRAALVM(false), \ "Bootstrap Graal before running Java main method") \ \ - product(ccstr, GraalClassPath, NULL, \ - "Use this path, zip, or jar, to locate Graal-specific classes") \ - \ product(intx, TraceGraal, 0, \ "Trace level for Graal") \ \ diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/graal/graalJavaAccess.hpp --- a/src/share/vm/graal/graalJavaAccess.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/graal/graalJavaAccess.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -75,10 +75,8 @@ start_class(HotSpotInstalledCode) \ long_field(HotSpotInstalledCode, nmethod) \ oop_field(HotSpotInstalledCode, method, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;") \ - end_class \ - start_class(HotSpotCodeInfo) \ - long_field(HotSpotCodeInfo, start) \ - oop_field(HotSpotCodeInfo, code, "[B") \ + long_field(HotSpotInstalledCode, start) \ + boolean_field(HotSpotInstalledCode, isDefault) \ end_class \ start_class(HotSpotCompilationResult) \ oop_field(HotSpotCompilationResult, comp, "Lcom/oracle/graal/api/code/CompilationResult;") \ @@ -88,6 +86,9 @@ oop_field(HotSpotCompilationResult, sites, "[Lcom/oracle/graal/api/code/CompilationResult$Site;") \ oop_field(HotSpotCompilationResult, exceptionHandlers, "[Lcom/oracle/graal/api/code/CompilationResult$ExceptionHandler;") \ end_class \ + start_class(HotSpotRuntimeCallTarget) \ + long_field(HotSpotRuntimeCallTarget, address) \ + end_class \ start_class(ExceptionHandler) \ int_field(ExceptionHandler, startBCI) \ int_field(ExceptionHandler, endBCI) \ @@ -122,7 +123,7 @@ int_field(CompilationResult_Site, pcOffset) \ end_class \ start_class(CompilationResult_Call) \ - oop_field(CompilationResult_Call, target, "Ljava/lang/Object;") \ + oop_field(CompilationResult_Call, target, "Lcom/oracle/graal/api/meta/InvokeTarget;") \ oop_field(CompilationResult_Call, debugInfo, "Lcom/oracle/graal/api/code/DebugInfo;") \ end_class \ start_class(CompilationResult_DataPatch) \ diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/graal/graalRuntime.cpp --- a/src/share/vm/graal/graalRuntime.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/graal/graalRuntime.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -127,18 +127,15 @@ // Make sure that stubs that need oopmaps have them switch (id) { // These stubs don't need to have an oopmap - case graal_slow_subtype_check_id: #if defined(SPARC) || defined(PPC) - case graal_handle_exception_nofpu_id: // Unused on sparc + case handle_exception_nofpu_id: // Unused on sparc #endif - case graal_verify_oop_id: - case graal_unwind_exception_call_id: - case graal_OSR_migration_end_id: - case graal_arithmetic_frem_id: - case graal_arithmetic_drem_id: - case graal_set_deopt_info_id: - break; - + case verify_oop_id: + case unwind_exception_call_id: + case OSR_migration_end_id: + case arithmetic_frem_id: + case arithmetic_drem_id: + break; // All other stubs should have oopmaps default: assert(oop_maps != NULL, "must have an oopmap"); @@ -443,17 +440,17 @@ return continuation; } -JRT_ENTRY(void, GraalRuntime::graal_create_null_exception(JavaThread* thread)) +JRT_ENTRY(void, GraalRuntime::create_null_exception(JavaThread* thread)) thread->set_vm_result(Exceptions::new_exception(thread, vmSymbols::java_lang_NullPointerException(), NULL)()); JRT_END -JRT_ENTRY(void, GraalRuntime::graal_create_out_of_bounds_exception(JavaThread* thread, jint index)) +JRT_ENTRY(void, GraalRuntime::create_out_of_bounds_exception(JavaThread* thread, jint index)) char message[jintAsStringSize]; sprintf(message, "%d", index); thread->set_vm_result(Exceptions::new_exception(thread, vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), message)()); JRT_END -JRT_ENTRY_NO_ASYNC(void, GraalRuntime::graal_monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock)) +JRT_ENTRY_NO_ASYNC(void, GraalRuntime::monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock)) if (TraceGraal >= 3) { char type[O_BUFLEN]; obj->klass()->name()->as_C_string(type, O_BUFLEN); @@ -484,15 +481,15 @@ } JRT_END -JRT_LEAF(void, GraalRuntime::graal_wb_pre_call(JavaThread* thread, oopDesc* obj)) +JRT_LEAF(void, GraalRuntime::wb_pre_call(JavaThread* thread, oopDesc* obj)) thread->satb_mark_queue().enqueue(obj); JRT_END -JRT_LEAF(void, GraalRuntime::graal_wb_post_call(JavaThread* thread, oopDesc* obj, void* card_addr)) +JRT_LEAF(void, GraalRuntime::wb_post_call(JavaThread* thread, oopDesc* obj, void* card_addr)) thread->dirty_card_queue().enqueue(card_addr); JRT_END -JRT_LEAF(void, GraalRuntime::graal_monitorexit(JavaThread* thread, oopDesc* obj, BasicLock* lock)) +JRT_LEAF(void, GraalRuntime::monitorexit(JavaThread* thread, oopDesc* obj, BasicLock* lock)) assert(thread == JavaThread::current(), "threads must correspond"); assert(thread->last_Java_sp(), "last_Java_sp must be set"); // monitorexit is non-blocking (leaf routine) => no exceptions can be thrown @@ -524,7 +521,7 @@ } JRT_END -JRT_ENTRY(void, GraalRuntime::graal_log_object(JavaThread* thread, oop obj, jint flags)) +JRT_ENTRY(void, GraalRuntime::log_object(JavaThread* thread, oop obj, jint flags)) bool string = mask_bits_are_true(flags, LOG_OBJECT_STRING); bool address = mask_bits_are_true(flags, LOG_OBJECT_ADDRESS); bool newline = mask_bits_are_true(flags, LOG_OBJECT_NEWLINE); @@ -546,7 +543,7 @@ } JRT_END -JRT_ENTRY(void, GraalRuntime::graal_vm_error(JavaThread* thread, oop where, oop format, jlong value)) +JRT_ENTRY(void, GraalRuntime::vm_error(JavaThread* thread, oop where, oop format, jlong value)) ResourceMark rm; assert(where == NULL || java_lang_String::is_instance(where), "must be"); const char *error_msg = where == NULL ? "" : java_lang_String::as_utf8_string(where); @@ -560,14 +557,15 @@ report_vm_error(__FILE__, __LINE__, error_msg, detail_msg); JRT_END -JRT_LEAF(void, GraalRuntime::graal_log_printf(JavaThread* thread, oop format, jlong v1, jlong v2, jlong v3)) + +JRT_LEAF(void, GraalRuntime::log_printf(JavaThread* thread, oop format, jlong v1, jlong v2, jlong v3)) ResourceMark rm; assert(format != NULL && java_lang_String::is_instance(format), "must be"); char *buf = java_lang_String::as_utf8_string(format); tty->print(buf, v1, v2, v3); JRT_END -JRT_ENTRY(void, GraalRuntime::graal_log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline)) +JRT_ENTRY(void, GraalRuntime::log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline)) union { jlong l; jdouble d; @@ -590,11 +588,11 @@ } JRT_END -JRT_ENTRY(jint, GraalRuntime::graal_identity_hash_code(JavaThread* thread, oop obj)) +JRT_ENTRY(jint, GraalRuntime::identity_hash_code(JavaThread* thread, oop obj)) return (jint) obj->identity_hash(); JRT_END -JRT_ENTRY(jboolean, GraalRuntime::graal_thread_is_interrupted(JavaThread* thread, oop receiver, jboolean clear_interrupted)) +JRT_ENTRY(jboolean, GraalRuntime::thread_is_interrupted(JavaThread* thread, oop receiver, jboolean clear_interrupted)) // Ensure that the C++ Thread and OSThread structures aren't freed before we operate Handle receiverHandle(thread, receiver); MutexLockerEx ml(thread->threadObj() == receiver ? NULL : Threads_lock); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/graal/graalRuntime.hpp --- a/src/share/vm/graal/graalRuntime.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/graal/graalRuntime.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -81,31 +81,29 @@ // runtime routines needed by code code generated // by Graal. #define GRAAL_STUBS(stub, last_entry) \ - stub(graal_register_finalizer) \ - stub(graal_new_instance) \ - stub(graal_new_array) \ - stub(graal_new_multi_array) \ - stub(graal_handle_exception_nofpu) /* optimized version that does not preserve fpu registers */ \ - stub(graal_slow_subtype_check) \ - stub(graal_unwind_exception_call) \ - stub(graal_OSR_migration_end) \ - stub(graal_arithmetic_frem) \ - stub(graal_arithmetic_drem) \ - stub(graal_monitorenter) \ - stub(graal_monitorexit) \ - stub(graal_verify_oop) \ - stub(graal_vm_error) \ - stub(graal_set_deopt_info) \ - stub(graal_create_null_pointer_exception) \ - stub(graal_create_out_of_bounds_exception) \ - stub(graal_log_object) \ - stub(graal_log_printf) \ - stub(graal_log_primitive) \ - stub(graal_identity_hash_code) \ - stub(graal_thread_is_interrupted) \ - stub(graal_wb_pre_call) \ - stub(graal_wb_post_call) \ - last_entry(number_of_ids) + stub(register_finalizer) \ + stub(new_instance) \ + stub(new_array) \ + stub(new_multi_array) \ + stub(handle_exception_nofpu) /* optimized version that does not preserve fpu registers */ \ + stub(unwind_exception_call) \ + stub(OSR_migration_end) \ + stub(arithmetic_frem) \ + stub(arithmetic_drem) \ + stub(monitorenter) \ + stub(monitorexit) \ + stub(verify_oop) \ + stub(vm_error) \ + stub(create_null_pointer_exception) \ + stub(create_out_of_bounds_exception) \ + stub(log_object) \ + stub(log_printf) \ + stub(log_primitive) \ + stub(identity_hash_code) \ + stub(thread_is_interrupted) \ + stub(wb_pre_call) \ + stub(wb_post_call) \ + last_entry(number_of_ids) #define DECLARE_STUB_ID(x) x ## _id , #define DECLARE_LAST_STUB_ID(x) x @@ -142,19 +140,18 @@ static address exception_handler_for_pc(JavaThread* thread); - static void graal_verify_oop(JavaThread* thread, oopDesc* obj); - static void graal_wb_pre_call(JavaThread* thread, oopDesc* obj); - static void graal_wb_post_call(JavaThread* thread, oopDesc* obj,void* obj); - static void graal_create_null_exception(JavaThread* thread); - static void graal_create_out_of_bounds_exception(JavaThread* thread, jint index); - static void graal_monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock); - static void graal_monitorexit (JavaThread* thread, oopDesc* obj, BasicLock* lock); - static void graal_vm_error(JavaThread* thread, oop where, oop format, jlong value); - static void graal_log_printf(JavaThread* thread, oop format, jlong v1, jlong v2, jlong v3); - static void graal_log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline); - - static jint graal_identity_hash_code(JavaThread* thread, oopDesc* objd); - static jboolean graal_thread_is_interrupted(JavaThread* thread, oopDesc* obj, jboolean clear_interrupte); + static void create_null_exception(JavaThread* thread); + static void create_out_of_bounds_exception(JavaThread* thread, jint index); + static void monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock); + static void monitorexit (JavaThread* thread, oopDesc* obj, BasicLock* lock); + static void vm_error(JavaThread* thread, oop where, oop format, jlong value); + static void log_printf(JavaThread* thread, oop format, jlong v1, jlong v2, jlong v3); + static void log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline); + static void wb_pre_call(JavaThread* thread, oopDesc* obj); + static void wb_post_call(JavaThread* thread, oopDesc* obj,void* obj); + + static jint identity_hash_code(JavaThread* thread, oopDesc* objd); + static jboolean thread_is_interrupted(JavaThread* thread, oopDesc* obj, jboolean clear_interrupte); // Note: Must be kept in sync with constants in com.oracle.graal.snippets.Log enum { @@ -162,7 +159,7 @@ LOG_OBJECT_STRING = 0x02, LOG_OBJECT_ADDRESS = 0x04 }; - static void graal_log_object(JavaThread* thread, oop msg, jint flags); + static void log_object(JavaThread* thread, oop msg, jint flags); public: // initialization diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/graal/graalVmIds.cpp --- a/src/share/vm/graal/graalVmIds.cpp Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +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. - */ - -#include "precompiled.hpp" -#include "graal/graalVmIds.hpp" -#include "ci/ciUtilities.hpp" - -// VmIds implementation - -jlong VmIds::addStub(address stub) { - return (jlong)stub; -} - -address VmIds::getStub(jlong id) { - return (address)id; -} - diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/graal/graalVmIds.hpp --- a/src/share/vm/graal/graalVmIds.hpp Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +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. - */ - -#ifndef SHARE_VM_GRAAL_GRAAL_VM_IDS_HPP -#define SHARE_VM_GRAAL_GRAAL_VM_IDS_HPP - -#include "memory/allocation.hpp" -#include "utilities/growableArray.hpp" -#include "oops/oop.hpp" -#include "runtime/handles.hpp" -#include "runtime/thread.hpp" -#include "classfile/javaClasses.hpp" -#include "runtime/jniHandles.hpp" - -class VmIds : public AllStatic { - -public: - // Adds a stub address, and returns the corresponding vmId (which is of type STUB) - static jlong addStub(address stub); - - // Returns the stub address with the given vmId - static address getStub(jlong id); - - // Returns the stub address with the given vmId taken from a java.lang.Long - static address getStub(oop id); - - // Helper function to convert a symbol to a java.lang.String object - template static T toString(Symbol* symbol, TRAPS); - - // Helper function to convert a java.lang.String object to a symbol (this will return NULL if the symbol doesn't exist in the system) - static Symbol* toSymbol(jstring string); - - // Helper function to get the contents of a java.lang.Long - static jlong getBoxedLong(oop obj); -}; - -inline address VmIds::getStub(oop obj) { - return getStub(getBoxedLong(obj)); -} - -template <> inline Handle VmIds::toString(Symbol* symbol, TRAPS) { - return java_lang_String::create_from_symbol(symbol, THREAD); -} - -template <> inline oop VmIds::toString(Symbol* symbol, TRAPS) { - return toString(symbol, THREAD)(); -} - -template <> inline jstring VmIds::toString(Symbol* symbol, TRAPS) { - return (jstring)JNIHandles::make_local(toString(symbol, THREAD)); -} - -template <> inline jobject VmIds::toString(Symbol* symbol, TRAPS) { - return JNIHandles::make_local(toString(symbol, THREAD)); -} - -inline Symbol* VmIds::toSymbol(jstring string) { - return java_lang_String::as_symbol(JNIHandles::resolve(string), Thread::current()); -} - -inline jlong VmIds::getBoxedLong(oop obj) { - assert(obj->is_oop(true), "cannot unbox null or non-oop"); - return obj->long_field(java_lang_boxing_object::value_offset_in_bytes(T_LONG)); -} - -#endif // SHARE_VM_GRAAL_GRAAL_VM_IDS_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/interpreter/bytecodeInterpreter.cpp --- a/src/share/vm/interpreter/bytecodeInterpreter.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/interpreter/bytecodeInterpreter.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -3099,9 +3099,9 @@ tty->print_cr("&native_fresult: " INTPTR_FORMAT, (uintptr_t) &this->_native_fresult); tty->print_cr("native_lresult: " INTPTR_FORMAT, (uintptr_t) this->_native_lresult); #endif -#if defined(IA64) && !defined(ZERO) +#if !defined(ZERO) tty->print_cr("last_Java_fp: " INTPTR_FORMAT, (uintptr_t) this->_last_Java_fp); -#endif // IA64 && !ZERO +#endif // !ZERO tty->print_cr("self_link: " INTPTR_FORMAT, (uintptr_t) this->_self_link); } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/interpreter/bytecodeTracer.cpp --- a/src/share/vm/interpreter/bytecodeTracer.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/interpreter/bytecodeTracer.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -335,9 +335,6 @@ st->print_cr(" %s", constants->resolved_klass_at(i)->external_name()); } else if (tag.is_unresolved_klass()) { st->print_cr(" ", i); - } else if (tag.is_object()) { - st->print(" "); - print_oop(constants->object_at(i), st); } else if (tag.is_method_type()) { int i2 = constants->method_type_index_at(i); st->print(" %d", i2); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/interpreter/interpreter.cpp --- a/src/share/vm/interpreter/interpreter.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/interpreter/interpreter.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -63,8 +63,9 @@ void InterpreterCodelet::print_on(outputStream* st) const { ttyLocker ttyl; - if (PrintInterpreter || PrintMachineCodeToFile) { + if (PrintInterpreter) { + st->cr(); st->print_cr("----------------------------------------------------------------------"); } @@ -73,7 +74,8 @@ st->print_cr("[" INTPTR_FORMAT ", " INTPTR_FORMAT "] %d bytes", code_begin(), code_end(), code_size()); - if (PrintInterpreter || PrintMachineCodeToFile) { + if (PrintInterpreter) { + st->cr(); Disassembler::decode(code_begin(), code_end(), st, DEBUG_ONLY(_comments) NOT_DEBUG(CodeComments())); } } @@ -388,7 +390,6 @@ assert(method->contains(bcp), "just checkin'"); Bytecodes::Code code = Bytecodes::java_code_at(method, bcp); #if defined(COMPILER1) || defined(GRAAL) - if(code == Bytecodes::_athrow ) { return Interpreter::rethrow_exception_entry(); } @@ -434,8 +435,7 @@ case Bytecodes::_getstatic : case Bytecodes::_putstatic : case Bytecodes::_aastore : -#if defined(COMPILER1) - +#ifdef COMPILER1 //special case of reexecution case Bytecodes::_athrow : #endif diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/interpreter/linkResolver.cpp --- a/src/share/vm/interpreter/linkResolver.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/interpreter/linkResolver.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1241,7 +1241,6 @@ void LinkResolver::resolve_invokedynamic(CallInfo& result, constantPoolHandle pool, int index, TRAPS) { assert(EnableInvokeDynamic, ""); - pool->set_invokedynamic(); // mark header to flag active call sites //resolve_pool(, method_name, method_signature, current_klass, pool, index, CHECK); Symbol* method_name = pool->name_ref_at(index); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/interpreter/rewriter.cpp --- a/src/share/vm/interpreter/rewriter.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/interpreter/rewriter.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -48,7 +48,6 @@ add_cp_cache_entry(i); break; case JVM_CONSTANT_String: - case JVM_CONSTANT_Object: case JVM_CONSTANT_MethodHandle : // fall through case JVM_CONSTANT_MethodType : // fall through add_resolved_references_entry(i); @@ -116,9 +115,7 @@ while (!bcs.is_last_bytecode()) { Bytecodes::Code opcode = bcs.raw_next(); switch (opcode) { - case Bytecodes::_return: - *bcs.bcp() = Bytecodes::_return_register_finalizer; - break; + case Bytecodes::_return: *bcs.bcp() = Bytecodes::_return_register_finalizer; break; case Bytecodes::_istore: case Bytecodes::_lstore: @@ -240,7 +237,7 @@ address p = bcp + offset; int cp_index = is_wide ? Bytes::get_Java_u2(p) : (u1)(*p); constantTag tag = _pool->tag_at(cp_index).value(); - if (tag.is_method_handle() || tag.is_method_type() || tag.is_string() || tag.is_object()) { + if (tag.is_method_handle() || tag.is_method_type() || tag.is_string()) { int ref_index = cp_entry_to_resolved_references(cp_index); if (is_wide) { (*bcp) = Bytecodes::_fast_aldc_w; @@ -318,12 +315,12 @@ switch (c) { case Bytecodes::_lookupswitch : { #ifndef CC_INTERP - Bytecode_lookupswitch bc(method, bcp); - (*bcp) = ( - bc.number_of_pairs() < BinarySwitchThreshold - ? Bytecodes::_fast_linearswitch - : Bytecodes::_fast_binaryswitch - ); + Bytecode_lookupswitch bc(method, bcp); + (*bcp) = ( + bc.number_of_pairs() < BinarySwitchThreshold + ? Bytecodes::_fast_linearswitch + : Bytecodes::_fast_binaryswitch + ); #endif break; } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/interpreter/templateInterpreter.cpp --- a/src/share/vm/interpreter/templateInterpreter.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/interpreter/templateInterpreter.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -27,7 +27,6 @@ #include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreterRuntime.hpp" #include "interpreter/templateTable.hpp" -#include "utilities/machineCodePrinter.hpp" #ifndef CC_INTERP @@ -52,9 +51,6 @@ "Interpreter"); InterpreterGenerator g(_code); if (PrintInterpreter) print(); - if (PrintMachineCodeToFile) { - MachineCodePrinter::print(_code); - } } // initialize dispatch table @@ -184,7 +180,7 @@ #endif // !PRODUCT EntryPoint TemplateInterpreter::_return_entry[TemplateInterpreter::number_of_return_entries]; EntryPoint TemplateInterpreter::_earlyret_entry; -EntryPoint TemplateInterpreter::_deopt_entry [TemplateInterpreter::number_of_deopt_entries ]; +EntryPoint TemplateInterpreter::_deopt_entry[TemplateInterpreter::number_of_deopt_entries ]; EntryPoint TemplateInterpreter::_continuation_entry; EntryPoint TemplateInterpreter::_safept_entry; @@ -276,15 +272,15 @@ for (int i = 0; i < Interpreter::number_of_deopt_entries; i++) { Interpreter::_deopt_entry[i] = EntryPoint( - generate_deopt_entry_for(itos, i), - generate_deopt_entry_for(itos, i), - generate_deopt_entry_for(itos, i), - generate_deopt_entry_for(atos, i), - generate_deopt_entry_for(itos, i), - generate_deopt_entry_for(ltos, i), - generate_deopt_entry_for(ftos, i), - generate_deopt_entry_for(dtos, i), - generate_deopt_entry_for(vtos, i) + ((InterpreterGenerator*)this)->generate_deopt_entry_for(itos, i), + ((InterpreterGenerator*)this)->generate_deopt_entry_for(itos, i), + ((InterpreterGenerator*)this)->generate_deopt_entry_for(itos, i), + ((InterpreterGenerator*)this)->generate_deopt_entry_for(atos, i), + ((InterpreterGenerator*)this)->generate_deopt_entry_for(itos, i), + ((InterpreterGenerator*)this)->generate_deopt_entry_for(ltos, i), + ((InterpreterGenerator*)this)->generate_deopt_entry_for(ftos, i), + ((InterpreterGenerator*)this)->generate_deopt_entry_for(dtos, i), + ((InterpreterGenerator*)this)->generate_deopt_entry_for(vtos, i) ); } } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/interpreter/templateInterpreterGenerator.hpp --- a/src/share/vm/interpreter/templateInterpreterGenerator.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/interpreter/templateInterpreterGenerator.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -55,7 +55,6 @@ address generate_continuation_for(TosState state); address generate_return_entry_for(TosState state, int step); address generate_earlyret_entry_for(TosState state); - address generate_deopt_entry_for(TosState state, int step); address generate_safept_entry_for(TosState state, address runtime_entry); void generate_throw_exception(); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/allocation.hpp --- a/src/share/vm/memory/allocation.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/allocation.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -34,9 +34,6 @@ #ifdef COMPILER2 #include "opto/c2_globals.hpp" #endif -#ifdef GRAAL -#include "graal/graalGlobals.hpp" -#endif #include @@ -148,9 +145,10 @@ mtChunk = 0x0B00, // chunk that holds content of arenas mtJavaHeap = 0x0C00, // Java heap mtClassShared = 0x0D00, // class data sharing - mt_number_of_types = 0x000D, // number of memory types (mtDontTrack + mtTest = 0x0E00, // Test type for verifying NMT + mt_number_of_types = 0x000E, // number of memory types (mtDontTrack // is not included as validate type) - mtDontTrack = 0x0E00, // memory we do not or cannot track + mtDontTrack = 0x0F00, // memory we do not or cannot track mt_masks = 0x7F00, // object type mask diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/binaryTreeDictionary.cpp --- a/src/share/vm/memory/binaryTreeDictionary.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/binaryTreeDictionary.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "utilities/macros.hpp" #include "gc_implementation/shared/allocationStats.hpp" #include "memory/binaryTreeDictionary.hpp" #include "memory/freeList.hpp" @@ -31,12 +32,13 @@ #include "memory/metachunk.hpp" #include "runtime/globals.hpp" #include "utilities/ostream.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/adaptiveFreeList.hpp" #include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" #include "gc_implementation/shared/spaceDecorator.hpp" #include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS //////////////////////////////////////////////////////////////////////////////// // A binary tree based search structure for free blocks. @@ -118,7 +120,7 @@ } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Specialize for AdaptiveFreeList which tries to avoid // splitting a chunk of a size that is under populated in favor of // an over populated size. The general get_better_list() just returns @@ -160,7 +162,7 @@ } return curTL; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS template class FreeList_t> TreeList* @@ -871,9 +873,9 @@ template class FreeList_t> void BinaryTreeDictionary::dict_census_update(size_t size, bool split, bool birth){} -#ifndef SERIALGC +#if INCLUDE_ALL_GCS template <> -void BinaryTreeDictionary::dict_census_update(size_t size, bool split, bool birth){ +void AFLBinaryTreeDictionary::dict_census_update(size_t size, bool split, bool birth){ TreeList* nd = find_list(size); if (nd) { if (split) { @@ -900,7 +902,7 @@ // This is a birth associated with a LinAB. The chunk // for the LinAB is not in the dictionary. } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS template class FreeList_t> bool BinaryTreeDictionary::coal_dict_over_populated(size_t size) { @@ -909,9 +911,9 @@ return true; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS template <> -bool BinaryTreeDictionary::coal_dict_over_populated(size_t size) { +bool AFLBinaryTreeDictionary::coal_dict_over_populated(size_t size) { if (FLSAlwaysCoalesceLarge) return true; TreeList* list_of_size = find_list(size); @@ -919,7 +921,7 @@ return list_of_size == NULL || list_of_size->coal_desired() <= 0 || list_of_size->count() > list_of_size->coal_desired(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Closures for walking the binary tree. // do_list() walks the free list in a node applying the closure @@ -979,7 +981,7 @@ void do_list(FreeList* fl) {} -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void do_list(AdaptiveFreeList* fl) { double coalSurplusPercent = _percentage; fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate, _intra_sweep_estimate); @@ -987,7 +989,7 @@ fl->set_before_sweep(fl->count()); fl->set_bfr_surp(fl->surplus()); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS }; // Used to search the tree until a condition is met. @@ -1134,13 +1136,13 @@ setTreeSurplusClosure(double v) { percentage = v; } void do_list(FreeList* fl) {} -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void do_list(AdaptiveFreeList* fl) { double splitSurplusPercent = percentage; fl->set_surplus(fl->count() - (ssize_t)((double)fl->desired() * splitSurplusPercent)); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS }; template class FreeList_t> @@ -1157,7 +1159,7 @@ setTreeHintsClosure(size_t v) { hint = v; } void do_list(FreeList* fl) {} -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void do_list(AdaptiveFreeList* fl) { fl->set_hint(hint); assert(fl->hint() == 0 || fl->hint() > fl->size(), @@ -1166,7 +1168,7 @@ hint = fl->size(); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS }; template class FreeList_t> @@ -1180,7 +1182,7 @@ class clearTreeCensusClosure : public AscendTreeCensusClosure { void do_list(FreeList* fl) {} -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void do_list(AdaptiveFreeList* fl) { fl->set_prev_sweep(fl->count()); fl->set_coal_births(0); @@ -1188,7 +1190,7 @@ fl->set_split_births(0); fl->set_split_deaths(0); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS }; template class FreeList_t> @@ -1252,7 +1254,7 @@ total()->set_count( total()->count() + fl->count() ); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void do_list(AdaptiveFreeList* fl) { if (++_print_line >= 40) { FreeList_t::print_labels_on(gclog_or_tty, "size"); @@ -1271,7 +1273,7 @@ total()->set_split_births(total()->split_births() + fl->split_births()); total()->set_split_deaths(total()->split_deaths() + fl->split_deaths()); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS }; template class FreeList_t> @@ -1286,9 +1288,9 @@ FreeList_t::print_labels_on(gclog_or_tty, " "); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS template <> -void BinaryTreeDictionary::print_dict_census(void) const { +void AFLBinaryTreeDictionary::print_dict_census(void) const { gclog_or_tty->print("\nBinaryTree\n"); AdaptiveFreeList::print_labels_on(gclog_or_tty, "size"); @@ -1308,7 +1310,7 @@ (double)(total->desired() - total->count()) /(total->desired() != 0 ? (double)total->desired() : 1.0)); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS template class FreeList_t> class PrintFreeListsClosure : public AscendTreeCensusClosure { @@ -1414,10 +1416,10 @@ template class TreeChunk; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Explicitly instantiate these types for FreeChunk. template class TreeList; template class BinaryTreeDictionary; template class TreeChunk; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/binaryTreeDictionary.hpp --- a/src/share/vm/memory/binaryTreeDictionary.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/binaryTreeDictionary.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -43,6 +43,10 @@ template class FreeList_t> class DescendTreeCensusClosure; template class FreeList_t> class DescendTreeSearchClosure; +class FreeChunk; +template class AdaptiveFreeList; +typedef BinaryTreeDictionary AFLBinaryTreeDictionary; + template class FreeList_t> class TreeList : public FreeList_t { friend class TreeChunk; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/cardTableModRefBS.cpp --- a/src/share/vm/memory/cardTableModRefBS.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/cardTableModRefBS.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -34,6 +34,7 @@ #include "runtime/mutexLocker.hpp" #include "runtime/virtualspace.hpp" #include "services/memTracker.hpp" +#include "utilities/macros.hpp" #ifdef COMPILER1 #include "c1/c1_LIR.hpp" #include "c1/c1_LIRGenerator.hpp" @@ -499,13 +500,13 @@ int n_threads = SharedHeap::heap()->n_par_threads(); bool is_par = n_threads > 0; if (is_par) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS assert(SharedHeap::heap()->n_par_threads() == SharedHeap::heap()->workers()->active_workers(), "Mismatch"); non_clean_card_iterate_parallel_work(sp, mr, cl, ct, n_threads); -#else // SERIALGC +#else // INCLUDE_ALL_GCS fatal("Parallel gc not supported here."); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } else { // We do not call the non_clean_card_iterate_serial() version below because // we want to clear the cards (which non_clean_card_iterate_serial() does not diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/cardTableRS.cpp --- a/src/share/vm/memory/cardTableRS.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/cardTableRS.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -31,10 +31,11 @@ #include "oops/oop.inline.hpp" #include "runtime/java.hpp" #include "runtime/os.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/concurrentMark.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" -#endif +#endif // INCLUDE_ALL_GCS CardTableRS::CardTableRS(MemRegion whole_heap, int max_covered_regions) : @@ -42,7 +43,7 @@ _cur_youngergen_card_val(youngergenP1_card), _regions_to_iterate(max_covered_regions - 1) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseG1GC) { _ct_bs = new G1SATBCardTableLoggingModRefBS(whole_heap, max_covered_regions); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/collectorPolicy.cpp --- a/src/share/vm/memory/collectorPolicy.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/collectorPolicy.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -39,10 +39,11 @@ #include "runtime/java.hpp" #include "runtime/thread.inline.hpp" #include "runtime/vmThread.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.hpp" #include "gc_implementation/concurrentMarkSweep/cmsGCAdaptivePolicyCounters.hpp" -#endif +#endif // INCLUDE_ALL_GCS // CollectorPolicy methods. @@ -167,11 +168,11 @@ void GenCollectorPolicy::initialize_size_policy(size_t init_eden_size, size_t init_promo_size, size_t init_survivor_size) { - const double max_gc_minor_pause_sec = ((double) MaxGCMinorPauseMillis)/1000.0; + const double max_gc_pause_sec = ((double) MaxGCPauseMillis)/1000.0; _size_policy = new AdaptiveSizePolicy(init_eden_size, init_promo_size, init_survivor_size, - max_gc_minor_pause_sec, + max_gc_pause_sec, GCTimeRatio); } @@ -235,6 +236,18 @@ if (NewSize + OldSize > MaxHeapSize) { MaxHeapSize = NewSize + OldSize; } + + if (FLAG_IS_CMDLINE(OldSize) && FLAG_IS_DEFAULT(NewSize)) { + // NewRatio will be used later to set the young generation size so we use + // it to calculate how big the heap should be based on the requested OldSize + // and NewRatio. + assert(NewRatio > 0, "NewRatio should have been set up earlier"); + size_t calculated_heapsize = (OldSize / NewRatio) * (NewRatio + 1); + + calculated_heapsize = align_size_up(calculated_heapsize, max_alignment()); + MaxHeapSize = calculated_heapsize; + InitialHeapSize = calculated_heapsize; + } MaxHeapSize = align_size_up(MaxHeapSize, max_alignment()); always_do_update_barrier = UseConcMarkSweepGC; @@ -384,14 +397,15 @@ // keeping it simple also seems a worthwhile goal. bool TwoGenerationCollectorPolicy::adjust_gen0_sizes(size_t* gen0_size_ptr, size_t* gen1_size_ptr, - size_t heap_size, - size_t min_gen0_size) { + const size_t heap_size, + const size_t min_gen1_size) { bool result = false; + if ((*gen1_size_ptr + *gen0_size_ptr) > heap_size) { - if (((*gen0_size_ptr + OldSize) > heap_size) && - (heap_size - min_gen0_size) >= min_alignment()) { - // Adjust gen0 down to accomodate OldSize - *gen0_size_ptr = heap_size - min_gen0_size; + if ((heap_size < (*gen0_size_ptr + min_gen1_size)) && + (heap_size >= min_gen1_size + min_alignment())) { + // Adjust gen0 down to accommodate min_gen1_size + *gen0_size_ptr = heap_size - min_gen1_size; *gen0_size_ptr = MAX2((uintx)align_size_down(*gen0_size_ptr, min_alignment()), min_alignment()); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/collectorPolicy.hpp --- a/src/share/vm/memory/collectorPolicy.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/collectorPolicy.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -29,6 +29,7 @@ #include "memory/barrierSet.hpp" #include "memory/generationSpec.hpp" #include "memory/genRemSet.hpp" +#include "utilities/macros.hpp" // This class (or more correctly, subtypes of this class) // are used to define global garbage collector attributes. @@ -48,10 +49,10 @@ class GenCollectorPolicy; class TwoGenerationCollectorPolicy; class AdaptiveSizePolicy; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS class ConcurrentMarkSweepPolicy; class G1CollectorPolicy; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS class GCPolicyCounters; class MarkSweepPolicy; @@ -134,21 +135,21 @@ virtual GenCollectorPolicy* as_generation_policy() { return NULL; } virtual TwoGenerationCollectorPolicy* as_two_generation_policy() { return NULL; } virtual MarkSweepPolicy* as_mark_sweep_policy() { return NULL; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS virtual ConcurrentMarkSweepPolicy* as_concurrent_mark_sweep_policy() { return NULL; } virtual G1CollectorPolicy* as_g1_policy() { return NULL; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Note that these are not virtual. bool is_generation_policy() { return as_generation_policy() != NULL; } bool is_two_generation_policy() { return as_two_generation_policy() != NULL; } bool is_mark_sweep_policy() { return as_mark_sweep_policy() != NULL; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS bool is_concurrent_mark_sweep_policy() { return as_concurrent_mark_sweep_policy() != NULL; } bool is_g1_policy() { return as_g1_policy() != NULL; } -#else // SERIALGC +#else // INCLUDE_ALL_GCS bool is_concurrent_mark_sweep_policy() { return false; } bool is_g1_policy() { return false; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS virtual BarrierSet::Name barrier_set_name() = 0; @@ -321,7 +322,7 @@ // Returns true is gen0 sizes were adjusted bool adjust_gen0_sizes(size_t* gen0_size_ptr, size_t* gen1_size_ptr, - size_t heap_size, size_t min_gen1_size); + const size_t heap_size, const size_t min_gen1_size); }; class MarkSweepPolicy : public TwoGenerationCollectorPolicy { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/filemap.cpp --- a/src/share/vm/memory/filemap.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/filemap.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -210,13 +210,14 @@ tty->print_cr(" %s", _full_path); } - // Remove the existing file in case another process has it open. +#ifdef _WINDOWS // On Windows, need WRITE permission to remove the file. + chmod(_full_path, _S_IREAD | _S_IWRITE); +#endif + + // Use remove() to delete the existing file because, on Unix, this will + // allow processes that have it open continued access to the file. remove(_full_path); -#ifdef _WINDOWS // if 0444 is used on Windows, then remove() will fail. - int fd = open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0744); -#else int fd = open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0444); -#endif if (fd < 0) { fail_stop("Unable to create shared archive file %s.", _full_path); } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/freeBlockDictionary.cpp --- a/src/share/vm/memory/freeBlockDictionary.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/freeBlockDictionary.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -23,13 +23,15 @@ */ #include "precompiled.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #include "memory/freeBlockDictionary.hpp" #include "memory/metablock.hpp" #include "memory/metachunk.hpp" #include "runtime/thread.inline.hpp" +#include "utilities/macros.hpp" #ifndef PRODUCT template Mutex* FreeBlockDictionary::par_lock() const { @@ -56,7 +58,7 @@ template class FreeBlockDictionary; template class FreeBlockDictionary; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Explicitly instantiate for FreeChunk template class FreeBlockDictionary; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/freeList.cpp --- a/src/share/vm/memory/freeList.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/freeList.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -31,10 +31,11 @@ #include "runtime/globals.hpp" #include "runtime/mutex.hpp" #include "runtime/vmThread.hpp" +#include "utilities/macros.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Free list. A FreeList is used to access a linked list of chunks // of space in the heap. The head and tail are maintained so that @@ -341,6 +342,6 @@ template class FreeList; template class FreeList; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS template class FreeList; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/genCollectedHeap.cpp --- a/src/share/vm/memory/genCollectedHeap.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/genCollectedHeap.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -51,10 +51,11 @@ #include "services/memoryService.hpp" #include "utilities/vmError.hpp" #include "utilities/workgroup.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp" #include "gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp" -#endif +#endif // INCLUDE_ALL_GCS GenCollectedHeap* GenCollectedHeap::_gch; NOT_PRODUCT(size_t GenCollectedHeap::_skip_header_HeapWords = 0;) @@ -141,14 +142,14 @@ } clear_incremental_collection_failed(); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // If we are running CMS, create the collector responsible // for collecting the CMS generations. if (collector_policy()->is_concurrent_mark_sweep_policy()) { bool success = create_cms_collector(); if (!success) return JNI_ENOMEM; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS return JNI_OK; } @@ -686,12 +687,12 @@ void GenCollectedHeap::collect(GCCause::Cause cause) { if (should_do_concurrent_full_gc(cause)) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // mostly concurrent full collection collect_mostly_concurrent(cause); -#else // SERIALGC +#else // INCLUDE_ALL_GCS ShouldNotReachHere(); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } else { #ifdef ASSERT if (cause == GCCause::_scavenge_alot) { @@ -736,7 +737,7 @@ } } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS bool GenCollectedHeap::create_cms_collector() { assert(((_gens[1]->kind() == Generation::ConcurrentMarkSweep) || @@ -772,7 +773,7 @@ VMThread::execute(&op); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS void GenCollectedHeap::do_full_collection(bool clear_all_soft_refs) { do_full_collection(clear_all_soft_refs, _n_gens - 1); @@ -1116,22 +1117,22 @@ if (workers() != NULL) { workers()->threads_do(tc); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseConcMarkSweepGC) { ConcurrentMarkSweepThread::threads_do(tc); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } void GenCollectedHeap::print_gc_threads_on(outputStream* st) const { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseParNewGC) { workers()->print_worker_threads_on(st); } if (UseConcMarkSweepGC) { ConcurrentMarkSweepThread::print_all_on(st); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } void GenCollectedHeap::print_tracing_info() const { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/generationSpec.cpp --- a/src/share/vm/memory/generationSpec.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/generationSpec.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -30,11 +30,12 @@ #include "memory/generationSpec.hpp" #include "memory/tenuredGeneration.hpp" #include "runtime/java.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parNew/asParNewGeneration.hpp" #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp" #include "gc_implementation/parNew/parNewGeneration.hpp" -#endif +#endif // INCLUDE_ALL_GCS Generation* GenerationSpec::init(ReservedSpace rs, int level, GenRemSet* remset) { @@ -45,7 +46,7 @@ case Generation::MarkSweepCompact: return new TenuredGeneration(rs, init_size(), level, remset); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case Generation::ParNew: return new ParNewGeneration(rs, init_size(), level); @@ -94,7 +95,7 @@ return g; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS default: guarantee(false, "unrecognized GenerationName"); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/heap.cpp --- a/src/share/vm/memory/heap.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/heap.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -127,7 +127,7 @@ assert(_number_of_reserved_segments >= _number_of_committed_segments, "just checking"); // reserve space for _segmap - if (!_segmap.initialize(align_to_allocation_size(_number_of_reserved_segments), align_to_allocation_size(_number_of_committed_segments))) { + if (!_segmap.initialize(align_to_page_size(_number_of_reserved_segments), align_to_page_size(_number_of_committed_segments))) { return false; } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/heapInspection.cpp --- a/src/share/vm/memory/heapInspection.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/heapInspection.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,15 +23,17 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderData.hpp" #include "gc_interface/collectedHeap.hpp" #include "memory/genCollectedHeap.hpp" #include "memory/heapInspection.hpp" #include "memory/resourceArea.hpp" #include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" -#endif +#endif // INCLUDE_ALL_GCS // HeapInspection @@ -41,12 +43,24 @@ } else if(e1->_instance_words < e2->_instance_words) { return 1; } - return 0; + // Sort alphabetically, note 'Z' < '[' < 'a', but it's better to group + // the array classes before all the instance classes. + ResourceMark rm; + const char* name1 = e1->klass()->external_name(); + const char* name2 = e2->klass()->external_name(); + bool d1 = (name1[0] == '['); + bool d2 = (name2[0] == '['); + if (d1 && !d2) { + return -1; + } else if (d2 && !d1) { + return 1; + } else { + return strcmp(name1, name2); + } } -void KlassInfoEntry::print_on(outputStream* st) const { - ResourceMark rm; - const char* name;; +const char* KlassInfoEntry::name() const { + const char* name; if (_klass->name() != NULL) { name = _klass->external_name(); } else { @@ -60,11 +74,17 @@ if (_klass == Universe::longArrayKlassObj()) name = ""; else name = ""; } + return name; +} + +void KlassInfoEntry::print_on(outputStream* st) const { + ResourceMark rm; + // simplify the formatting (ILP32 vs LP64) - always cast the numbers to 64-bit st->print_cr(INT64_FORMAT_W(13) " " UINT64_FORMAT_W(13) " %s", (jlong) _instance_count, (julong) _instance_words * HeapWordSize, - name); + name()); } KlassInfoEntry* KlassInfoBucket::lookup(Klass* const k) { @@ -101,7 +121,14 @@ } } -KlassInfoTable::KlassInfoTable(int size, HeapWord* ref) { +void KlassInfoTable::AllClassesFinder::do_klass(Klass* k) { + // This has the SIDE EFFECT of creating a KlassInfoEntry + // for , if one doesn't exist yet. + _table->lookup(k); +} + +KlassInfoTable::KlassInfoTable(int size, HeapWord* ref, + bool need_class_stats) { _size = 0; _ref = ref; _buckets = NEW_C_HEAP_ARRAY(KlassInfoBucket, size, mtInternal); @@ -110,6 +137,10 @@ for (int index = 0; index < _size; index++) { _buckets[index].initialize(); } + if (need_class_stats) { + AllClassesFinder finder(this); + ClassLoaderDataGraph::classes_do(&finder); + } } } @@ -165,7 +196,8 @@ return (*e1)->compare(*e1,*e2); } -KlassInfoHisto::KlassInfoHisto(const char* title, int estimatedCount) : +KlassInfoHisto::KlassInfoHisto(KlassInfoTable* cit, const char* title, int estimatedCount) : + _cit(cit), _title(title) { _elements = new (ResourceObj::C_HEAP, mtInternal) GrowableArray(estimatedCount,true); } @@ -196,9 +228,205 @@ total, totalw * HeapWordSize); } -void KlassInfoHisto::print_on(outputStream* st) const { - st->print_cr("%s",title()); - print_elements(st); +#define MAKE_COL_NAME(field, name, help) #name, +#define MAKE_COL_HELP(field, name, help) help, + +static const char *name_table[] = { + HEAP_INSPECTION_COLUMNS_DO(MAKE_COL_NAME) +}; + +static const char *help_table[] = { + HEAP_INSPECTION_COLUMNS_DO(MAKE_COL_HELP) +}; + +bool KlassInfoHisto::is_selected(const char *col_name) { + if (_selected_columns == NULL) { + return true; + } + if (strcmp(_selected_columns, col_name) == 0) { + return true; + } + + const char *start = strstr(_selected_columns, col_name); + if (start == NULL) { + return false; + } + + // The following must be true, because _selected_columns != col_name + if (start > _selected_columns && start[-1] != ',') { + return false; + } + char x = start[strlen(col_name)]; + if (x != ',' && x != '\0') { + return false; + } + + return true; +} + +void KlassInfoHisto::print_title(outputStream* st, bool csv_format, + bool selected[], int width_table[], + const char *name_table[]) { + if (csv_format) { + st->print("Index,Super"); + for (int c=0; cprint(",%s", name_table[c]);} + } + st->print(",ClassName"); + } else { + st->print("Index Super"); + for (int c=0; cprint(str_fmt(width_table[c]), name_table[c]);} + } + st->print(" ClassName"); + } + + if (is_selected("ClassLoader")) { + st->print(",ClassLoader"); + } + st->cr(); +} + +void KlassInfoHisto::print_class_stats(outputStream* st, + bool csv_format, const char *columns) { + ResourceMark rm; + KlassSizeStats sz, sz_sum; + int i; + julong *col_table = (julong*)(&sz); + julong *colsum_table = (julong*)(&sz_sum); + int width_table[KlassSizeStats::_num_columns]; + bool selected[KlassSizeStats::_num_columns]; + + _selected_columns = columns; + + memset(&sz_sum, 0, sizeof(sz_sum)); + for (int c=0; clength(); i++) { + elements()->at(i)->set_index(i+1); + } + + for (int pass=1; pass<=2; pass++) { + if (pass == 2) { + print_title(st, csv_format, selected, width_table, name_table); + } + for(i=0; i < elements()->length(); i++) { + KlassInfoEntry* e = (KlassInfoEntry*)elements()->at(i); + const Klass* k = e->klass(); + + memset(&sz, 0, sizeof(sz)); + sz._inst_count = e->count(); + sz._inst_bytes = HeapWordSize * e->words(); + k->collect_statistics(&sz); + sz._total_bytes = sz._ro_bytes + sz._rw_bytes; + + if (pass == 1) { + for (int c=0; coop_is_instance()) { + Klass* super = ((InstanceKlass*)k)->java_super(); + if (super) { + KlassInfoEntry* super_e = _cit->lookup(super); + if (super_e) { + super_index = super_e->index(); + } + } + } + + if (csv_format) { + st->print("%d,%d", e->index(), super_index); + for (int c=0; cprint("," JULONG_FORMAT, col_table[c]);} + } + st->print(",%s",e->name()); + } else { + st->print("%5d %5d", e->index(), super_index); + for (int c=0; cprint(" %s", e->name()); + } + if (is_selected("ClassLoader")) { + ClassLoaderData* loader_data = k->class_loader_data(); + st->print(","); + loader_data->print_value_on(st); + } + st->cr(); + } + } + + if (pass == 1) { + for (int c=0; cprint(","); + for (int c=0; cprint("," JULONG_FORMAT, colsum_table[c]);} + } + } else { + st->print(" "); + for (int c=0; cprint(" Total"); + if (sz_sum._total_bytes > 0) { + st->cr(); + st->print(" "); + for (int c=0; cprint(str_fmt(width_table[c]), "-"); + break; + default: + { + double perc = (double)(100) * (double)(colsum_table[c]) / (double)sz_sum._total_bytes; + st->print(perc_fmt(width_table[c]), perc); + } + } + } + } + } + } + st->cr(); + + if (!csv_format) { + print_title(st, csv_format, selected, width_table, name_table); + } +} + +julong KlassInfoHisto::annotations_bytes(Array* p) const { + julong bytes = 0; + if (p != NULL) { + for (int i = 0; i < p->length(); i++) { + bytes += count_bytes_array(p->at(i)); + } + bytes += count_bytes_array(p); + } + return bytes; +} + +void KlassInfoHisto::print_histo_on(outputStream* st, bool print_stats, + bool csv_format, const char *columns) { + if (print_stats) { + print_class_stats(st, csv_format, columns); + } else { + st->print_cr("%s",title()); + print_elements(st); + } } class HistoClosure : public KlassInfoClosure { @@ -236,8 +464,26 @@ CollectedHeap* heap = Universe::heap(); bool is_shared_heap = false; + if (_print_help) { + for (int c=0; cprint("%s:\n\t", name_table[c]); + const int max_col = 60; + int col = 0; + for (const char *p = help_table[c]; *p; p++,col++) { + if (col >= max_col && *p == ' ') { + st->print("\n\t"); + col = 0; + } else { + st->print("%c", *p); + } + } + st->print_cr(".\n"); + } + return; + } + // Collect klass instance info - KlassInfoTable cit(KlassInfoTable::cit_size, ref); + KlassInfoTable cit(KlassInfoTable::cit_size, ref, _print_class_stats); if (!cit.allocation_failed()) { // Iterate over objects in the heap RecordInstanceClosure ric(&cit); @@ -252,14 +498,14 @@ missed_count); } // Sort and print klass instance info - KlassInfoHisto histo("\n" - " num #instances #bytes class name\n" - "----------------------------------------------", - KlassInfoHisto::histo_initial_size); + const char *title = "\n" + " num #instances #bytes class name\n" + "----------------------------------------------"; + KlassInfoHisto histo(&cit, title, KlassInfoHisto::histo_initial_size); HistoClosure hc(&histo); cit.iterate(&hc); histo.sort(); - histo.print_on(st); + histo.print_histo_on(st, _print_class_stats, _csv_format, _columns); } else { st->print_cr("WARNING: Ran out of C-heap; histogram not generated"); } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/heapInspection.hpp --- a/src/share/vm/memory/heapInspection.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/heapInspection.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2010, 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 @@ -27,6 +27,8 @@ #include "memory/allocation.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/annotations.hpp" +#include "utilities/macros.hpp" #if INCLUDE_SERVICES @@ -44,16 +46,148 @@ // to KlassInfoEntry's and is used to sort // the entries. +#define HEAP_INSPECTION_COLUMNS_DO(f) \ + f(inst_size, InstSize, \ + "Size of each object instance of the Java class") \ + f(inst_count, InstCount, \ + "Number of object instances of the Java class") \ + f(inst_bytes, InstBytes, \ + "This is usually (InstSize * InstNum). The only exception is " \ + "java.lang.Class, whose InstBytes also includes the slots " \ + "used to store static fields. InstBytes is not counted in " \ + "ROAll, RWAll or Total") \ + f(mirror_bytes, Mirror, \ + "Size of the Klass::java_mirror() object") \ + f(klass_bytes, KlassBytes, \ + "Size of the InstanceKlass or ArrayKlass for this class. " \ + "Note that this includes VTab, ITab, OopMap") \ + f(secondary_supers_bytes, K_secondary_supers, \ + "Number of bytes used by the Klass::secondary_supers() array") \ + f(vtab_bytes, VTab, \ + "Size of the embedded vtable in InstanceKlass") \ + f(itab_bytes, ITab, \ + "Size of the embedded itable in InstanceKlass") \ + f(nonstatic_oopmap_bytes, OopMap, \ + "Size of the embedded nonstatic_oop_map in InstanceKlass") \ + f(methods_array_bytes, IK_methods, \ + "Number of bytes used by the InstanceKlass::methods() array") \ + f(method_ordering_bytes, IK_method_ordering, \ + "Number of bytes used by the InstanceKlass::method_ordering() array") \ + f(local_interfaces_bytes, IK_local_interfaces, \ + "Number of bytes used by the InstanceKlass::local_interfaces() array") \ + f(transitive_interfaces_bytes, IK_transitive_interfaces, \ + "Number of bytes used by the InstanceKlass::transitive_interfaces() array") \ + f(fields_bytes, IK_fields, \ + "Number of bytes used by the InstanceKlass::fields() array") \ + f(inner_classes_bytes, IK_inner_classes, \ + "Number of bytes used by the InstanceKlass::inner_classes() array") \ + f(signers_bytes, IK_signers, \ + "Number of bytes used by the InstanceKlass::singers() array") \ + f(class_annotations_bytes, class_annotations, \ + "Size of class annotations") \ + f(class_type_annotations_bytes, class_type_annotations, \ + "Size of class type annotations") \ + f(fields_annotations_bytes, fields_annotations, \ + "Size of field annotations") \ + f(fields_type_annotations_bytes, fields_type_annotations, \ + "Size of field type annotations") \ + f(methods_annotations_bytes, methods_annotations, \ + "Size of method annotations") \ + f(methods_parameter_annotations_bytes, methods_parameter_annotations, \ + "Size of method parameter annotations") \ + f(methods_type_annotations_bytes, methods_type_annotations, \ + "Size of methods type annotations") \ + f(methods_default_annotations_bytes, methods_default_annotations, \ + "Size of methods default annotations") \ + f(annotations_bytes, annotations, \ + "Size of all annotations") \ + f(cp_bytes, Cp, \ + "Size of InstanceKlass::constants()") \ + f(cp_tags_bytes, CpTags, \ + "Size of InstanceKlass::constants()->tags()") \ + f(cp_cache_bytes, CpCache, \ + "Size of InstanceKlass::constants()->cache()") \ + f(cp_operands_bytes, CpOperands, \ + "Size of InstanceKlass::constants()->operands()") \ + f(cp_refmap_bytes, CpRefMap, \ + "Size of InstanceKlass::constants()->reference_map()") \ + f(cp_all_bytes, CpAll, \ + "Sum of Cp + CpTags + CpCache + CpOperands + CpRefMap") \ + f(method_count, MethodCount, \ + "Number of methods in this class") \ + f(method_bytes, MethodBytes, \ + "Size of the Method object") \ + f(const_method_bytes, ConstMethod, \ + "Size of the ConstMethod object") \ + f(method_data_bytes, MethodData, \ + "Size of the MethodData object") \ + f(stackmap_bytes, StackMap, \ + "Size of the stackmap_data") \ + f(bytecode_bytes, Bytecodes, \ + "Of the MethodBytes column, how much are the space taken up by bytecodes") \ + f(method_all_bytes, MethodAll, \ + "Sum of MethodBytes + Constmethod + Stackmap + Methoddata") \ + f(ro_bytes, ROAll, \ + "Size of all class meta data that could (potentially) be placed " \ + "in read-only memory. (This could change with CDS design)") \ + f(rw_bytes, RWAll, \ + "Size of all class meta data that must be placed in read/write " \ + "memory. (This could change with CDS design) ") \ + f(total_bytes, Total, \ + "ROAll + RWAll. Note that this does NOT include InstBytes.") + +// Size statistics for a Klass - filled in by Klass::collect_statistics() +class KlassSizeStats { +public: +#define COUNT_KLASS_SIZE_STATS_FIELD(field, name, help) _index_ ## field, +#define DECLARE_KLASS_SIZE_STATS_FIELD(field, name, help) julong _ ## field; + + enum { + HEAP_INSPECTION_COLUMNS_DO(COUNT_KLASS_SIZE_STATS_FIELD) + _num_columns + }; + + HEAP_INSPECTION_COLUMNS_DO(DECLARE_KLASS_SIZE_STATS_FIELD) + + static int count(oop x) { + return (HeapWordSize * ((x) ? (x)->size() : 0)); + } + + static int count_array(objArrayOop x) { + return (HeapWordSize * ((x) ? (x)->size() : 0)); + } + + template static int count(T* x) { + return (HeapWordSize * ((x) ? (x)->size() : 0)); + } + + template static int count_array(T* x) { + if (x == NULL) { + return 0; + } + if (x->length() == 0) { + // This is a shared array, e.g., Universe::the_empty_int_array(). Don't + // count it to avoid double-counting. + return 0; + } + return HeapWordSize * x->size(); + } +}; + + + + class KlassInfoEntry: public CHeapObj { private: KlassInfoEntry* _next; Klass* _klass; long _instance_count; size_t _instance_words; + long _index; public: KlassInfoEntry(Klass* k, KlassInfoEntry* next) : - _klass(k), _instance_count(0), _instance_words(0), _next(next) + _klass(k), _instance_count(0), _instance_words(0), _next(next), _index(-1) {} KlassInfoEntry* next() { return _next; } bool is_equal(Klass* k) { return k == _klass; } @@ -62,8 +196,11 @@ void set_count(long ct) { _instance_count = ct; } size_t words() { return _instance_words; } void set_words(size_t wds) { _instance_words = wds; } + void set_index(long index) { _index = index; } + long index() { return _index; } int compare(KlassInfoEntry* e1, KlassInfoEntry* e2); void print_on(outputStream* st) const; + const char* name() const; }; class KlassInfoClosure: public StackObj { @@ -95,45 +232,132 @@ KlassInfoBucket* _buckets; uint hash(Klass* p); - KlassInfoEntry* lookup(Klass* const k); + KlassInfoEntry* lookup(Klass* const k); // allocates if not found! + + class AllClassesFinder : public KlassClosure { + KlassInfoTable *_table; + public: + AllClassesFinder(KlassInfoTable* table) : _table(table) {} + virtual void do_klass(Klass* k); + }; public: // Table size enum { cit_size = 20011 }; - KlassInfoTable(int size, HeapWord* ref); + KlassInfoTable(int size, HeapWord* ref, bool need_class_stats); ~KlassInfoTable(); bool record_instance(const oop obj); void iterate(KlassInfoClosure* cic); bool allocation_failed() { return _buckets == NULL; } + + friend class KlassInfoHisto; }; class KlassInfoHisto : public StackObj { private: + KlassInfoTable *_cit; GrowableArray* _elements; GrowableArray* elements() const { return _elements; } const char* _title; const char* title() const { return _title; } static int sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2); void print_elements(outputStream* st) const; + void print_class_stats(outputStream* st, bool csv_format, const char *columns); + julong annotations_bytes(Array* p) const; + const char *_selected_columns; + bool is_selected(const char *col_name); + void print_title(outputStream* st, bool csv_format, + bool selected_columns_table[], int width_table[], + const char *name_table[]); + + template static int count_bytes(T* x) { + return (HeapWordSize * ((x) ? (x)->size() : 0)); + } + + template static int count_bytes_array(T* x) { + if (x == NULL) { + return 0; + } + if (x->length() == 0) { + // This is a shared array, e.g., Universe::the_empty_int_array(). Don't + // count it to avoid double-counting. + return 0; + } + return HeapWordSize * x->size(); + } + + // returns a format string to print a julong with the given width. E.g, + // printf(num_fmt(6), julong(10)) would print out the number 10 with 4 + // leading spaces. + static void print_julong(outputStream* st, int width, julong n) { + int num_spaces = width - julong_width(n); + if (num_spaces > 0) { + st->print(str_fmt(num_spaces), ""); + } + st->print(JULONG_FORMAT, n); + } + + static char* perc_fmt(int width) { + static char buf[32]; + jio_snprintf(buf, sizeof(buf), "%%%d.1f%%%%", width-1); + return buf; + } + + static char* str_fmt(int width) { + static char buf[32]; + jio_snprintf(buf, sizeof(buf), "%%%ds", width); + return buf; + } + + static int julong_width(julong n) { + if (n == 0) { + return 1; + } + int w = 0; + while (n > 0) { + n /= 10; + w += 1; + } + return w; + } + + static int col_width(julong n, const char *name) { + int w = julong_width(n); + int min = (int)(strlen(name)); + if (w < min) { + w = min; + } + // add a leading space for separation. + return w + 1; + } + public: enum { histo_initial_size = 1000 }; - KlassInfoHisto(const char* title, + KlassInfoHisto(KlassInfoTable* cit, const char* title, int estimatedCount); ~KlassInfoHisto(); void add(KlassInfoEntry* cie); - void print_on(outputStream* st) const; + void print_histo_on(outputStream* st, bool print_class_stats, bool csv_format, const char *columns); void sort(); }; #endif // INCLUDE_SERVICES -class HeapInspection : public AllStatic { +class HeapInspection : public StackObj { + bool _csv_format; // "comma separated values" format for spreadsheet. + bool _print_help; + bool _print_class_stats; + const char* _columns; public: - static void heap_inspection(outputStream* st, bool need_prologue) NOT_SERVICES_RETURN; + HeapInspection(bool csv_format, bool print_help, + bool print_class_stats, const char *columns) : + _csv_format(csv_format), _print_help(print_help), + _print_class_stats(print_class_stats), _columns(columns) {} + void heap_inspection(outputStream* st, bool need_prologue) NOT_SERVICES_RETURN; static void find_instances_at_safepoint(Klass* k, GrowableArray* result) NOT_SERVICES_RETURN; }; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/metaspace.cpp --- a/src/share/vm/memory/metaspace.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/metaspace.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1064,11 +1064,11 @@ // // After the GC the compute_new_size() for MetaspaceGC is called to // resize the capacity of the metaspaces. The current implementation -// is based on the flags MinHeapFreeRatio and MaxHeapFreeRatio used +// is based on the flags MinMetaspaceFreeRatio and MaxHeapFreeRatio used // to resize the Java heap by some GC's. New flags can be implemented // if really needed. MinHeapFreeRatio is used to calculate how much // free space is desirable in the metaspace capacity to decide how much -// to increase the HWM. MaxHeapFreeRatio is used to decide how much +// to increase the HWM. MaxMetaspaceFreeRatio is used to decide how much // free space is desirable in the metaspace capacity before decreasing // the HWM. @@ -1166,7 +1166,7 @@ size_t capacity_until_GC = vsl->capacity_bytes_sum(); size_t free_after_gc = capacity_until_GC - used_after_gc; - const double minimum_free_percentage = MinHeapFreeRatio / 100.0; + const double minimum_free_percentage = MinMetaspaceFreeRatio / 100.0; const double maximum_used_percentage = 1.0 - minimum_free_percentage; const double min_tmp = used_after_gc / maximum_used_percentage; @@ -1232,8 +1232,8 @@ max_shrink_words)); // Should shrinking be considered? - if (MaxHeapFreeRatio < 100) { - const double maximum_free_percentage = MaxHeapFreeRatio / 100.0; + if (MaxMetaspaceFreeRatio < 100) { + const double maximum_free_percentage = MaxMetaspaceFreeRatio / 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)); @@ -1737,10 +1737,10 @@ *class_chunk_word_size = ClassSmallChunk; break; } - assert(chunk_word_size != 0 && class_chunk_word_size != 0, + assert(*chunk_word_size != 0 && *class_chunk_word_size != 0, err_msg("Initial chunks sizes bad: data " SIZE_FORMAT " class " SIZE_FORMAT, - chunk_word_size, class_chunk_word_size)); + *chunk_word_size, *class_chunk_word_size)); } size_t SpaceManager::sum_free_in_chunks_in_use() const { @@ -2040,7 +2040,7 @@ align_size_up(humongous_chunks->word_size(), HumongousChunkGranularity), err_msg("Humongous chunk size is wrong: word size " SIZE_FORMAT - " granularity " SIZE_FORMAT, + " granularity %d", humongous_chunks->word_size(), HumongousChunkGranularity)); Metachunk* next_humongous_chunks = humongous_chunks->next(); chunk_manager->humongous_dictionary()->return_chunk(humongous_chunks); @@ -2264,7 +2264,8 @@ } MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag); assert(allocation_total() == sum_used_in_chunks_in_use(), - err_msg("allocation total is not consistent %d vs %d", + err_msg("allocation total is not consistent " SIZE_FORMAT + " vs " SIZE_FORMAT, allocation_total(), sum_used_in_chunks_in_use())); } @@ -2578,7 +2579,8 @@ // argument passed in is at the top of the compressed space void Metaspace::initialize_class_space(ReservedSpace rs) { // The reserved space size may be bigger because of alignment, esp with UseLargePages - assert(rs.size() >= ClassMetaspaceSize, err_msg("%d != %d", rs.size(), ClassMetaspaceSize)); + assert(rs.size() >= ClassMetaspaceSize, + err_msg(SIZE_FORMAT " != " UINTX_FORMAT, rs.size(), ClassMetaspaceSize)); _class_space_list = new VirtualSpaceList(rs); } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/space.cpp --- a/src/share/vm/memory/space.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/space.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -40,6 +40,7 @@ #include "runtime/safepoint.hpp" #include "utilities/copy.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" void SpaceMemRegionOopsIterClosure::do_oop(oop* p) { SpaceMemRegionOopsIterClosure::do_oop_work(p); } void SpaceMemRegionOopsIterClosure::do_oop(narrowOop* p) { SpaceMemRegionOopsIterClosure::do_oop_work(p); } @@ -658,7 +659,7 @@ } } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define ContigSpace_PAR_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ \ void ContiguousSpace::par_oop_iterate(MemRegion mr, OopClosureType* blk) {\ @@ -673,7 +674,7 @@ ALL_PAR_OOP_ITERATE_CLOSURES(ContigSpace_PAR_OOP_ITERATE_DEFN) #undef ContigSpace_PAR_OOP_ITERATE_DEFN -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS void ContiguousSpace::oop_iterate(ExtendedOopClosure* blk) { if (is_empty()) return; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/space.hpp --- a/src/share/vm/memory/space.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/space.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -34,6 +34,7 @@ #include "oops/markOop.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/prefetch.hpp" +#include "utilities/macros.hpp" #include "utilities/workgroup.hpp" #ifdef TARGET_OS_FAMILY_linux # include "os_linux.inline.hpp" @@ -884,14 +885,14 @@ } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // In support of parallel oop_iterate. #define ContigSpace_PAR_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ void par_oop_iterate(MemRegion mr, OopClosureType* blk); ALL_PAR_OOP_ITERATE_CLOSURES(ContigSpace_PAR_OOP_ITERATE_DECL) #undef ContigSpace_PAR_OOP_ITERATE_DECL -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Compaction support virtual void reset_after_compaction() { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/specialized_oop_closures.hpp --- a/src/share/vm/memory/specialized_oop_closures.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/specialized_oop_closures.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -26,9 +26,10 @@ #define SHARE_VM_MEMORY_SPECIALIZED_OOP_CLOSURES_HPP #include "runtime/atomic.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1_specialized_oop_closures.hpp" -#endif +#endif // INCLUDE_ALL_GCS // The following OopClosure types get specialized versions of // "oop_oop_iterate" that invoke the closures' do_oop methods @@ -80,20 +81,20 @@ f(FastScanClosure,_nv) \ f(FilteringClosure,_nv) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_P(f) \ f(ParScanWithBarrierClosure,_nv) \ f(ParScanWithoutBarrierClosure,_nv) -#else // SERIALGC +#else // INCLUDE_ALL_GCS #define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_P(f) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_1(f) \ f(NoHeaderExtendedOopClosure,_nv) \ SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_S(f) \ SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_P(f) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(f) \ f(MarkRefsIntoAndScanClosure,_nv) \ f(Par_MarkRefsIntoAndScanClosure,_nv) \ @@ -104,9 +105,9 @@ f(CMSKeepAliveClosure,_nv) \ f(CMSInnerParMarkAndPushClosure,_nv) \ FURTHER_SPECIALIZED_OOP_OOP_ITERATE_CLOSURES(f) -#else // SERIALGC +#else // INCLUDE_ALL_GCS #define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(f) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // We separate these out, because sometime the general one has @@ -120,7 +121,7 @@ #define ALL_OOP_OOP_ITERATE_CLOSURES_2(f) \ SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(f) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // This macro applies an argument macro to all OopClosures for which we // want specialized bodies of a family of methods related to // "par_oop_iterate". The arguments to f are the same as above. @@ -136,7 +137,7 @@ #define ALL_PAR_OOP_ITERATE_CLOSURES(f) \ f(ExtendedOopClosure,_v) \ SPECIALIZED_PAR_OOP_ITERATE_CLOSURES(f) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // This macro applies an argument macro to all OopClosures for which we // want specialized bodies of a family of methods related to @@ -155,14 +156,14 @@ f(ScanClosure,_nv) \ f(FastScanClosure,_nv) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_P(f) \ f(ParScanWithBarrierClosure,_nv) \ f(ParScanWithoutBarrierClosure,_nv) \ FURTHER_SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES(f) -#else // SERIALGC +#else // INCLUDE_ALL_GCS #define SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_P(f) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #define SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG(f) \ SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_S(f) \ diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/tenuredGeneration.cpp --- a/src/share/vm/memory/tenuredGeneration.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/tenuredGeneration.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -33,6 +33,7 @@ #include "memory/tenuredGeneration.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" +#include "utilities/macros.hpp" TenuredGeneration::TenuredGeneration(ReservedSpace rs, size_t initial_byte_size, int level, @@ -61,7 +62,7 @@ _space_counters = new CSpaceCounters(gen_name, 0, _virtual_space.reserved_size(), _the_space, _gen_counters); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseParNewGC) { typedef ParGCAllocBufferWithBOT* ParGCAllocBufferWithBOTPtr; _alloc_buffers = NEW_C_HEAP_ARRAY(ParGCAllocBufferWithBOTPtr, @@ -77,7 +78,7 @@ } else { _alloc_buffers = NULL; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } @@ -339,7 +340,7 @@ } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS oop TenuredGeneration::par_promote(int thread_num, oop old, markOop m, size_t word_sz) { @@ -423,10 +424,10 @@ } } -#else // SERIALGC +#else // INCLUDE_ALL_GCS void TenuredGeneration::retire_alloc_buffers_before_full_gc() {} void TenuredGeneration::verify_alloc_buffers_clean() {} -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS bool TenuredGeneration::promotion_attempt_is_safe(size_t max_promotion_in_bytes) const { size_t available = max_contiguous_available(); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/tenuredGeneration.hpp --- a/src/share/vm/memory/tenuredGeneration.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/tenuredGeneration.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -29,6 +29,7 @@ #include "gc_implementation/shared/gcStats.hpp" #include "gc_implementation/shared/generationCounters.hpp" #include "memory/generation.hpp" +#include "utilities/macros.hpp" // TenuredGeneration models the heap containing old (promoted/tenured) objects. @@ -45,11 +46,11 @@ size_t _capacity_at_prologue; size_t _used_at_prologue; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // To support parallel promotion: an array of parallel allocation // buffers, one per thread, initially NULL. ParGCAllocBufferWithBOT** _alloc_buffers; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Retire all alloc buffers before a full GC, so that they will be // re-allocated at the start of the next young GC. @@ -93,14 +94,14 @@ size_t size, bool is_tlab); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Overrides. virtual oop par_promote(int thread_num, oop obj, markOop m, size_t word_sz); virtual void par_promote_alloc_undo(int thread_num, HeapWord* obj, size_t word_sz); virtual void par_promote_alloc_done(int thread_num); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Performance Counter support void update_counters(); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/universe.cpp --- a/src/share/vm/memory/universe.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/universe.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -70,13 +70,14 @@ #include "utilities/events.hpp" #include "utilities/hashtable.inline.hpp" #include "utilities/preserveException.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.hpp" #include "gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1CollectorPolicy.hpp" #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" -#endif +#endif // INCLUDE_ALL_GCS // Known objects Klass* Universe::_boolArrayKlassObj = NULL; @@ -144,6 +145,7 @@ NarrowPtrStruct Universe::_narrow_klass = { NULL, 0, true }; address Universe::_narrow_ptrs_base; +size_t Universe::_class_metaspace_size; void Universe::basic_type_classes_do(void f(Klass*)) { f(boolArrayKlassObj()); @@ -689,8 +691,15 @@ // Return specified base for the first request. if (!FLAG_IS_DEFAULT(HeapBaseMinAddress) && (mode == UnscaledNarrowOop)) { base = HeapBaseMinAddress; - } else if (total_size <= OopEncodingHeapMax && (mode != HeapBasedNarrowOop)) { - if (total_size <= NarrowOopHeapMax && (mode == UnscaledNarrowOop) && + + // If the total size and the metaspace size are small enough to allow + // UnscaledNarrowOop then just use UnscaledNarrowOop. + } else if ((total_size <= OopEncodingHeapMax) && (mode != HeapBasedNarrowOop) && + (!UseCompressedKlassPointers || + (((OopEncodingHeapMax - heap_size) + Universe::class_metaspace_size()) <= KlassEncodingMetaspaceMax))) { + // We don't need to check the metaspace size here because it is always smaller + // than total_size. + if ((total_size <= NarrowOopHeapMax) && (mode == UnscaledNarrowOop) && (Universe::narrow_oop_shift() == 0)) { // Use 32-bits oops without encoding and // place heap's top on the 4Gb boundary @@ -706,14 +715,24 @@ base = (OopEncodingHeapMax - heap_size); } } + + // See if ZeroBaseNarrowOop encoding will work for a heap based at + // (KlassEncodingMetaspaceMax - class_metaspace_size()). + } else if (UseCompressedKlassPointers && (mode != HeapBasedNarrowOop) && + (Universe::class_metaspace_size() + HeapBaseMinAddress <= KlassEncodingMetaspaceMax) && + (KlassEncodingMetaspaceMax + heap_size - Universe::class_metaspace_size() <= OopEncodingHeapMax)) { + base = (KlassEncodingMetaspaceMax - Universe::class_metaspace_size()); } else { - // Can't reserve below 32Gb. + // UnscaledNarrowOop encoding didn't work, and no base was found for ZeroBasedOops or + // HeapBasedNarrowOop encoding was requested. So, can't reserve below 32Gb. Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); } + // Set narrow_oop_base and narrow_oop_use_implicit_null_checks // used in ReservedHeapSpace() constructors. // The final values will be set in initialize_heap() below. - if (base != 0 && (base + heap_size) <= OopEncodingHeapMax) { + if ((base != 0) && ((base + heap_size) <= OopEncodingHeapMax) && + (!UseCompressedKlassPointers || (base + Universe::class_metaspace_size()) <= KlassEncodingMetaspaceMax)) { // Use zero based compressed oops Universe::set_narrow_oop_base(NULL); // Don't need guard page for implicit checks in indexed @@ -740,20 +759,20 @@ jint Universe::initialize_heap() { if (UseParallelGC) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS Universe::_collectedHeap = new ParallelScavengeHeap(); -#else // SERIALGC +#else // INCLUDE_ALL_GCS fatal("UseParallelGC not supported in this VM."); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } else if (UseG1GC) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS G1CollectorPolicy* g1p = new G1CollectorPolicy(); G1CollectedHeap* g1h = new G1CollectedHeap(g1p); Universe::_collectedHeap = g1h; -#else // SERIALGC +#else // INCLUDE_ALL_GCS fatal("UseG1GC not supported in java kernel vm."); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } else { GenCollectorPolicy *gc_policy; @@ -761,15 +780,15 @@ if (UseSerialGC) { gc_policy = new MarkSweepPolicy(); } else if (UseConcMarkSweepGC) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseAdaptiveSizePolicy) { gc_policy = new ASConcurrentMarkSweepPolicy(); } else { gc_policy = new ConcurrentMarkSweepPolicy(); } -#else // SERIALGC +#else // INCLUDE_ALL_GCS fatal("UseConcMarkSweepGC not supported in this VM."); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } else { // default old generation gc_policy = new MarkSweepPolicy(); } @@ -796,7 +815,9 @@ tty->print("heap address: " PTR_FORMAT ", size: " SIZE_FORMAT " MB", Universe::heap()->base(), Universe::heap()->reserved_region().byte_size()/M); } - if ((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax) { + if (((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax) || + (UseCompressedKlassPointers && + ((uint64_t)Universe::heap()->base() + Universe::class_metaspace_size() > KlassEncodingMetaspaceMax))) { // Can't reserve heap below 32Gb. // keep the Universe::narrow_oop_base() set in Universe::reserve_heap() Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); @@ -862,8 +883,8 @@ // be compressed the same as instances. // Need to round class space size up because it's below the heap and // the actual alignment depends on its size. - size_t metaspace_size = align_size_up(ClassMetaspaceSize, alignment); - size_t total_reserved = align_size_up(heap_size + metaspace_size, alignment); + Universe::set_class_metaspace_size(align_size_up(ClassMetaspaceSize, alignment)); + size_t total_reserved = align_size_up(heap_size + Universe::class_metaspace_size(), alignment); char* addr = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); ReservedHeapSpace total_rs(total_reserved, alignment, UseLargePages, addr); @@ -904,8 +925,8 @@ // compressed oops is greater than the one used for compressed klass // ptrs, a metadata space on top of the heap could become // unreachable. - ReservedSpace class_rs = total_rs.first_part(metaspace_size); - ReservedSpace heap_rs = total_rs.last_part(metaspace_size, alignment); + ReservedSpace class_rs = total_rs.first_part(Universe::class_metaspace_size()); + ReservedSpace heap_rs = total_rs.last_part(Universe::class_metaspace_size(), alignment); Metaspace::initialize_class_space(class_rs); if (UseCompressedOops) { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/memory/universe.hpp --- a/src/share/vm/memory/universe.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/memory/universe.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -211,6 +211,9 @@ static struct NarrowPtrStruct _narrow_klass; static address _narrow_ptrs_base; + // Aligned size of the metaspace. + static size_t _class_metaspace_size; + // array of dummy objects used with +FullGCAlot debug_only(static objArrayOop _fullgc_alot_dummy_array;) // index of next entry to clear @@ -278,6 +281,13 @@ static bool reserve_metaspace_helper(bool with_base = false); static ReservedHeapSpace reserve_heap_metaspace(size_t heap_size, size_t alignment, bool& contiguous); + static size_t class_metaspace_size() { + return _class_metaspace_size; + } + static void set_class_metaspace_size(size_t metaspace_size) { + _class_metaspace_size = metaspace_size; + } + // Debugging static int _verify_count; // number of verifies done // True during call to verify(). Should only be set/cleared in verify(). diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/annotations.cpp --- a/src/share/vm/oops/annotations.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/annotations.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/classLoaderData.hpp" +#include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" #include "memory/oopFactory.hpp" #include "oops/annotations.hpp" @@ -35,16 +36,8 @@ return new (loader_data, size(), true, THREAD) Annotations(); } -Annotations* Annotations::allocate(ClassLoaderData* loader_data, - Array* fa, - Array* ma, - Array* mpa, - Array* mda, TRAPS) { - return new (loader_data, size(), true, THREAD) Annotations(fa, ma, mpa, mda); -} - // helper -static void free_contents(ClassLoaderData* loader_data, Array* p) { +void Annotations::free_contents(ClassLoaderData* loader_data, Array* p) { if (p != NULL) { for (int i = 0; i < p->length(); i++) { MetadataFactory::free_array(loader_data, p->at(i)); @@ -58,44 +51,16 @@ MetadataFactory::free_array(loader_data, class_annotations()); } free_contents(loader_data, fields_annotations()); - free_contents(loader_data, methods_annotations()); - free_contents(loader_data, methods_parameter_annotations()); - free_contents(loader_data, methods_default_annotations()); - // Recursively deallocate optional Annotations linked through this one - MetadataFactory::free_metadata(loader_data, type_annotations()); + if (class_type_annotations() != NULL) { + MetadataFactory::free_array(loader_data, class_type_annotations()); + } + free_contents(loader_data, fields_type_annotations()); } -// Set the annotation at 'idnum' to 'anno'. -// We don't want to create or extend the array if 'anno' is NULL, since that is the -// default value. However, if the array exists and is long enough, we must set NULL values. -void Annotations::set_methods_annotations_of(instanceKlassHandle ik, - int idnum, AnnotationArray* anno, - Array** md_p, - TRAPS) { - Array* md = *md_p; - if (md != NULL && md->length() > idnum) { - md->at_put(idnum, anno); - } else if (anno != NULL) { - // create the array - int length = MAX2(idnum+1, (int)ik->idnum_allocated_count()); - md = MetadataFactory::new_array(ik->class_loader_data(), length, CHECK); - if (*md_p != NULL) { - // copy the existing entries - for (int index = 0; index < (*md_p)->length(); index++) { - md->at_put(index, (*md_p)->at(index)); - } - } - set_annotations(md, md_p); - md->at_put(idnum, anno); - } // if no array and idnum isn't included there is nothing to do -} - -// Keep created annotations in a global growable array (should be hashtable) -// need to add, search, delete when class is unloaded. -// Does it need a lock? yes. This sucks. - // Copy annotations to JVM call or reflection to the java heap. +// The alternative to creating this array and adding to Java heap pressure +// is to have a hashtable of the already created typeArrayOops typeArrayOop Annotations::make_java_array(AnnotationArray* annotations, TRAPS) { if (annotations != NULL) { int length = annotations->length(); @@ -114,14 +79,44 @@ st->print("Anotations(" INTPTR_FORMAT ")", this); } +#if INCLUDE_SERVICES +// Size Statistics + +julong Annotations::count_bytes(Array* p) { + julong bytes = 0; + if (p != NULL) { + for (int i = 0; i < p->length(); i++) { + bytes += KlassSizeStats::count_array(p->at(i)); + } + bytes += KlassSizeStats::count_array(p); + } + return bytes; +} + +void Annotations::collect_statistics(KlassSizeStats *sz) const { + sz->_annotations_bytes = sz->count(this); + sz->_class_annotations_bytes = sz->count(class_annotations()); + sz->_class_type_annotations_bytes = sz->count(class_type_annotations()); + sz->_fields_annotations_bytes = count_bytes(fields_annotations()); + sz->_fields_type_annotations_bytes = count_bytes(fields_type_annotations()); + + sz->_annotations_bytes += + sz->_class_annotations_bytes + + sz->_class_type_annotations_bytes + + sz->_fields_annotations_bytes + + sz->_fields_type_annotations_bytes; + + sz->_ro_bytes += sz->_annotations_bytes; +} +#endif // INCLUDE_SERVICES + #define BULLET " - " #ifndef PRODUCT void Annotations::print_on(outputStream* st) const { st->print(BULLET"class_annotations "); class_annotations()->print_value_on(st); st->print(BULLET"fields_annotations "); fields_annotations()->print_value_on(st); - st->print(BULLET"methods_annotations "); methods_annotations()->print_value_on(st); - st->print(BULLET"methods_parameter_annotations"); methods_parameter_annotations()->print_value_on(st); - st->print(BULLET"methods_default_annotations "); methods_default_annotations()->print_value_on(st); + st->print(BULLET"class_type_annotations "); class_type_annotations()->print_value_on(st); + st->print(BULLET"fields_type_annotations "); fields_type_annotations()->print_value_on(st); } #endif // PRODUCT diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/annotations.hpp --- a/src/share/vm/oops/annotations.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/annotations.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ class ClassLoaderData; class outputStream; +class KlassSizeStats; typedef Array AnnotationArray; @@ -48,101 +49,46 @@ // Annotation objects (byte arrays) for fields, or null if no annotations. // Indices correspond to entries (not indices) in fields array. Array* _fields_annotations; - // Annotation objects (byte arrays) for methods, or null if no annotations. - // Index is the idnum, which is initially the same as the methods array index. - Array* _methods_annotations; - // Annotation objects (byte arrays) for methods' parameters, or null if no - // such annotations. - // Index is the idnum, which is initially the same as the methods array index. - Array* _methods_parameter_annotations; - // Annotation objects (byte arrays) for methods' default values, or null if no - // such annotations. - // Index is the idnum, which is initially the same as the methods array index. - Array* _methods_default_annotations; // Type annotations for this class, or null if none. - Annotations* _type_annotations; - - // Constructor where some some values are known to not be null - Annotations(Array* fa, Array* ma, - Array* mpa, Array* mda) : - _class_annotations(NULL), - _fields_annotations(fa), - _methods_annotations(ma), - _methods_parameter_annotations(mpa), - _methods_default_annotations(mda), - _type_annotations(NULL) {} + AnnotationArray* _class_type_annotations; + Array* _fields_type_annotations; public: // Allocate instance of this class static Annotations* allocate(ClassLoaderData* loader_data, TRAPS); - static Annotations* allocate(ClassLoaderData* loader_data, - Array* fa, - Array* ma, - Array* mpa, - Array* mda, TRAPS); + + static void free_contents(ClassLoaderData* loader_data, Array* p); void deallocate_contents(ClassLoaderData* loader_data); DEBUG_ONLY(bool on_stack() { return false; }) // for template + + // Sizing (in words) static int size() { return sizeof(Annotations) / wordSize; } +#if INCLUDE_SERVICES + void collect_statistics(KlassSizeStats *sz) const; +#endif // Constructor to initialize to null Annotations() : _class_annotations(NULL), _fields_annotations(NULL), - _methods_annotations(NULL), - _methods_parameter_annotations(NULL), - _methods_default_annotations(NULL), - _type_annotations(NULL) {} + _class_type_annotations(NULL), + _fields_type_annotations(NULL) {} AnnotationArray* class_annotations() const { return _class_annotations; } Array* fields_annotations() const { return _fields_annotations; } - Array* methods_annotations() const { return _methods_annotations; } - Array* methods_parameter_annotations() const { return _methods_parameter_annotations; } - Array* methods_default_annotations() const { return _methods_default_annotations; } - Annotations* type_annotations() const { return _type_annotations; } + AnnotationArray* class_type_annotations() const { return _class_type_annotations; } + Array* fields_type_annotations() const { return _fields_type_annotations; } void set_class_annotations(AnnotationArray* md) { _class_annotations = md; } void set_fields_annotations(Array* md) { _fields_annotations = md; } - void set_methods_annotations(Array* md) { _methods_annotations = md; } - void set_methods_parameter_annotations(Array* md) { _methods_parameter_annotations = md; } - void set_methods_default_annotations(Array* md) { _methods_default_annotations = md; } - void set_type_annotations(Annotations* annos) { _type_annotations = annos; } - - // Redefine classes support - AnnotationArray* get_method_annotations_of(int idnum) - { return get_method_annotations_from(idnum, _methods_annotations); } - - AnnotationArray* get_method_parameter_annotations_of(int idnum) - { return get_method_annotations_from(idnum, _methods_parameter_annotations); } - AnnotationArray* get_method_default_annotations_of(int idnum) - { return get_method_annotations_from(idnum, _methods_default_annotations); } - - - void set_method_annotations_of(instanceKlassHandle ik, - int idnum, AnnotationArray* anno, TRAPS) { - set_methods_annotations_of(ik, idnum, anno, &_methods_annotations, THREAD); - } - - void set_method_parameter_annotations_of(instanceKlassHandle ik, - int idnum, AnnotationArray* anno, TRAPS) { - set_methods_annotations_of(ik, idnum, anno, &_methods_parameter_annotations, THREAD); - } - - void set_method_default_annotations_of(instanceKlassHandle ik, - int idnum, AnnotationArray* anno, TRAPS) { - set_methods_annotations_of(ik, idnum, anno, &_methods_default_annotations, THREAD); - } + void set_class_type_annotations(AnnotationArray* cta) { _class_type_annotations = cta; } + void set_fields_type_annotations(Array* fta) { _fields_type_annotations = fta; } // Turn metadata annotations into a Java heap object (oop) static typeArrayOop make_java_array(AnnotationArray* annotations, TRAPS); - inline AnnotationArray* get_method_annotations_from(int idnum, Array* annos); - void set_annotations(Array* md, Array** md_p) { *md_p = md; } - bool is_klass() const { return false; } private: - void set_methods_annotations_of(instanceKlassHandle ik, - int idnum, AnnotationArray* anno, - Array** md_p, TRAPS); - + static julong count_bytes(Array* p); public: const char* internal_name() const { return "{constant pool}"; } #ifndef PRODUCT @@ -150,13 +96,4 @@ #endif void print_value_on(outputStream* st) const; }; - - -// For method with idnum get the method's Annotations -inline AnnotationArray* Annotations::get_method_annotations_from(int idnum, Array* annos) { - if (annos == NULL || annos->length() <= idnum) { - return NULL; - } - return annos->at(idnum); -} #endif // SHARE_VM_OOPS_ANNOTATIONS_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/arrayKlass.hpp --- a/src/share/vm/oops/arrayKlass.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/arrayKlass.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -106,6 +106,14 @@ static int header_size() { return sizeof(ArrayKlass)/HeapWordSize; } static int static_size(int header_size); +#if INCLUDE_SERVICES + virtual void collect_statistics(KlassSizeStats *sz) const { + Klass::collect_statistics(sz); + // Do nothing for now, but remember to modify if you add new + // stuff to ArrayKlass. + } +#endif + // Java vtable klassVtable* vtable() const; // return new klassVtable int vtable_length() const { return _vtable_len; } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/constMethod.cpp --- a/src/share/vm/oops/constMethod.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/constMethod.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "interpreter/interpreter.hpp" #include "memory/gcLocker.hpp" +#include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" #include "oops/constMethod.hpp" #include "oops/method.hpp" @@ -35,51 +36,26 @@ ConstMethod* ConstMethod::allocate(ClassLoaderData* loader_data, int byte_code_size, - int compressed_line_number_size, - int localvariable_table_length, - int exception_table_length, - int checked_exceptions_length, - int method_parameters_length, - u2 generic_signature_index, + InlineTableSizes* sizes, MethodType method_type, TRAPS) { - int size = ConstMethod::size(byte_code_size, - compressed_line_number_size, - localvariable_table_length, - exception_table_length, - checked_exceptions_length, - method_parameters_length, - generic_signature_index); + int size = ConstMethod::size(byte_code_size, sizes); return new (loader_data, size, true, THREAD) ConstMethod( - byte_code_size, compressed_line_number_size, localvariable_table_length, - exception_table_length, checked_exceptions_length, - method_parameters_length, generic_signature_index, - method_type, size); + byte_code_size, sizes, method_type, size); } ConstMethod::ConstMethod(int byte_code_size, - int compressed_line_number_size, - int localvariable_table_length, - int exception_table_length, - int checked_exceptions_length, - int method_parameters_length, - u2 generic_signature_index, + InlineTableSizes* sizes, MethodType method_type, int size) { No_Safepoint_Verifier no_safepoint; - set_interpreter_kind(Interpreter::invalid); init_fingerprint(); set_constants(NULL); set_stackmap_data(NULL); set_code_size(byte_code_size); set_constMethod_size(size); - set_inlined_tables_length(generic_signature_index, - checked_exceptions_length, - compressed_line_number_size, - localvariable_table_length, - exception_table_length, - method_parameters_length); + set_inlined_tables_length(sizes); set_method_type(method_type); assert(this->size() == size, "wrong size for object"); } @@ -87,47 +63,70 @@ // Deallocate metadata fields associated with ConstMethod* void ConstMethod::deallocate_contents(ClassLoaderData* loader_data) { - set_interpreter_kind(Interpreter::invalid); if (stackmap_data() != NULL) { MetadataFactory::free_array(loader_data, stackmap_data()); } set_stackmap_data(NULL); + + // deallocate annotation arrays + if (has_method_annotations()) + MetadataFactory::free_array(loader_data, method_annotations()); + if (has_parameter_annotations()) + MetadataFactory::free_array(loader_data, parameter_annotations()); + if (has_type_annotations()) + MetadataFactory::free_array(loader_data, type_annotations()); + if (has_default_annotations()) + MetadataFactory::free_array(loader_data, default_annotations()); } // How big must this constMethodObject be? int ConstMethod::size(int code_size, - int compressed_line_number_size, - int local_variable_table_length, - int exception_table_length, - int checked_exceptions_length, - int method_parameters_length, - u2 generic_signature_index) { + InlineTableSizes* sizes) { int extra_bytes = code_size; - if (compressed_line_number_size > 0) { - extra_bytes += compressed_line_number_size; + if (sizes->compressed_linenumber_size() > 0) { + extra_bytes += sizes->compressed_linenumber_size(); } - if (checked_exceptions_length > 0) { + if (sizes->checked_exceptions_length() > 0) { extra_bytes += sizeof(u2); - extra_bytes += checked_exceptions_length * sizeof(CheckedExceptionElement); + extra_bytes += sizes->checked_exceptions_length() * sizeof(CheckedExceptionElement); } - if (local_variable_table_length > 0) { + if (sizes->localvariable_table_length() > 0) { extra_bytes += sizeof(u2); extra_bytes += - local_variable_table_length * sizeof(LocalVariableTableElement); + sizes->localvariable_table_length() * sizeof(LocalVariableTableElement); } - if (exception_table_length > 0) { + if (sizes->exception_table_length() > 0) { extra_bytes += sizeof(u2); - extra_bytes += exception_table_length * sizeof(ExceptionTableElement); + extra_bytes += sizes->exception_table_length() * sizeof(ExceptionTableElement); } - if (generic_signature_index != 0) { + if (sizes->generic_signature_index() != 0) { extra_bytes += sizeof(u2); } - if (method_parameters_length > 0) { + if (sizes->method_parameters_length() > 0) { extra_bytes += sizeof(u2); - extra_bytes += method_parameters_length * sizeof(MethodParametersElement); + extra_bytes += sizes->method_parameters_length() * sizeof(MethodParametersElement); + } + + // Align sizes up to a word. + extra_bytes = align_size_up(extra_bytes, BytesPerWord); + + // One pointer per annotation array + if (sizes->method_annotations_length() > 0) { + extra_bytes += sizeof(AnnotationArray*); } + if (sizes->parameter_annotations_length() > 0) { + extra_bytes += sizeof(AnnotationArray*); + } + if (sizes->type_annotations_length() > 0) { + extra_bytes += sizeof(AnnotationArray*); + } + if (sizes->default_annotations_length() > 0) { + extra_bytes += sizeof(AnnotationArray*); + } + int extra_words = align_size_up(extra_bytes, BytesPerWord) / BytesPerWord; + assert(extra_words == extra_bytes/BytesPerWord, "should already be aligned"); return align_object_size(header_size() + extra_words); } @@ -144,12 +143,28 @@ return code_end(); } +// Last short in ConstMethod* before annotations +u2* ConstMethod::last_u2_element() const { + int offset = 0; + if (has_method_annotations()) offset++; + if (has_parameter_annotations()) offset++; + if (has_type_annotations()) offset++; + if (has_default_annotations()) offset++; + return (u2*)((AnnotationArray**)constMethod_end() - offset) - 1; +} + u2* ConstMethod::generic_signature_index_addr() const { // Located at the end of the constMethod. assert(has_generic_signature(), "called only if generic signature exists"); return last_u2_element(); } +u2* ConstMethod::method_parameters_length_addr() const { + assert(has_method_parameters(), "called only if table is present"); + return has_generic_signature() ? (last_u2_element() - 1) : + last_u2_element(); +} + u2* ConstMethod::checked_exceptions_length_addr() const { // Located immediately before the generic signature index. assert(has_checked_exceptions(), "called only if table is present"); @@ -163,12 +178,6 @@ } } -u2* ConstMethod::method_parameters_length_addr() const { - assert(has_method_parameters(), "called only if table is present"); - return has_generic_signature() ? (last_u2_element() - 1) : - last_u2_element(); -} - u2* ConstMethod::exception_table_length_addr() const { assert(has_exception_handler(), "called only if table is present"); if (has_checked_exceptions()) { @@ -180,9 +189,9 @@ return (u2*)method_parameters_start() - 1; } else { // Else, the exception table is at the end of the constMethod. - return has_generic_signature() ? (last_u2_element() - 1) : - last_u2_element(); - } + return has_generic_signature() ? (last_u2_element() - 1) : + last_u2_element(); + } } } @@ -203,32 +212,38 @@ // Else, the exception table is at the end of the constMethod. return has_generic_signature() ? (last_u2_element() - 1) : last_u2_element(); + } } } - } } // Update the flags to indicate the presence of these optional fields. -void ConstMethod::set_inlined_tables_length(u2 generic_signature_index, - int checked_exceptions_len, - int compressed_line_number_size, - int localvariable_table_len, - int exception_table_len, - int method_parameters_len) { - assert(_flags == 0, "Error"); - if (compressed_line_number_size > 0) +void ConstMethod::set_inlined_tables_length(InlineTableSizes* sizes) { + _flags = 0; + if (sizes->compressed_linenumber_size() > 0) _flags |= _has_linenumber_table; - if (generic_signature_index != 0) + if (sizes->generic_signature_index() != 0) _flags |= _has_generic_signature; - if (method_parameters_len > 0) + if (sizes->method_parameters_length() > 0) _flags |= _has_method_parameters; - if (checked_exceptions_len > 0) + if (sizes->checked_exceptions_length() > 0) _flags |= _has_checked_exceptions; - if (exception_table_len > 0) + if (sizes->exception_table_length() > 0) _flags |= _has_exception_table; - if (localvariable_table_len > 0) + if (sizes->localvariable_table_length() > 0) _flags |= _has_localvariable_table; + // annotations, they are all pointer sized embedded objects so don't have + // a length embedded also. + if (sizes->method_annotations_length() > 0) + _flags |= _has_method_annotations; + if (sizes->parameter_annotations_length() > 0) + _flags |= _has_parameter_annotations; + if (sizes->type_annotations_length() > 0) + _flags |= _has_type_annotations; + if (sizes->default_annotations_length() > 0) + _flags |= _has_default_annotations; + // This code is extremely brittle and should possibly be revised. // The *_length_addr functions walk backwards through the // constMethod data, using each of the length indexes ahead of them, @@ -241,17 +256,17 @@ // Also, the servicability agent needs to be informed anytime // anything is added here. It might be advisable to have some sort // of indication of this inline. - if (generic_signature_index != 0) - *(generic_signature_index_addr()) = generic_signature_index; + if (sizes->generic_signature_index() != 0) + *(generic_signature_index_addr()) = sizes->generic_signature_index(); // New data should probably go here. - if (method_parameters_len > 0) - *(method_parameters_length_addr()) = method_parameters_len; - if (checked_exceptions_len > 0) - *(checked_exceptions_length_addr()) = checked_exceptions_len; - if (exception_table_len > 0) - *(exception_table_length_addr()) = exception_table_len; - if (localvariable_table_len > 0) - *(localvariable_table_length_addr()) = localvariable_table_len; + if (sizes->method_parameters_length() > 0) + *(method_parameters_length_addr()) = sizes->method_parameters_length(); + if (sizes->checked_exceptions_length() > 0) + *(checked_exceptions_length_addr()) = sizes->checked_exceptions_length(); + if (sizes->exception_table_length() > 0) + *(exception_table_length_addr()) = sizes->exception_table_length(); + if (sizes->localvariable_table_length() > 0) + *(localvariable_table_length_addr()) = sizes->localvariable_table_length(); } int ConstMethod::method_parameters_length() const { @@ -306,6 +321,34 @@ return (ExceptionTableElement*)addr; } +AnnotationArray** ConstMethod::method_annotations_addr() const { + assert(has_method_annotations(), "should only be called if method annotations are present"); + return (AnnotationArray**)constMethod_end() - 1; +} + +AnnotationArray** ConstMethod::parameter_annotations_addr() const { + assert(has_parameter_annotations(), "should only be called if method parameter annotations are present"); + int offset = 1; + if (has_method_annotations()) offset++; + return (AnnotationArray**)constMethod_end() - offset; +} + +AnnotationArray** ConstMethod::type_annotations_addr() const { + assert(has_type_annotations(), "should only be called if method type annotations are present"); + int offset = 1; + if (has_method_annotations()) offset++; + if (has_parameter_annotations()) offset++; + return (AnnotationArray**)constMethod_end() - offset; +} + +AnnotationArray** ConstMethod::default_annotations_addr() const { + assert(has_default_annotations(), "should only be called if method default annotations are present"); + int offset = 1; + if (has_method_annotations()) offset++; + if (has_parameter_annotations()) offset++; + if (has_type_annotations()) offset++; + return (AnnotationArray**)constMethod_end() - offset; +} // Printing @@ -330,6 +373,35 @@ method()->print_value_on(st); } +#if INCLUDE_SERVICES +// Size Statistics +void ConstMethod::collect_statistics(KlassSizeStats *sz) const { + int n1, n2, n3; + sz->_const_method_bytes += (n1 = sz->count(this)); + sz->_bytecode_bytes += (n2 = code_size()); + sz->_stackmap_bytes += (n3 = sz->count_array(stackmap_data())); + + // Count method annotations + int a1 = 0, a2 = 0, a3 = 0, a4 = 0; + if (has_method_annotations()) { + sz->_methods_annotations_bytes += (a1 = sz->count_array(method_annotations())); + } + if (has_parameter_annotations()) { + sz->_methods_parameter_annotations_bytes += (a2 = sz->count_array(parameter_annotations())); + } + if (has_type_annotations()) { + sz->_methods_type_annotations_bytes += (a3 = sz->count_array(type_annotations())); + } + if (has_default_annotations()) { + sz->_methods_default_annotations_bytes += (a4 = sz->count_array(default_annotations())); + } + + int size_annotations = a1 + a2 + a3 + a4; + + sz->_method_all_bytes += n1 + n3 + size_annotations; // note: n2 is part of n3 + sz->_ro_bytes += n1 + n3 + size_annotations; +} +#endif // INCLUDE_SERVICES // Verification @@ -339,10 +411,9 @@ // Verification can occur during oop construction before the method or // other fields have been initialized. - guarantee(is_metadata(), err_msg("Should be metadata " PTR_FORMAT, this)); guarantee(method()->is_method(), "should be method"); - address m_end = (address)((oop*) this + size()); + address m_end = (address)((intptr_t) this + size()); address compressed_table_start = code_end(); guarantee(compressed_table_start <= m_end, "invalid method layout"); address compressed_table_end = compressed_table_start; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/constMethod.hpp --- a/src/share/vm/oops/constMethod.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/constMethod.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,19 +86,22 @@ // | generic signature index (u2) | // | (indexed from start of constMethodOop) | // |------------------------------------------------------| +// | annotations arrays - method, parameter, type, default| +// | pointer to Array if annotation is present | +// |------------------------------------------------------| // // IMPORTANT: If anything gets added here, there need to be changes to // ensure that ServicabilityAgent doesn't get broken as a result! -// Utitily class decribing elements in checked exceptions table inlined in Method*. +// Utility class describing elements in checked exceptions table inlined in Method*. class CheckedExceptionElement VALUE_OBJ_CLASS_SPEC { public: u2 class_cp_index; }; -// Utitily class decribing elements in local variable table inlined in Method*. +// Utility class describing elements in local variable table inlined in Method*. class LocalVariableTableElement VALUE_OBJ_CLASS_SPEC { public: u2 start_bci; @@ -109,7 +112,7 @@ u2 slot; }; -// Utitily class describing elements in exception table +// Utility class describing elements in exception table class ExceptionTableElement VALUE_OBJ_CLASS_SPEC { public: u2 start_pc; @@ -122,14 +125,55 @@ class MethodParametersElement VALUE_OBJ_CLASS_SPEC { public: u2 name_cp_index; - // This has to happen, otherwise it will cause SIGBUS from a - // misaligned u4 on some architectures (ie SPARC) - // because MethodParametersElements are only aligned mod 2 - // within the ConstMethod container u2 flags_hi; - u2 flags_hi; - u2 flags_lo; + u2 flags; }; +class KlassSizeStats; + +// Class to collect the sizes of ConstMethod inline tables +#define INLINE_TABLES_DO(do_element) \ + do_element(localvariable_table_length) \ + do_element(compressed_linenumber_size) \ + do_element(exception_table_length) \ + do_element(checked_exceptions_length) \ + do_element(method_parameters_length) \ + do_element(generic_signature_index) \ + do_element(method_annotations_length) \ + do_element(parameter_annotations_length) \ + do_element(type_annotations_length) \ + do_element(default_annotations_length) + +#define INLINE_TABLE_DECLARE(sym) int _##sym; +#define INLINE_TABLE_PARAM(sym) int sym, +#define INLINE_TABLE_INIT(sym) _##sym(sym), +#define INLINE_TABLE_NULL(sym) _##sym(0), +#define INLINE_TABLE_ACCESSOR(sym) int sym() const { return _##sym; } + +class InlineTableSizes : StackObj { + // declarations + INLINE_TABLES_DO(INLINE_TABLE_DECLARE) + int _end; + public: + InlineTableSizes( + INLINE_TABLES_DO(INLINE_TABLE_PARAM) + int end) : + INLINE_TABLES_DO(INLINE_TABLE_INIT) + _end(end) {} + + // Default constructor for no inlined tables + InlineTableSizes() : + INLINE_TABLES_DO(INLINE_TABLE_NULL) + _end(0) {} + + // Accessors + INLINE_TABLES_DO(INLINE_TABLE_ACCESSOR) +}; +#undef INLINE_TABLE_ACCESSOR +#undef INLINE_TABLE_NULL +#undef INLINE_TABLE_INIT +#undef INLINE_TABLE_PARAM +#undef INLINE_TABLE_DECLARE + class ConstMethod : public MetaspaceObj { friend class VMStructs; @@ -139,13 +183,17 @@ private: enum { - _has_linenumber_table = 1, - _has_checked_exceptions = 2, - _has_localvariable_table = 4, - _has_exception_table = 8, - _has_generic_signature = 16, - _has_method_parameters = 32, - _is_overpass = 64 + _has_linenumber_table = 0x0001, + _has_checked_exceptions = 0x0002, + _has_localvariable_table = 0x0004, + _has_exception_table = 0x0008, + _has_generic_signature = 0x0010, + _has_method_parameters = 0x0020, + _is_overpass = 0x0040, + _has_method_annotations = 0x0080, + _has_parameter_annotations = 0x0100, + _has_type_annotations = 0x0200, + _has_default_annotations = 0x0400 }; // Bit vector of signature @@ -162,8 +210,7 @@ Array* _stackmap_data; int _constMethod_size; - jbyte _interpreter_kind; - jbyte _flags; + u2 _flags; // Size of Java bytecodes allocated immediately after Method*. u2 _code_size; @@ -178,36 +225,21 @@ // Constructor ConstMethod(int byte_code_size, - int compressed_line_number_size, - int localvariable_table_length, - int exception_table_length, - int checked_exceptions_length, - int method_parameters_length, - u2 generic_signature_index, + InlineTableSizes* sizes, MethodType is_overpass, int size); public: static ConstMethod* allocate(ClassLoaderData* loader_data, int byte_code_size, - int compressed_line_number_size, - int localvariable_table_length, - int exception_table_length, - int checked_exceptions_length, - int method_parameters_length, - u2 generic_signature_index, + InlineTableSizes* sizes, MethodType mt, TRAPS); bool is_constMethod() const { return true; } // Inlined tables - void set_inlined_tables_length(u2 generic_signature_index, - int checked_exceptions_len, - int compressed_line_number_size, - int localvariable_table_len, - int exception_table_len, - int method_parameters_length); + void set_inlined_tables_length(InlineTableSizes* sizes); bool has_generic_signature() const { return (_flags & _has_generic_signature) != 0; } @@ -239,10 +271,6 @@ } } - - void set_interpreter_kind(int kind) { _interpreter_kind = kind; } - int interpreter_kind(void) const { return _interpreter_kind; } - // constant pool ConstantPool* constants() const { return _constants; } void set_constants(ConstantPool* c) { _constants = c; } @@ -311,15 +339,13 @@ } // Size needed - static int size(int code_size, int compressed_line_number_size, - int local_variable_table_length, - int exception_table_length, - int checked_exceptions_length, - int method_parameters_length, - u2 generic_signature_index); + static int size(int code_size, InlineTableSizes* sizes); int size() const { return _constMethod_size;} void set_constMethod_size(int size) { _constMethod_size = size; } +#if INCLUDE_SERVICES + void collect_statistics(KlassSizeStats *sz) const; +#endif // code size int code_size() const { return _code_size; } @@ -355,6 +381,65 @@ int method_parameters_length() const; MethodParametersElement* method_parameters_start() const; + // method annotations + bool has_method_annotations() const + { return (_flags & _has_method_annotations) != 0; } + + bool has_parameter_annotations() const + { return (_flags & _has_parameter_annotations) != 0; } + + bool has_type_annotations() const + { return (_flags & _has_type_annotations) != 0; } + + bool has_default_annotations() const + { return (_flags & _has_default_annotations) != 0; } + + + AnnotationArray** method_annotations_addr() const; + AnnotationArray* method_annotations() const { + return has_method_annotations() ? *(method_annotations_addr()) : NULL; + } + void set_method_annotations(AnnotationArray* anno) { + *(method_annotations_addr()) = anno; + } + + AnnotationArray** parameter_annotations_addr() const; + AnnotationArray* parameter_annotations() const { + return has_parameter_annotations() ? *(parameter_annotations_addr()) : NULL; + } + void set_parameter_annotations(AnnotationArray* anno) { + *(parameter_annotations_addr()) = anno; + } + + AnnotationArray** type_annotations_addr() const; + AnnotationArray* type_annotations() const { + return has_type_annotations() ? *(type_annotations_addr()) : NULL; + } + void set_type_annotations(AnnotationArray* anno) { + *(type_annotations_addr()) = anno; + } + + AnnotationArray** default_annotations_addr() const; + AnnotationArray* default_annotations() const { + return has_default_annotations() ? *(default_annotations_addr()) : NULL; + } + void set_default_annotations(AnnotationArray* anno) { + *(default_annotations_addr()) = anno; + } + + int method_annotations_length() const { + return has_method_annotations() ? method_annotations()->length() : 0; + } + int parameter_annotations_length() const { + return has_parameter_annotations() ? parameter_annotations()->length() : 0; + } + int type_annotations_length() const { + return has_type_annotations() ? type_annotations()->length() : 0; + } + int default_annotations_length() const { + return has_default_annotations() ? default_annotations()->length() : 0; + } + // byte codes void set_code(address code) { if (code_size() > 0) { @@ -410,11 +495,10 @@ // First byte after ConstMethod* address constMethod_end() const - { return (address)((oop*)this + _constMethod_size); } + { return (address)((intptr_t*)this + _constMethod_size); } // Last short in ConstMethod* - u2* last_u2_element() const - { return (u2*)constMethod_end() - 1; } + u2* last_u2_element() const; public: // Printing diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/constantPool.cpp --- a/src/share/vm/oops/constantPool.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/constantPool.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -25,16 +25,17 @@ #include "precompiled.hpp" #include "classfile/classLoaderData.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/metadataOnStackMark.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "interpreter/linkResolver.hpp" +#include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" #include "memory/oopFactory.hpp" #include "oops/constantPool.hpp" #include "oops/instanceKlass.hpp" #include "oops/objArrayKlass.hpp" -#include "prims/jvmtiRedefineClasses.hpp" #include "runtime/fieldType.hpp" #include "runtime/init.hpp" #include "runtime/javaCalls.hpp" @@ -65,11 +66,10 @@ set_operands(NULL); set_pool_holder(NULL); set_flags(0); + // only set to non-zero if constant pool is merged by RedefineClasses set_version(0); set_lock(new Monitor(Monitor::nonleaf + 2, "A constant pool lock")); - // all fields are initialized; needed for GC - set_on_stack(false); // initialize tag array int length = tags->length(); @@ -100,18 +100,6 @@ set_lock(NULL); } -void ConstantPool::set_flag_at(FlagBit fb) { - const int MAX_STATE_CHANGES = 2; - for (int i = MAX_STATE_CHANGES + 10; i > 0; i--) { - int oflags = _flags; - int nflags = oflags | (1 << (int)fb); - if (Atomic::cmpxchg(nflags, &_flags, oflags) == oflags) - return; - } - assert(false, "failed to cmpxchg flags"); - _flags |= (1 << (int)fb); // better than nothing -} - objArrayOop ConstantPool::resolved_references() const { return (objArrayOop)JNIHandles::resolve(_resolved_references); } @@ -707,10 +695,6 @@ result_oop = string_at_impl(this_oop, index, cache_index, CHECK_NULL); break; - case JVM_CONSTANT_Object: - result_oop = this_oop->object_at(index); - break; - case JVM_CONSTANT_MethodHandleInError: case JVM_CONSTANT_MethodTypeInError: { @@ -1111,32 +1095,9 @@ } // end compare_entry_to() -// Copy this constant pool's entries at start_i to end_i (inclusive) -// to the constant pool to_cp's entries starting at to_i. A total of -// (end_i - start_i) + 1 entries are copied. -void ConstantPool::copy_cp_to_impl(constantPoolHandle from_cp, int start_i, int end_i, - constantPoolHandle to_cp, int to_i, TRAPS) { - - int dest_i = to_i; // leave original alone for debug purposes - - for (int src_i = start_i; src_i <= end_i; /* see loop bottom */ ) { - copy_entry_to(from_cp, src_i, to_cp, dest_i, CHECK); - - switch (from_cp->tag_at(src_i).value()) { - case JVM_CONSTANT_Double: - case JVM_CONSTANT_Long: - // double and long take two constant pool entries - src_i += 2; - dest_i += 2; - break; - - default: - // all others take one constant pool entry - src_i++; - dest_i++; - break; - } - } +void ConstantPool::copy_operands(constantPoolHandle from_cp, + constantPoolHandle to_cp, + TRAPS) { int from_oplen = operand_array_length(from_cp->operands()); int old_oplen = operand_array_length(to_cp->operands()); @@ -1164,7 +1125,7 @@ (len = old_off) * sizeof(u2)); fillp += len; // first part of src - Copy::conjoint_memory_atomic(to_cp->operands()->adr_at(0), + Copy::conjoint_memory_atomic(from_cp->operands()->adr_at(0), new_operands->adr_at(fillp), (len = from_off) * sizeof(u2)); fillp += len; @@ -1174,7 +1135,7 @@ (len = old_len - old_off) * sizeof(u2)); fillp += len; // second part of src - Copy::conjoint_memory_atomic(to_cp->operands()->adr_at(from_off), + Copy::conjoint_memory_atomic(from_cp->operands()->adr_at(from_off), new_operands->adr_at(fillp), (len = from_len - from_off) * sizeof(u2)); fillp += len; @@ -1192,8 +1153,39 @@ to_cp->set_operands(new_operands); } } +} // end copy_operands() -} // end copy_cp_to() + +// Copy this constant pool's entries at start_i to end_i (inclusive) +// to the constant pool to_cp's entries starting at to_i. A total of +// (end_i - start_i) + 1 entries are copied. +void ConstantPool::copy_cp_to_impl(constantPoolHandle from_cp, int start_i, int end_i, + constantPoolHandle to_cp, int to_i, TRAPS) { + + + int dest_i = to_i; // leave original alone for debug purposes + + for (int src_i = start_i; src_i <= end_i; /* see loop bottom */ ) { + copy_entry_to(from_cp, src_i, to_cp, dest_i, CHECK); + + switch (from_cp->tag_at(src_i).value()) { + case JVM_CONSTANT_Double: + case JVM_CONSTANT_Long: + // double and long take two constant pool entries + src_i += 2; + dest_i += 2; + break; + + default: + // all others take one constant pool entry + src_i++; + dest_i++; + break; + } + } + copy_operands(from_cp, to_cp, CHECK); + +} // end copy_cp_to_impl() // Copy this constant pool's entry at from_i to the constant pool @@ -1755,7 +1747,11 @@ void ConstantPool::set_on_stack(const bool value) { - _on_stack = value; + if (value) { + _flags |= _on_stack; + } else { + _flags &= ~_on_stack; + } if (value) MetadataOnStackMark::record(this); } @@ -1824,9 +1820,8 @@ st->print_cr(internal_name()); if (flags() != 0) { st->print(" - flags: 0x%x", flags()); - if (has_pseudo_string()) st->print(" has_pseudo_string"); - if (has_invokedynamic()) st->print(" has_invokedynamic"); if (has_preresolution()) st->print(" has_preresolution"); + if (on_stack()) st->print(" on_stack"); st->cr(); } if (pool_holder() != NULL) { @@ -1868,13 +1863,14 @@ st->print(" name_and_type_index=%d", uncached_name_and_type_ref_index_at(index)); break; case JVM_CONSTANT_String : - unresolved_string_at(index)->print_value_on(st); + if (is_pseudo_string_at(index)) { + oop anObj = pseudo_string_at(index); + anObj->print_value_on(st); + st->print(" {0x%lx}", (address)anObj); + } else { + unresolved_string_at(index)->print_value_on(st); + } break; - case JVM_CONSTANT_Object : { - oop anObj = object_at(index); - anObj->print_value_on(st); - st->print(" {0x%lx}", (address)anObj); - } break; case JVM_CONSTANT_Integer : st->print("%d", int_at(index)); break; @@ -1938,8 +1934,6 @@ void ConstantPool::print_value_on(outputStream* st) const { assert(is_constantPool(), "must be constantPool"); st->print("constant pool [%d]", length()); - if (has_pseudo_string()) st->print("/pseudo_string"); - if (has_invokedynamic()) st->print("/invokedynamic"); if (has_preresolution()) st->print("/preresolution"); if (operands() != NULL) st->print("/operands[%d]", operands()->length()); print_address_on(st); @@ -1954,6 +1948,20 @@ } } +#if INCLUDE_SERVICES +// Size Statistics +void ConstantPool::collect_statistics(KlassSizeStats *sz) const { + sz->_cp_all_bytes += (sz->_cp_bytes = sz->count(this)); + sz->_cp_all_bytes += (sz->_cp_tags_bytes = sz->count_array(tags())); + sz->_cp_all_bytes += (sz->_cp_cache_bytes = sz->count(cache())); + sz->_cp_all_bytes += (sz->_cp_operands_bytes = sz->count_array(operands())); + sz->_cp_all_bytes += (sz->_cp_refmap_bytes = sz->count_array(reference_map())); + + sz->_ro_bytes += sz->_cp_operands_bytes + sz->_cp_tags_bytes + + sz->_cp_refmap_bytes; + sz->_rw_bytes += sz->_cp_bytes + sz->_cp_cache_bytes; +} +#endif // INCLUDE_SERVICES // Verification diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/constantPool.hpp --- a/src/share/vm/oops/constantPool.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/constantPool.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -80,6 +80,7 @@ } }; +class KlassSizeStats; class ConstantPool : public Metadata { friend class VMStructs; friend class BytecodeInterpreter; // Directly extracts an oop in the pool for fast instanceof/checkcast @@ -95,11 +96,14 @@ jobject _resolved_references; Array* _reference_map; - int _flags; // a few header bits to describe contents for GC + enum { + _has_preresolution = 1, // Flags + _on_stack = 2 + }; + + int _flags; // old fashioned bit twiddling int _length; // number of elements in the array - bool _on_stack; // Redefined method still executing refers to this constant pool. - union { // set for CDS to restore resolved references int _resolved_reference_length; @@ -115,17 +119,8 @@ void set_operands(Array* operands) { _operands = operands; } - enum FlagBit { - FB_has_invokedynamic = 1, - FB_has_pseudo_string = 2, - FB_has_preresolution = 3 - }; - - int flags() const { return _flags; } - void set_flags(int f) { _flags = f; } - bool flag_at(FlagBit fb) const { return (_flags & (1 << (int)fb)) != 0; } - void set_flag_at(FlagBit fb); - // no clear_flag_at function; they only increase + int flags() const { return _flags; } + void set_flags(int f) { _flags = f; } private: intptr_t* base() const { return (intptr_t*) (((char*) this) + sizeof(ConstantPool)); } @@ -178,18 +173,14 @@ Array* tags() const { return _tags; } Array* operands() const { return _operands; } - bool has_pseudo_string() const { return flag_at(FB_has_pseudo_string); } - bool has_invokedynamic() const { return flag_at(FB_has_invokedynamic); } - bool has_preresolution() const { return flag_at(FB_has_preresolution); } - void set_pseudo_string() { set_flag_at(FB_has_pseudo_string); } - void set_invokedynamic() { set_flag_at(FB_has_invokedynamic); } - void set_preresolution() { set_flag_at(FB_has_preresolution); } + bool has_preresolution() const { return (_flags & _has_preresolution) != 0; } + void set_has_preresolution() { _flags |= _has_preresolution; } // Redefine classes support. If a method refering to this constant pool // is on the executing stack, or as a handle in vm code, this constant pool // can't be removed from the set of previous versions saved in the instance // class. - bool on_stack() const { return _on_stack; } + bool on_stack() const { return (_flags &_on_stack) != 0; } void set_on_stack(const bool value); // Klass holding pool @@ -325,14 +316,6 @@ resolved_references()->obj_at_put(obj_index, str); } - void set_object_tag_at(int which) { - release_tag_at_put(which, JVM_CONSTANT_Object); - } - - void object_at_put(int which, oop obj) { - resolved_references()->obj_at_put(cp_to_object_index(which), obj); - } - // For temporary use while constructing constant pool void string_index_at_put(int which, int string_index) { tag_at_put(which, JVM_CONSTANT_StringIndex); @@ -430,12 +413,6 @@ // Version that can be used before string oop array is created. oop uncached_string_at(int which, TRAPS); - oop object_at(int which) { - assert(tag_at(which).is_object(), "Corrupted constant pool"); - int obj_index = cp_to_object_index(which); - return resolved_references()->obj_at(obj_index); - } - // A "pseudo-string" is an non-string oop that has found is way into // a String entry. // Under EnableInvokeDynamic this can happen if the user patches a live @@ -455,10 +432,18 @@ return s; } + oop pseudo_string_at(int which) { + assert(tag_at(which).is_string(), "Corrupted constant pool"); + assert(unresolved_string_at(which) == NULL, "shouldn't have symbol"); + int obj_index = cp_to_object_index(which); + oop s = resolved_references()->obj_at(obj_index); + return s; + } + void pseudo_string_at_put(int which, int obj_index, oop x) { assert(EnableInvokeDynamic, ""); - set_pseudo_string(); // mark header assert(tag_at(which).is_string(), "Corrupted constant pool"); + unresolved_string_at_put(which, NULL); // indicates patched string string_at_put(which, obj_index, x); // this works just fine } @@ -686,9 +671,13 @@ return 0 <= index && index < length(); } + // Sizing (in words) static int header_size() { return sizeof(ConstantPool)/HeapWordSize; } static int size(int length) { return align_object_size(header_size() + length); } int size() const { return size(length()); } +#if INCLUDE_SERVICES + void collect_statistics(KlassSizeStats *sz) const; +#endif friend class ClassFileParser; friend class SystemDictionary; @@ -785,6 +774,7 @@ } static void copy_cp_to_impl(constantPoolHandle from_cp, int start_i, int end_i, constantPoolHandle to_cp, int to_i, TRAPS); static void copy_entry_to(constantPoolHandle from_cp, int from_i, constantPoolHandle to_cp, int to_i, TRAPS); + static void copy_operands(constantPoolHandle from_cp, constantPoolHandle to_cp, TRAPS); int find_matching_entry(int pattern_i, constantPoolHandle search_cp, TRAPS); int version() const { return _saved._version; } void set_version(int version) { _saved._version = version; } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/cpCache.cpp --- a/src/share/vm/oops/cpCache.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/cpCache.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -33,9 +33,10 @@ #include "prims/jvmtiRedefineClassesTrace.hpp" #include "prims/methodHandles.hpp" #include "runtime/handles.inline.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS # include "gc_implementation/parallelScavenge/psPromotionManager.hpp" -#endif +#endif // INCLUDE_ALL_GCS // Implememtation of ConstantPoolCacheEntry @@ -401,8 +402,9 @@ } +#if INCLUDE_JVMTI // RedefineClasses() API support: -// If this constantPoolCacheEntry refers to old_method then update it +// If this ConstantPoolCacheEntry refers to old_method then update it // to refer to new_method. bool ConstantPoolCacheEntry::adjust_method_entry(Method* old_method, Method* new_method, bool * trace_name_printed) { @@ -460,16 +462,24 @@ return false; } -#ifndef PRODUCT -bool ConstantPoolCacheEntry::check_no_old_entries() { +// a constant pool cache entry should never contain old or obsolete methods +bool ConstantPoolCacheEntry::check_no_old_or_obsolete_entries() { if (is_vfinal()) { + // virtual and final so _f2 contains method ptr instead of vtable index Metadata* f2 = (Metadata*)_f2; - return (f2->is_valid() && f2->is_method() && !((Method*)f2)->is_old()); - } else { - return (_f1 == NULL || (_f1->is_valid() && _f1->is_method() && !((Method*)_f1)->is_old())); + // Return false if _f2 refers to an old or an obsolete method. + // _f2 == NULL || !_f2->is_method() are just as unexpected here. + return (f2 != NULL NOT_PRODUCT(&& f2->is_valid()) && f2->is_method() && + !((Method*)f2)->is_old() && !((Method*)f2)->is_obsolete()); + } else if (_f1 == NULL || + (NOT_PRODUCT(_f1->is_valid() &&) !_f1->is_method())) { + // _f1 == NULL || !_f1->is_method() are OK here + return true; } + // return false if _f1 refers to an old or an obsolete method + return (NOT_PRODUCT(_f1->is_valid() &&) _f1->is_method() && + !((Method*)_f1)->is_old() && !((Method*)_f1)->is_obsolete()); } -#endif bool ConstantPoolCacheEntry::is_interesting_method_entry(Klass* k) { if (!is_method_entry()) { @@ -502,13 +512,15 @@ // the method is in the interesting class so the entry is interesting return true; } +#endif // INCLUDE_JVMTI void ConstantPoolCacheEntry::print(outputStream* st, int index) const { // print separator if (index == 0) st->print_cr(" -------------"); // print entry st->print("%3d ("PTR_FORMAT") ", index, (intptr_t)this); - st->print_cr("[%02x|%02x|%5d]", bytecode_2(), bytecode_1(), constant_pool_index()); + st->print_cr("[%02x|%02x|%5d]", bytecode_2(), bytecode_1(), + constant_pool_index()); st->print_cr(" [ "PTR_FORMAT"]", (intptr_t)_f1); st->print_cr(" [ "PTR_FORMAT"]", (intptr_t)_f2); st->print_cr(" [ "PTR_FORMAT"]", (intptr_t)_flags); @@ -552,8 +564,9 @@ } } +#if INCLUDE_JVMTI // RedefineClasses() API support: -// If any entry of this constantPoolCache points to any of +// If any entry of this ConstantPoolCache points to any of // old_methods, replace it with the corresponding new_method. void ConstantPoolCache::adjust_method_entries(Method** old_methods, Method** new_methods, int methods_length, bool * trace_name_printed) { @@ -572,7 +585,7 @@ continue; } - // The constantPoolCache contains entries for several different + // The ConstantPoolCache contains entries for several different // things, but we only care about methods. In fact, we only care // about methods in the same class as the one that contains the // old_methods. At this point, we have an interesting entry. @@ -591,17 +604,25 @@ } } -#ifndef PRODUCT -bool ConstantPoolCache::check_no_old_entries() { +// the constant pool cache should never contain old or obsolete methods +bool ConstantPoolCache::check_no_old_or_obsolete_entries() { for (int i = 1; i < length(); i++) { if (entry_at(i)->is_interesting_method_entry(NULL) && - !entry_at(i)->check_no_old_entries()) { + !entry_at(i)->check_no_old_or_obsolete_entries()) { return false; } } return true; } -#endif // PRODUCT + +void ConstantPoolCache::dump_cache() { + for (int i = 1; i < length(); i++) { + if (entry_at(i)->is_interesting_method_entry(NULL)) { + entry_at(i)->print(tty, i); + } + } +} +#endif // INCLUDE_JVMTI // Printing diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/cpCache.hpp --- a/src/share/vm/oops/cpCache.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/cpCache.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -337,16 +337,18 @@ static ByteSize f2_offset() { return byte_offset_of(ConstantPoolCacheEntry, _f2); } static ByteSize flags_offset() { return byte_offset_of(ConstantPoolCacheEntry, _flags); } +#if INCLUDE_JVMTI // RedefineClasses() API support: - // If this constantPoolCacheEntry refers to old_method then update it + // If this ConstantPoolCacheEntry refers to old_method then update it // to refer to new_method. // trace_name_printed is set to true if the current call has // printed the klass name so that other routines in the adjust_* // group don't print the klass name. bool adjust_method_entry(Method* old_method, Method* new_method, bool * trace_name_printed); - NOT_PRODUCT(bool check_no_old_entries();) + bool check_no_old_or_obsolete_entries(); bool is_interesting_method_entry(Klass* k); +#endif // INCLUDE_JVMTI // Debugging & Printing void print (outputStream* st, int index) const; @@ -423,15 +425,18 @@ return (base_offset() + ConstantPoolCacheEntry::size_in_bytes() * index); } +#if INCLUDE_JVMTI // RedefineClasses() API support: - // If any entry of this constantPoolCache points to any of + // If any entry of this ConstantPoolCache points to any of // old_methods, replace it with the corresponding new_method. // trace_name_printed is set to true if the current call has // printed the klass name so that other routines in the adjust_* // group don't print the klass name. void adjust_method_entries(Method** old_methods, Method** new_methods, int methods_length, bool * trace_name_printed); - NOT_PRODUCT(bool check_no_old_entries();) + bool check_no_old_or_obsolete_entries(); + void dump_cache(); +#endif // INCLUDE_JVMTI // Deallocate - no fields to deallocate DEBUG_ONLY(bool on_stack() { return false; }) diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/generateOopMap.cpp --- a/src/share/vm/oops/generateOopMap.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/generateOopMap.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1853,7 +1853,6 @@ if (tag.is_klass() || tag.is_unresolved_klass() || tag.is_string() || - tag.is_object() || tag.is_method_handle() || tag.is_method_type()) { assert(bt == T_OBJECT, "Guard is incorrect"); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/instanceClassLoaderKlass.cpp --- a/src/share/vm/oops/instanceClassLoaderKlass.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/instanceClassLoaderKlass.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -36,12 +36,13 @@ #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "runtime/handles.inline.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parNew/parOopClosures.inline.hpp" #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" #include "oops/oop.pcgc.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS #define if_do_metadata_checked(closure, nv_suffix) \ /* Make sure the non-virtual and the virtual versions match. */ \ @@ -73,7 +74,7 @@ return size; \ } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ \ int InstanceClassLoaderKlass:: \ @@ -83,7 +84,7 @@ int size = InstanceKlass::oop_oop_iterate_backwards##nv_suffix(obj, closure); \ return size; \ } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS #define InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ @@ -111,10 +112,10 @@ ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m) @@ -129,7 +130,7 @@ } } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void InstanceClassLoaderKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) { InstanceKlass::oop_follow_contents(cm, obj); @@ -155,5 +156,5 @@ } return size_helper(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/instanceClassLoaderKlass.hpp --- a/src/share/vm/oops/instanceClassLoaderKlass.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/instanceClassLoaderKlass.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -26,6 +26,7 @@ #define SHARE_VM_OOPS_INSTANCECLASSLOADERKLASS_HPP #include "oops/instanceKlass.hpp" +#include "utilities/macros.hpp" // An InstanceClassLoaderKlass is a specialization of the InstanceKlass. It does // not add any field. It is added to walk the dependencies for the class loader @@ -61,13 +62,13 @@ ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DECL) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS // Garbage collection void oop_follow_contents(oop obj); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/instanceKlass.cpp --- a/src/share/vm/oops/instanceKlass.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/instanceKlass.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ #include "interpreter/rewriter.hpp" #include "jvmtifiles/jvmti.h" #include "memory/genOopClosures.inline.hpp" +#include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" #include "memory/oopFactory.hpp" #include "oops/fieldStreams.hpp" @@ -55,7 +56,8 @@ #include "runtime/thread.inline.hpp" #include "services/threadService.hpp" #include "utilities/dtrace.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/cmsOopClosures.inline.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" @@ -66,7 +68,7 @@ #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" #include "oops/oop.pcgc.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 #include "c1/c1_Compiler.hpp" #endif @@ -164,20 +166,19 @@ volatile int InstanceKlass::_total_instanceKlass_count = 0; Klass* InstanceKlass::allocate_instance_klass(ClassLoaderData* loader_data, - int vtable_len, - int itable_len, - int static_field_size, - int nonstatic_oop_map_size, - ReferenceType rt, - AccessFlags access_flags, - Symbol* name, + int vtable_len, + int itable_len, + int static_field_size, + int nonstatic_oop_map_size, + ReferenceType rt, + AccessFlags access_flags, + Symbol* name, Klass* super_klass, - KlassHandle host_klass, - TRAPS) { + bool is_anonymous, + TRAPS) { int size = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size, - access_flags.is_interface(), - !host_klass.is_null()); + access_flags.is_interface(), is_anonymous); // Allocation InstanceKlass* ik; @@ -185,25 +186,25 @@ if (name == vmSymbols::java_lang_Class()) { ik = new (loader_data, size, THREAD) InstanceMirrorKlass( vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, - access_flags, !host_klass.is_null()); + access_flags, is_anonymous); } else if (name == vmSymbols::java_lang_ClassLoader() || (SystemDictionary::ClassLoader_klass_loaded() && super_klass != NULL && super_klass->is_subtype_of(SystemDictionary::ClassLoader_klass()))) { ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass( vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, - access_flags, !host_klass.is_null()); + access_flags, is_anonymous); } else { // normal class ik = new (loader_data, size, THREAD) InstanceKlass( vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, - access_flags, !host_klass.is_null()); + access_flags, is_anonymous); } } else { // reference klass ik = new (loader_data, size, THREAD) InstanceRefKlass( vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, - access_flags, !host_klass.is_null()); + access_flags, is_anonymous); } Atomic::inc(&_total_instanceKlass_count); @@ -2042,7 +2043,7 @@ assert_is_in_closed_subset) } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void InstanceKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) { assert(obj != NULL, "can't follow the content of NULL object"); @@ -2054,7 +2055,7 @@ PSParallelCompact::mark_and_push(cm, p), \ assert_is_in) } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // closure's do_metadata() method dictates whether the given closure should be // applied to the klass ptr in the object header. @@ -2082,7 +2083,7 @@ return size_helper(); \ } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ \ int InstanceKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, \ @@ -2100,7 +2101,7 @@ assert_is_in_closed_subset) \ return size_helper(); \ } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS #define InstanceKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ \ @@ -2124,10 +2125,10 @@ ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_DEFN_m) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_DEFN_m) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS int InstanceKlass::oop_adjust_pointers(oop obj) { int size = size_helper(); @@ -2139,7 +2140,7 @@ return size; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void InstanceKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { InstanceKlass_OOP_MAP_REVERSE_ITERATE( \ obj, \ @@ -2159,7 +2160,7 @@ return size; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) { assert(is_loader_alive(is_alive), "this klass should be live"); @@ -2791,7 +2792,10 @@ st->print("%s", source_debug_extension()); st->cr(); } - st->print(BULLET"annotations: "); annotations()->print_value_on(st); st->cr(); + st->print(BULLET"class annotations: "); class_annotations()->print_value_on(st); st->cr(); + st->print(BULLET"class type annotations: "); class_type_annotations()->print_value_on(st); st->cr(); + st->print(BULLET"field annotations: "); fields_annotations()->print_value_on(st); st->cr(); + st->print(BULLET"field type annotations: "); fields_type_annotations()->print_value_on(st); st->cr(); { ResourceMark rm; // PreviousVersionInfo objects returned via PreviousVersionWalker @@ -2960,6 +2964,52 @@ return external_name(); } +#if INCLUDE_SERVICES +// Size Statistics +void InstanceKlass::collect_statistics(KlassSizeStats *sz) const { + Klass::collect_statistics(sz); + + sz->_inst_size = HeapWordSize * size_helper(); + sz->_vtab_bytes = HeapWordSize * align_object_offset(vtable_length()); + sz->_itab_bytes = HeapWordSize * align_object_offset(itable_length()); + sz->_nonstatic_oopmap_bytes = HeapWordSize * + ((is_interface() || is_anonymous()) ? + align_object_offset(nonstatic_oop_map_size()) : + nonstatic_oop_map_size()); + + int n = 0; + n += (sz->_methods_array_bytes = sz->count_array(methods())); + n += (sz->_method_ordering_bytes = sz->count_array(method_ordering())); + n += (sz->_local_interfaces_bytes = sz->count_array(local_interfaces())); + n += (sz->_transitive_interfaces_bytes = sz->count_array(transitive_interfaces())); + n += (sz->_signers_bytes = sz->count_array(signers())); + n += (sz->_fields_bytes = sz->count_array(fields())); + n += (sz->_inner_classes_bytes = sz->count_array(inner_classes())); + sz->_ro_bytes += n; + + const ConstantPool* cp = constants(); + if (cp) { + cp->collect_statistics(sz); + } + + const Annotations* anno = annotations(); + if (anno) { + anno->collect_statistics(sz); + } + + const Array* methods_array = methods(); + if (methods()) { + for (int i = 0; i < methods_array->length(); i++) { + Method* method = methods_array->at(i); + if (method) { + sz->_method_count ++; + method->collect_statistics(sz); + } + } + } +} +#endif // INCLUDE_SERVICES + // Verification class VerifyFieldClosure: public OopClosure { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/instanceKlass.hpp --- a/src/share/vm/oops/instanceKlass.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/instanceKlass.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ #include "runtime/os.hpp" #include "utilities/accessFlags.hpp" #include "utilities/bitMap.inline.hpp" +#include "utilities/macros.hpp" // An InstanceKlass is the VM level representation of a Java class. // It contains all information needed for at class at execution runtime. @@ -154,8 +155,8 @@ ReferenceType rt, AccessFlags access_flags, Symbol* name, - Klass* super_klass, - KlassHandle host_klass, + Klass* super_klass, + bool is_anonymous, TRAPS); InstanceKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } @@ -256,6 +257,16 @@ // JVMTI fields can be moved to their own structure - see 6315920 unsigned char * _cached_class_file_bytes; // JVMTI: cached class file, before retransformable agent modified it in CFLH jint _cached_class_file_len; // JVMTI: length of above + + volatile u2 _idnum_allocated_count; // JNI/JVMTI: increments with the addition of methods, old ids don't change + + // Class states are defined as ClassState (see above). + // Place the _init_state here to utilize the unused 2-byte after + // _idnum_allocated_count. + u1 _init_state; // state of class + u1 _reference_type; // reference type + + JvmtiCachedClassFieldMap* _jvmti_cached_class_field_map; // JVMTI: used during heap iteration // Method array. @@ -281,15 +292,6 @@ // ... Array* _fields; - volatile u2 _idnum_allocated_count; // JNI/JVMTI: increments with the addition of methods, old ids don't change - - // Class states are defined as ClassState (see above). - // Place the _init_state here to utilize the unused 2-byte after - // _idnum_allocated_count. - u1 _init_state; // state of class - - u1 _reference_type; // reference type - // embedded Java vtable follows here // embedded Java itables follows here // embedded static fields follows here @@ -677,19 +679,19 @@ // annotations support Annotations* annotations() const { return _annotations; } void set_annotations(Annotations* anno) { _annotations = anno; } + AnnotationArray* class_annotations() const { - if (annotations() == NULL) return NULL; - return annotations()->class_annotations(); + return (_annotations != NULL) ? _annotations->class_annotations() : NULL; } Array* fields_annotations() const { - if (annotations() == NULL) return NULL; - return annotations()->fields_annotations(); + return (_annotations != NULL) ? _annotations->fields_annotations() : NULL; } - Annotations* type_annotations() const { - if (annotations() == NULL) return NULL; - return annotations()->type_annotations(); + AnnotationArray* class_type_annotations() const { + return (_annotations != NULL) ? _annotations->class_type_annotations() : NULL; } - + Array* fields_type_annotations() const { + return (_annotations != NULL) ? _annotations->fields_type_annotations() : NULL; + } // allocation instanceOop allocate_instance(TRAPS); @@ -808,6 +810,7 @@ // Sizing (in words) static int header_size() { return align_object_offset(sizeof(InstanceKlass)/HeapWordSize); } + static int size(int vtable_length, int itable_length, int nonstatic_oop_map_size, bool is_interface, bool is_anonymous) { @@ -826,6 +829,9 @@ is_interface(), is_anonymous()); } +#if INCLUDE_SERVICES + virtual void collect_statistics(KlassSizeStats *sz) const; +#endif static int vtable_start_offset() { return header_size(); } static int vtable_length_offset() { return offset_of(InstanceKlass, _vtable_len) / HeapWordSize; } @@ -842,10 +848,14 @@ return (OopMapBlock*)(start_of_itable() + align_object_offset(itable_length())); } + Klass** end_of_nonstatic_oop_maps() const { + return (Klass**)(start_of_nonstatic_oop_maps() + + nonstatic_oop_map_count()); + } + Klass** adr_implementor() const { if (is_interface()) { - return (Klass**)(start_of_nonstatic_oop_maps() + - nonstatic_oop_map_count()); + return (Klass**)end_of_nonstatic_oop_maps(); } else { return NULL; } @@ -857,8 +867,7 @@ if (adr_impl != NULL) { return adr_impl + 1; } else { - return (Klass**)(start_of_nonstatic_oop_maps() + - nonstatic_oop_map_count()); + return end_of_nonstatic_oop_maps(); } } else { return NULL; @@ -932,13 +941,13 @@ ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_DECL) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS u2 idnum_allocated_count() const { return _idnum_allocated_count; } private: @@ -1015,6 +1024,7 @@ void print_value_on(outputStream* st) const; void oop_print_value_on(oop obj, outputStream* st); + #ifndef PRODUCT void oop_print_on (oop obj, outputStream* st); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/instanceMirrorKlass.cpp --- a/src/share/vm/oops/instanceMirrorKlass.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/instanceMirrorKlass.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -35,7 +35,8 @@ #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "runtime/handles.inline.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/cmsOopClosures.inline.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" @@ -45,7 +46,7 @@ #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" #include "oops/oop.pcgc.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS int InstanceMirrorKlass::_offset_of_static_fields = 0; @@ -168,7 +169,7 @@ assert_is_in_closed_subset) } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void InstanceMirrorKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) { InstanceKlass::oop_follow_contents(cm, obj); @@ -189,7 +190,7 @@ PSParallelCompact::mark_and_push(cm, p), \ assert_is_in) } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS int InstanceMirrorKlass::oop_adjust_pointers(oop obj) { int size = oop_size(obj); @@ -262,7 +263,7 @@ } \ } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ \ int InstanceMirrorKlass:: \ @@ -278,7 +279,7 @@ InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(oop, nv_suffix); \ } \ } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS #define InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ @@ -310,14 +311,14 @@ ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void InstanceMirrorKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { // Note that we don't have to follow the mirror -> klass pointer, since all // klasses that are dirty will be scavenged when we iterate over the @@ -353,7 +354,7 @@ assert_nothing) return size; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS int InstanceMirrorKlass::instance_size(KlassHandle k) { if (k() != NULL && k->oop_is_instance()) { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/instanceMirrorKlass.hpp --- a/src/share/vm/oops/instanceMirrorKlass.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/instanceMirrorKlass.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -28,6 +28,7 @@ #include "classfile/systemDictionary.hpp" #include "oops/instanceKlass.hpp" #include "runtime/handles.hpp" +#include "utilities/macros.hpp" // An InstanceMirrorKlass is a specialized InstanceKlass for // java.lang.Class instances. These instances are special because @@ -107,13 +108,13 @@ ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_DECL) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS }; #endif // SHARE_VM_OOPS_INSTANCEMIRRORKLASS_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/instanceRefKlass.cpp --- a/src/share/vm/oops/instanceRefKlass.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/instanceRefKlass.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -33,7 +33,8 @@ #include "oops/instanceRefKlass.hpp" #include "oops/oop.inline.hpp" #include "utilities/preserveException.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" #include "gc_implementation/g1/g1RemSet.inline.hpp" @@ -42,7 +43,7 @@ #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" #include "oops/oop.pcgc.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS template void specialized_oop_follow_contents(InstanceRefKlass* ref, oop obj) { @@ -120,7 +121,7 @@ } } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS template void specialized_oop_follow_contents(InstanceRefKlass* ref, ParCompactionManager* cm, @@ -194,7 +195,7 @@ specialized_oop_follow_contents(this, cm, obj); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #ifdef ASSERT template void trace_reference_gc(const char *s, oop obj, @@ -317,7 +318,7 @@ } \ } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ \ int InstanceRefKlass:: \ @@ -333,7 +334,7 @@ InstanceRefKlass_SPECIALIZED_OOP_ITERATE(oop, nv_suffix, contains); \ } \ } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS #define InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ @@ -354,14 +355,14 @@ ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_DEFN) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS template void specialized_oop_push_contents(InstanceRefKlass *ref, PSPromotionManager* pm, oop obj) { @@ -444,7 +445,7 @@ } return size_helper(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS void InstanceRefKlass::update_nonstatic_oop_maps(Klass* k) { // Clear the nonstatic oop-map entries corresponding to referent diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/instanceRefKlass.hpp --- a/src/share/vm/oops/instanceRefKlass.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/instanceRefKlass.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -26,6 +26,7 @@ #define SHARE_VM_OOPS_INSTANCEREFKLASS_HPP #include "oops/instanceKlass.hpp" +#include "utilities/macros.hpp" // An InstanceRefKlass is a specialized InstanceKlass for Java // classes that are subclasses of java/lang/ref/Reference. @@ -83,13 +84,13 @@ ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_DECL) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS static void release_and_notify_pending_list_lock(BasicLock *pending_list_basic_lock); static void acquire_pending_list_lock(BasicLock *pending_list_basic_lock); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/klass.cpp --- a/src/share/vm/oops/klass.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/klass.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #include "classfile/vmSymbols.hpp" #include "gc_implementation/shared/markSweep.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" +#include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" @@ -37,11 +38,12 @@ #include "oops/oop.inline2.hpp" #include "runtime/atomic.hpp" #include "utilities/stack.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/psParallelCompact.hpp" #include "gc_implementation/parallelScavenge/psPromotionManager.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" -#endif +#endif // INCLUDE_ALL_GCS void Klass::set_name(Symbol* n) { _name = n; @@ -624,6 +626,17 @@ obj->print_address_on(st); } +#if INCLUDE_SERVICES +// Size Statistics +void Klass::collect_statistics(KlassSizeStats *sz) const { + sz->_klass_bytes = sz->count(this); + sz->_mirror_bytes = sz->count(java_mirror()); + sz->_secondary_supers_bytes = sz->count_array(secondary_supers()); + + sz->_ro_bytes += sz->_secondary_supers_bytes; + sz->_rw_bytes += sz->_klass_bytes + sz->_mirror_bytes; +} +#endif // INCLUDE_SERVICES // Verification diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/klass.hpp --- a/src/share/vm/oops/klass.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/klass.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,11 +35,12 @@ #include "runtime/orderAccess.hpp" #include "trace/traceMacros.hpp" #include "utilities/accessFlags.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp" #include "gc_implementation/g1/g1OopClosures.hpp" #include "gc_implementation/parNew/parOopClosures.hpp" -#endif +#endif // INCLUDE_ALL_GCS // // A Klass provides: @@ -75,11 +76,11 @@ // [class_loader_data] // [modifier_flags] // [access_flags ] -// [verify_count ] - not in product -// [alloc_count ] // [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] // [trace_id] @@ -91,6 +92,7 @@ class ClassLoaderData; class klassVtable; class ParCompactionManager; +class KlassSizeStats; class Klass : public Metadata { friend class VMStructs; @@ -168,18 +170,18 @@ jint _modifier_flags; // Processed access flags, for use by Class.getModifiers. AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here. + // Biased locking implementation and statistics + // (the 64-bit chunk goes first, to avoid some fragmentation) + jlong _last_biased_lock_bulk_revocation_time; + 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 - // Biased locking implementation and statistics - // (the 64-bit chunk goes first, to avoid some fragmentation) - jlong _last_biased_lock_bulk_revocation_time; - markOop _prototype_header; // Used when biased locking is both enabled and disabled for this type - jint _biased_lock_revocation_count; - TRACE_DEFINE_KLASS_TRACE_ID; // Remembered sets support for the oops in the klasses. @@ -489,6 +491,9 @@ // Size of klass in word size. virtual int size() const = 0; +#if INCLUDE_SERVICES + virtual void collect_statistics(KlassSizeStats *sz) const; +#endif // Returns the Java name for a class (Resource allocated) // For arrays, this returns the name of the element with a leading '['. @@ -637,13 +642,13 @@ return oop_oop_iterate(obj, blk); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // In case we don't have a specialized backward scanner use forward // iteration. virtual int oop_oop_iterate_backwards_v(oop obj, ExtendedOopClosure* blk) { return oop_oop_iterate_v(obj, blk); } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS // Iterates "blk" over all the oops in "obj" (of type "this") within "mr". // (I don't see why the _m should be required, but without it the Solaris @@ -675,7 +680,7 @@ SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_1(Klass_OOP_OOP_ITERATE_DECL) SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(Klass_OOP_OOP_ITERATE_DECL) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define Klass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ virtual int oop_oop_iterate_backwards##nv_suffix(oop obj, \ OopClosureType* blk) { \ @@ -685,7 +690,7 @@ SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_1(Klass_OOP_OOP_ITERATE_BACKWARDS_DECL) SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(Klass_OOP_OOP_ITERATE_BACKWARDS_DECL) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS virtual void array_klasses_do(void f(Klass* k)) {} virtual void with_array_klasses_do(void f(Klass* k)); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/klassPS.hpp --- a/src/share/vm/oops/klassPS.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/klassPS.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -27,7 +27,9 @@ // Expands to Parallel Scavenge and Parallel Old declarations -#ifndef SERIALGC +#include "utilities/macros.hpp" + +#if INCLUDE_ALL_GCS #define PARALLEL_GC_DECLS \ virtual void oop_push_contents(PSPromotionManager* pm, oop obj); \ /* Parallel Old GC support \ @@ -44,9 +46,9 @@ virtual void oop_push_contents(PSPromotionManager* pm, oop obj) = 0; \ virtual void oop_follow_contents(ParCompactionManager* cm, oop obj) = 0; \ virtual int oop_update_pointers(ParCompactionManager* cm, oop obj) = 0; -#else // SERIALGC +#else // INCLUDE_ALL_GCS #define PARALLEL_GC_DECLS #define PARALLEL_GC_DECLS_PV -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #endif // SHARE_VM_OOPS_KLASSPS_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/klassVtable.cpp --- a/src/share/vm/oops/klassVtable.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/klassVtable.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -610,6 +610,7 @@ Copy::disjoint_words((HeapWord*)table(), (HeapWord*)start, _length * vtableEntry::size()); } +#if INCLUDE_JVMTI void klassVtable::adjust_method_entries(Method** old_methods, Method** new_methods, int methods_length, bool * trace_name_printed) { // search the vtable for uses of either obsolete or EMCP methods @@ -638,11 +639,39 @@ new_method->name()->as_C_string(), new_method->signature()->as_C_string())); } + // cannot 'break' here; see for-loop comment above. } } } } +// a vtable should never contain old or obsolete methods +bool klassVtable::check_no_old_or_obsolete_entries() { + for (int i = 0; i < length(); i++) { + Method* m = unchecked_method_at(i); + if (m != NULL && + (NOT_PRODUCT(!m->is_valid() ||) m->is_old() || m->is_obsolete())) { + return false; + } + } + return true; +} + +void klassVtable::dump_vtable() { + tty->print_cr("vtable dump --"); + for (int i = 0; i < length(); i++) { + Method* m = unchecked_method_at(i); + if (m != NULL) { + tty->print(" (%5d) ", i); + m->access_flags().print_on(tty); + tty->print(" -- "); + m->print_name(tty); + tty->cr(); + } + } +} +#endif // INCLUDE_JVMTI + // CDS/RedefineClasses support - clear vtables so they can be reinitialized void klassVtable::clear_vtable() { for (int i = 0; i < _length; i++) table()[i].clear(); @@ -805,6 +834,7 @@ } } +#if INCLUDE_JVMTI void klassItable::adjust_method_entries(Method** old_methods, Method** new_methods, int methods_length, bool * trace_name_printed) { // search the itable for uses of either obsolete or EMCP methods @@ -833,13 +863,44 @@ new_method->name()->as_C_string(), new_method->signature()->as_C_string())); } - // Cannot break because there might be another entry for this method + // cannot 'break' here; see for-loop comment above. } ime++; } } } +// an itable should never contain old or obsolete methods +bool klassItable::check_no_old_or_obsolete_entries() { + itableMethodEntry* ime = method_entry(0); + for (int i = 0; i < _size_method_table; i++) { + Method* m = ime->method(); + if (m != NULL && + (NOT_PRODUCT(!m->is_valid() ||) m->is_old() || m->is_obsolete())) { + return false; + } + ime++; + } + return true; +} + +void klassItable::dump_itable() { + itableMethodEntry* ime = method_entry(0); + tty->print_cr("itable dump --"); + for (int i = 0; i < _size_method_table; i++) { + Method* m = ime->method(); + if (m != NULL) { + tty->print(" (%5d) ", i); + m->access_flags().print_on(tty); + tty->print(" -- "); + m->print_name(tty); + tty->cr(); + } + ime++; + } +} +#endif // INCLUDE_JVMTI + // Setup class InterfaceVisiterClosure : public StackObj { @@ -1126,43 +1187,6 @@ tty->print_cr("%6d bytes total", total); } -bool klassVtable::check_no_old_entries() { - // Check that there really is no entry - for (int i = 0; i < length(); i++) { - Method* m = unchecked_method_at(i); - if (m != NULL) { - if (!m->is_valid() || m->is_old()) { - return false; - } - } - } - return true; -} - -void klassVtable::dump_vtable() { - tty->print_cr("vtable dump --"); - for (int i = 0; i < length(); i++) { - Method* m = unchecked_method_at(i); - if (m != NULL) { - tty->print(" (%5d) ", i); - m->access_flags().print_on(tty); - tty->print(" -- "); - m->print_name(tty); - tty->cr(); - } - } -} - -bool klassItable::check_no_old_entries() { - itableMethodEntry* ime = method_entry(0); - for(int i = 0; i < _size_method_table; i++) { - Method* m = ime->method(); - if (m != NULL && (!m->is_valid() || m->is_old())) return false; - ime++; - } - return true; -} - int klassItable::_total_classes; // Total no. of classes with itables long klassItable::_total_size; // Total no. of bytes used for itables diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/klassVtable.hpp --- a/src/share/vm/oops/klassVtable.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/klassVtable.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,6 +90,7 @@ Array* methods, AccessFlags class_flags, Handle classloader, Symbol* classname, Array* local_interfaces, TRAPS); +#if INCLUDE_JVMTI // RedefineClasses() API support: // If any entry of this vtable points to any of old_methods, // replace it with the corresponding new_method. @@ -98,17 +99,15 @@ // group don't print the klass name. void adjust_method_entries(Method** old_methods, Method** new_methods, int methods_length, bool * trace_name_printed); + bool check_no_old_or_obsolete_entries(); + void dump_vtable(); +#endif // INCLUDE_JVMTI // Debugging code void print() PRODUCT_RETURN; void verify(outputStream* st, bool force = false); static void print_statistics() PRODUCT_RETURN; -#ifndef PRODUCT - bool check_no_old_entries(); - void dump_vtable(); -#endif - protected: friend class vtableEntry; private: @@ -275,6 +274,7 @@ // Updates void initialize_with_method(Method* m); +#if INCLUDE_JVMTI // RedefineClasses() API support: // if any entry of this itable points to any of old_methods, // replace it with the corresponding new_method. @@ -283,6 +283,9 @@ // group don't print the klass name. void adjust_method_entries(Method** old_methods, Method** new_methods, int methods_length, bool * trace_name_printed); + bool check_no_old_or_obsolete_entries(); + void dump_itable(); +#endif // INCLUDE_JVMTI // Setup of itable static int compute_itable_size(Array* transitive_interfaces); @@ -307,11 +310,6 @@ NOT_PRODUCT(static long _total_size;) // Total no. of bytes used for itables static void update_stats(int size) PRODUCT_RETURN NOT_PRODUCT({ _total_classes++; _total_size += size; }) - - public: -#ifndef PRODUCT - bool check_no_old_entries(); -#endif }; #endif // SHARE_VM_OOPS_KLASSVTABLE_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/method.cpp --- a/src/share/vm/oops/method.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/method.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/metadataOnStackMark.hpp" #include "classfile/systemDictionary.hpp" #include "code/debugInfoRec.hpp" #include "gc_interface/collectedHeap.inline.hpp" @@ -33,6 +34,7 @@ #include "interpreter/oopMapCache.hpp" #include "memory/gcLocker.hpp" #include "memory/generation.hpp" +#include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" #include "memory/oopFactory.hpp" #include "oops/constMethod.hpp" @@ -41,7 +43,6 @@ #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "prims/jvmtiExport.hpp" -#include "prims/jvmtiRedefineClasses.hpp" #include "prims/methodHandles.hpp" #include "prims/nativeLookup.hpp" #include "runtime/arguments.hpp" @@ -53,9 +54,6 @@ #include "runtime/signature.hpp" #include "utilities/quickSort.hpp" #include "utilities/xmlstream.hpp" -#ifdef GRAAL -#include "graal/graalJavaAccess.hpp" -#endif // Implementation of Method @@ -63,24 +61,14 @@ Method* Method::allocate(ClassLoaderData* loader_data, int byte_code_size, AccessFlags access_flags, - int compressed_line_number_size, - int localvariable_table_length, - int exception_table_length, - int checked_exceptions_length, - int method_parameters_length, - u2 generic_signature_index, + InlineTableSizes* sizes, ConstMethod::MethodType method_type, TRAPS) { assert(!access_flags.is_native() || byte_code_size == 0, "native methods should not contain byte codes"); ConstMethod* cm = ConstMethod::allocate(loader_data, byte_code_size, - compressed_line_number_size, - localvariable_table_length, - exception_table_length, - checked_exceptions_length, - method_parameters_length, - generic_signature_index, + sizes, method_type, CHECK_NULL); @@ -324,14 +312,6 @@ } -void Method::set_interpreter_kind() { - int kind = Interpreter::method_kind(this); - assert(kind != Interpreter::invalid, - "interpreter entry must be valid"); - set_interpreter_kind(kind); -} - - // Attempt to return method oop to original state. Clear any pointers // (to objects outside the shared spaces). We won't be able to predict // where they should point in a new JVM. Further initialize some @@ -339,7 +319,6 @@ void Method::remove_unshareable_info() { unlink_method(); - set_interpreter_kind(); } @@ -707,7 +686,7 @@ } -void Method::print_made_not_compilable(int comp_level, bool is_osr, bool report) { +void Method::print_made_not_compilable(int comp_level, bool is_osr, bool report, const char* reason) { if (PrintCompilation && report) { ttyLocker ttyl; tty->print("made not %scompilable on ", is_osr ? "OSR " : ""); @@ -721,15 +700,21 @@ } this->print_short_name(tty); int size = this->code_size(); - if (size > 0) + if (size > 0) { tty->print(" (%d bytes)", size); + } + if (reason != NULL) { + tty->print(" %s", reason); + } tty->cr(); } if ((TraceDeoptimization || LogCompilation) && (xtty != NULL)) { - ResourceMark rm; ttyLocker ttyl; xtty->begin_elem("make_not_%scompilable thread='" UINTX_FORMAT "'", is_osr ? "osr_" : "", os::current_thread_id()); + if (reason != NULL) { + xtty->print(" reason=\'%s\'", reason); + } xtty->method(this); xtty->stamp(); xtty->end_elem(); @@ -751,8 +736,8 @@ } // call this when compiler finds that this method is not compilable -void Method::set_not_compilable(int comp_level, bool report) { - print_made_not_compilable(comp_level, /*is_osr*/ false, report); +void Method::set_not_compilable(int comp_level, bool report, const char* reason) { + print_made_not_compilable(comp_level, /*is_osr*/ false, report, reason); if (comp_level == CompLevel_all) { set_not_c1_compilable(); set_not_c2_compilable(); @@ -777,8 +762,8 @@ return false; } -void Method::set_not_osr_compilable(int comp_level, bool report) { - print_made_not_compilable(comp_level, /*is_osr*/ true, report); +void Method::set_not_osr_compilable(int comp_level, bool report, const char* reason) { + print_made_not_compilable(comp_level, /*is_osr*/ true, report, reason); if (comp_level == CompLevel_all) { set_not_c1_osr_compilable(); set_not_c2_osr_compilable(); @@ -1036,7 +1021,7 @@ cp->set_pool_holder(InstanceKlass::cast(holder())); cp->symbol_at_put(_imcp_invoke_name, name); cp->symbol_at_put(_imcp_invoke_signature, signature); - cp->set_preresolution(); + cp->set_has_preresolution(); // decide on access bits: public or not? int flags_bits = (JVM_ACC_NATIVE | JVM_ACC_SYNTHETIC | JVM_ACC_FINAL); @@ -1046,9 +1031,9 @@ methodHandle m; { + InlineTableSizes sizes; Method* m_oop = Method::allocate(loader_data, 0, - accessFlags_from(flags_bits), - 0, 0, 0, 0, 0, 0, + accessFlags_from(flags_bits), &sizes, ConstMethod::NORMAL, CHECK_(empty)); m = methodHandle(THREAD, m_oop); } @@ -1097,22 +1082,35 @@ assert(!m->is_native(), "cannot rewrite native methods"); // Allocate new Method* AccessFlags flags = m->access_flags(); - u2 generic_signature_index = m->generic_signature_index(); - int checked_exceptions_len = m->checked_exceptions_length(); - int localvariable_len = m->localvariable_table_length(); - int exception_table_len = m->exception_table_length(); - int method_parameters_len = m->method_parameters_length(); + + ConstMethod* cm = m->constMethod(); + int checked_exceptions_len = cm->checked_exceptions_length(); + int localvariable_len = cm->localvariable_table_length(); + int exception_table_len = cm->exception_table_length(); + int method_parameters_len = cm->method_parameters_length(); + int method_annotations_len = cm->method_annotations_length(); + int parameter_annotations_len = cm->parameter_annotations_length(); + int type_annotations_len = cm->type_annotations_length(); + int default_annotations_len = cm->default_annotations_length(); + + InlineTableSizes sizes( + localvariable_len, + new_compressed_linenumber_size, + exception_table_len, + checked_exceptions_len, + method_parameters_len, + cm->generic_signature_index(), + method_annotations_len, + parameter_annotations_len, + type_annotations_len, + default_annotations_len, + 0); ClassLoaderData* loader_data = m->method_holder()->class_loader_data(); Method* newm_oop = Method::allocate(loader_data, new_code_length, flags, - new_compressed_linenumber_size, - localvariable_len, - exception_table_len, - checked_exceptions_len, - method_parameters_len, - generic_signature_index, + &sizes, m->method_type(), CHECK_(methodHandle())); methodHandle newm (THREAD, newm_oop); @@ -1312,29 +1310,6 @@ MethodHandles::print_as_basic_type_signature_on(st, signature(), true); } -// This is only done during class loading, so it is OK to assume method_idnum matches the methods() array -static void reorder_based_on_method_index(Array* methods, - Array* annotations, - GrowableArray* temp_array) { - if (annotations == NULL) { - return; - } - - int length = methods->length(); - int i; - // Copy to temp array - temp_array->clear(); - for (i = 0; i < length; i++) { - temp_array->append(annotations->at(i)); - } - - // Copy back using old method indices - for (i = 0; i < length; i++) { - Method* m = methods->at(i); - annotations->at_put(i, temp_array->at(m->method_idnum())); - } -} - // Comparer for sorting an object array containing // Method*s. static int method_comparator(Method* a, Method* b) { @@ -1342,48 +1317,13 @@ } // This is only done during class loading, so it is OK to assume method_idnum matches the methods() array -void Method::sort_methods(Array* methods, - Array* methods_annotations, - Array* methods_parameter_annotations, - Array* methods_default_annotations, - Array* methods_type_annotations, - bool idempotent) { +void Method::sort_methods(Array* methods, bool idempotent) { int length = methods->length(); if (length > 1) { - bool do_annotations = false; - if (methods_annotations != NULL || - methods_parameter_annotations != NULL || - methods_default_annotations != NULL || - methods_type_annotations != NULL) { - do_annotations = true; - } - if (do_annotations) { - // Remember current method ordering so we can reorder annotations - for (int i = 0; i < length; i++) { - Method* m = methods->at(i); - m->set_method_idnum(i); - } - } { No_Safepoint_Verifier nsv; QuickSort::sort(methods->data(), length, method_comparator, idempotent); } - - // Sort annotations if necessary - assert(methods_annotations == NULL || methods_annotations->length() == methods->length(), ""); - assert(methods_parameter_annotations == NULL || methods_parameter_annotations->length() == methods->length(), ""); - assert(methods_default_annotations == NULL || methods_default_annotations->length() == methods->length(), ""); - assert(methods_type_annotations == NULL || methods_type_annotations->length() == methods->length(), ""); - if (do_annotations) { - ResourceMark rm; - // Allocate temporary storage - GrowableArray* temp_array = new GrowableArray(length); - reorder_based_on_method_index(methods, methods_annotations, temp_array); - reorder_based_on_method_index(methods, methods_parameter_annotations, temp_array); - reorder_based_on_method_index(methods, methods_default_annotations, temp_array); - reorder_based_on_method_index(methods, methods_type_annotations, temp_array); - } - // Reset method ordering for (int i = 0; i < length; i++) { Method* m = methods->at(i); @@ -1394,9 +1334,9 @@ //----------------------------------------------------------------------------------- -// Non-product code +// Non-product code unless JVM/TI needs it -#ifndef PRODUCT +#if !defined(PRODUCT) || INCLUDE_JVMTI class SignatureTypePrinter : public SignatureTypeNames { private: outputStream* _st; @@ -1431,8 +1371,13 @@ sig.print_parameters(); st->print(")"); } +#endif // !PRODUCT || INCLUDE_JVMTI +//----------------------------------------------------------------------------------- +// Non-product code + +#ifndef PRODUCT void Method::print_codes_on(outputStream* st) const { print_codes_on(0, code_size(), st); } @@ -1963,6 +1908,22 @@ if (WizardMode && code() != NULL) st->print(" ((nmethod*)%p)", code()); } +#if INCLUDE_SERVICES +// Size Statistics +void Method::collect_statistics(KlassSizeStats *sz) const { + int mysize = sz->count(this); + sz->_method_bytes += mysize; + sz->_method_all_bytes += mysize; + sz->_rw_bytes += mysize; + + if (constMethod()) { + constMethod()->collect_statistics(sz); + } + if (method_data()) { + method_data()->collect_statistics(sz); + } +} +#endif // INCLUDE_SERVICES // Verification @@ -1979,16 +1940,3 @@ guarantee(md == NULL || md->is_methodData(), "should be method data"); } - -#ifdef GRAAL -void DebugScopedMethod::print_on(outputStream* st) { - if (_method != NULL) { - st->print("Method@%p", _method); - char holder[O_BUFLEN]; - char nameAndSig[O_BUFLEN]; - _method->method_holder()->name()->as_C_string(holder, O_BUFLEN); - _method->name_and_sig_as_C_string(nameAndSig, O_BUFLEN); - st->print(" - %s::%s", holder, nameAndSig); - } -} -#endif diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/method.hpp --- a/src/share/vm/oops/method.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/method.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,6 +101,8 @@ class AdapterHandlerEntry; class MethodData; class ConstMethod; +class InlineTableSizes; +class KlassSizeStats; class Method : public Metadata { friend class VMStructs; @@ -131,8 +133,8 @@ int _graal_priority; #endif #ifdef TIERED + float _rate; // Events (invocation and backedge counter increments) per millisecond jlong _prev_time; // Previous time the rate was acquired - float _rate; // Events (invocation and backedge counter increments) per millisecond #endif #ifndef PRODUCT @@ -160,12 +162,7 @@ static Method* allocate(ClassLoaderData* loader_data, int byte_code_size, AccessFlags access_flags, - int compressed_line_number_size, - int localvariable_table_length, - int exception_table_length, - int checked_exceptions_length, - int method_parameters_length, - u2 generic_signature_index, + InlineTableSizes* sizes, ConstMethod::MethodType method_type, TRAPS); @@ -210,33 +207,17 @@ // annotations support AnnotationArray* annotations() const { - InstanceKlass* ik = method_holder(); - if (ik->annotations() == NULL) { - return NULL; - } - return ik->annotations()->get_method_annotations_of(method_idnum()); + return constMethod()->method_annotations(); } AnnotationArray* parameter_annotations() const { - InstanceKlass* ik = method_holder(); - if (ik->annotations() == NULL) { - return NULL; - } - return ik->annotations()->get_method_parameter_annotations_of(method_idnum()); + return constMethod()->parameter_annotations(); } AnnotationArray* annotation_default() const { - InstanceKlass* ik = method_holder(); - if (ik->annotations() == NULL) { - return NULL; - } - return ik->annotations()->get_method_default_annotations_of(method_idnum()); + return constMethod()->default_annotations(); } - AnnotationArray* type_annotations() const { - InstanceKlass* ik = method_holder(); - Annotations* type_annos = ik->type_annotations(); - if (type_annos == NULL) - return NULL; - return type_annos->get_method_annotations_of(method_idnum()); -} + AnnotationArray* type_annotations() const { + return constMethod()->type_annotations(); + } #ifdef CC_INTERP void set_result_index(BasicType type); @@ -450,13 +431,6 @@ address interpreter_entry() const { return _i2i_entry; } // Only used when first initialize so we can set _i2i_entry and _from_interpreted_entry void set_interpreter_entry(address entry) { _i2i_entry = entry; _from_interpreted_entry = entry; } - int interpreter_kind(void) { - return constMethod()->interpreter_kind(); - } - void set_interpreter_kind(); - void set_interpreter_kind(int kind) { - constMethod()->set_interpreter_kind(kind); - } // native function (used for native methods only) enum { @@ -494,6 +468,8 @@ void print_codes_on(int from, int to, outputStream* st) const PRODUCT_RETURN; // method parameters + bool has_method_parameters() const + { return constMethod()->has_method_parameters(); } int method_parameters_length() const { return constMethod()->method_parameters_length(); } MethodParametersElement* method_parameters_start() const @@ -605,6 +581,9 @@ static int header_size() { return sizeof(Method)/HeapWordSize; } static int size(bool is_native); int size() const { return method_size(); } +#if INCLUDE_SERVICES + void collect_statistics(KlassSizeStats *sz) const; +#endif // interpreter support static ByteSize const_offset() { return byte_offset_of(Method, _constMethod ); } @@ -776,18 +755,18 @@ // whether it is not compilable for another reason like having a // breakpoint set in it. bool is_not_compilable(int comp_level = CompLevel_any) const; - void set_not_compilable(int comp_level = CompLevel_all, bool report = true); + void set_not_compilable(int comp_level = CompLevel_all, bool report = true, const char* reason = NULL); void set_not_compilable_quietly(int comp_level = CompLevel_all) { set_not_compilable(comp_level, false); } bool is_not_osr_compilable(int comp_level = CompLevel_any) const; - void set_not_osr_compilable(int comp_level = CompLevel_all, bool report = true); + void set_not_osr_compilable(int comp_level = CompLevel_all, bool report = true, const char* reason = NULL); void set_not_osr_compilable_quietly(int comp_level = CompLevel_all) { set_not_osr_compilable(comp_level, false); } private: - void print_made_not_compilable(int comp_level, bool is_osr, bool report); + 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(); } @@ -812,16 +791,15 @@ static bool has_unloaded_classes_in_signature(methodHandle m, TRAPS); // Printing - void print_short_name(outputStream* st = tty) /*PRODUCT_RETURN*/; // prints as klassname::methodname; Exposed so field engineers can debug VM + void print_short_name(outputStream* st = tty); // prints as klassname::methodname; Exposed so field engineers can debug VM +#if INCLUDE_JVMTI + void print_name(outputStream* st = tty); // prints as "virtual void foo(int)"; exposed for TraceRedefineClasses +#else void print_name(outputStream* st = tty) PRODUCT_RETURN; // prints as "virtual void foo(int)" +#endif // Helper routine used for method sorting - static void sort_methods(Array* methods, - Array* methods_annotations, - Array* methods_parameter_annotations, - Array* methods_default_annotations, - Array* methods_type_annotations, - bool idempotent = false); + static void sort_methods(Array* methods, bool idempotent = false); // Deallocation function for redefine classes or if an error occurs void deallocate_contents(ClassLoaderData* loader_data); @@ -1022,20 +1000,4 @@ } }; -#ifdef GRAAL -class DebugScopedMethod : public DebugScopedValue { -private: - Method* _method; -public: - DebugScopedMethod(const char* file, int line, Method* method) : DebugScopedValue(file, line), _method(method) {} - void print_on(outputStream* st); -}; -#define DS_METHOD(method) DebugScopedMethod __dsm__(__FILE__, __LINE__, method) -#define DS_METHOD1(var, method) DebugScopedMethod var(__FILE__, __LINE__, method) -#else -#define DS_METHOD(method) do {} while (0) -#define DS_METHOD1(var, method) do {} while (0) -#endif - #endif // SHARE_VM_OOPS_METHODOOP_HPP - diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/methodData.cpp --- a/src/share/vm/oops/methodData.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/methodData.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "interpreter/bytecode.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/linkResolver.hpp" +#include "memory/heapInspection.hpp" #include "oops/methodData.hpp" #include "prims/jvmtiRedefineClasses.hpp" #include "runtime/compilationPolicy.hpp" @@ -759,13 +760,6 @@ return CompilationPolicy::policy()->is_mature(_method); } -void MethodData::inc_decompile_count() { - _nof_decompiles += 1; - if (decompile_count() > (uint)PerMethodRecompilationCutoff) { - method()->set_not_compilable(CompLevel_full_optimization); - } -} - // Translate a bci to its corresponding data index (di). address MethodData::bci_to_dp(int bci) { ResourceMark rm; @@ -890,6 +884,15 @@ } #endif +#if INCLUDE_SERVICES +// Size Statistics +void MethodData::collect_statistics(KlassSizeStats *sz) const { + int n = sz->count(this); + sz->_method_data_bytes += n; + sz->_method_all_bytes += n; + sz->_rw_bytes += n; +} +#endif // INCLUDE_SERVICES // Verification diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/methodData.hpp --- a/src/share/vm/oops/methodData.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/methodData.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ #include "runtime/orderAccess.hpp" class BytecodeStream; +class KlassSizeStats; // The MethodData object collects counts and other profile information // during zeroth-tier (interpretive) and first-tier execution. @@ -1301,6 +1302,9 @@ // My size int size_in_bytes() const { return _size; } int size() const { return align_object_size(align_size_up(_size, BytesPerWord)/BytesPerWord); } +#if INCLUDE_SERVICES + void collect_statistics(KlassSizeStats *sz) const; +#endif int creation_mileage() const { return _creation_mileage; } void set_creation_mileage(int x) { _creation_mileage = x; } @@ -1471,7 +1475,12 @@ uint decompile_count() const { return _nof_decompiles; } - void inc_decompile_count(); + void inc_decompile_count() { + _nof_decompiles += 1; + if (decompile_count() > (uint)PerMethodRecompilationCutoff) { + method()->set_not_compilable(CompLevel_full_optimization, true, "decompile_count > PerMethodRecompilationCutoff"); + } + } // Support for code generation static ByteSize data_offset() { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/objArrayKlass.cpp --- a/src/share/vm/oops/objArrayKlass.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/objArrayKlass.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -43,7 +43,8 @@ #include "runtime/handles.inline.hpp" #include "runtime/mutexLocker.hpp" #include "utilities/copy.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/cmsOopClosures.inline.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" @@ -54,7 +55,7 @@ #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" #include "oops/oop.pcgc.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS ObjArrayKlass* ObjArrayKlass::allocate(ClassLoaderData* loader_data, int n, KlassHandle klass_handle, Symbol* name, TRAPS) { assert(ObjArrayKlass::header_size() <= InstanceKlass::header_size(), @@ -461,7 +462,7 @@ } } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void ObjArrayKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) { assert(obj->is_array(), "obj must be array"); @@ -472,7 +473,7 @@ objarray_follow_contents(cm, obj, 0); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #define if_do_metadata_checked(closure, nv_suffix) \ /* Make sure the non-virtual and the virtual versions match. */ \ @@ -573,7 +574,7 @@ return size; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void ObjArrayKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->is_objArray(), "obj must be obj array"); ObjArrayKlass_OOP_ITERATE( \ @@ -591,7 +592,7 @@ ObjArrayKlass_OOP_ITERATE(a, p, PSParallelCompact::adjust_pointer(p)) return size; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // JVM support diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/objArrayKlass.hpp --- a/src/share/vm/oops/objArrayKlass.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/objArrayKlass.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -28,6 +28,7 @@ #include "classfile/classLoaderData.hpp" #include "memory/specialized_oop_closures.hpp" #include "oops/arrayKlass.hpp" +#include "utilities/macros.hpp" // ObjArrayKlass is the klass for objArrays @@ -111,11 +112,11 @@ // Parallel Scavenge and Parallel Old PARALLEL_GC_DECLS -#ifndef SERIALGC +#if INCLUDE_ALL_GCS inline void oop_follow_contents(ParCompactionManager* cm, oop obj, int index); template inline void objarray_follow_contents(ParCompactionManager* cm, oop obj, int index); -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS // Iterators int oop_oop_iterate(oop obj, ExtendedOopClosure* blk) { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/objArrayKlass.inline.hpp --- a/src/share/vm/oops/objArrayKlass.inline.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/objArrayKlass.inline.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -27,10 +27,11 @@ #include "gc_implementation/shared/markSweep.inline.hpp" #include "oops/objArrayKlass.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/psCompactionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psParallelCompact.hpp" -#endif +#endif // INCLUDE_ALL_GCS void ObjArrayKlass::oop_follow_contents(oop obj, int index) { if (UseCompressedOops) { @@ -63,7 +64,7 @@ } } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void ObjArrayKlass::oop_follow_contents(ParCompactionManager* cm, oop obj, int index) { if (UseCompressedOops) { @@ -96,6 +97,6 @@ cm->push_objarray(a, end_index); // Push the continuation. } } -#endif // #ifndef SERIALGC +#endif // INCLUDE_ALL_GCS #endif // SHARE_VM_OOPS_OBJARRAYKLASS_INLINE_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/oop.hpp --- a/src/share/vm/oops/oop.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/oop.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -29,6 +29,7 @@ #include "memory/memRegion.hpp" #include "memory/specialized_oop_closures.hpp" #include "oops/metadata.hpp" +#include "utilities/macros.hpp" #include "utilities/top.hpp" // oopDesc is the top baseclass for objects classes. The {name}Desc classes describe @@ -298,7 +299,7 @@ // reference field in "this". void follow_contents(void); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Parallel Scavenge void push_contents(PSPromotionManager* pm); @@ -306,7 +307,7 @@ void update_contents(ParCompactionManager* cm); void follow_contents(ParCompactionManager* cm); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS bool is_scavengable() const; @@ -316,13 +317,13 @@ void forward_to(oop p); bool cas_forward_to(oop p, markOop compare); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Like "forward_to", but inserts the forwarding pointer atomically. // Exactly one thread succeeds in inserting the forwarding pointer, and // this call returns "NULL" for that thread; any other thread has the // value of the forwarding pointer returned and does not modify "this". oop forward_to_atomic(oop p); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS oop forwardee() const; @@ -334,10 +335,10 @@ // return the size of this oop. This is used by the MarkSweep collector. int adjust_pointers(); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Parallel old void update_header(ParCompactionManager* cm); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // mark-sweep support void follow_body(int begin, int end); @@ -354,7 +355,7 @@ ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_ITERATE_DECL) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ int oop_iterate_backwards(OopClosureType* blk); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/oop.inline.hpp --- a/src/share/vm/oops/oop.inline.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/oop.inline.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ #include "oops/oop.hpp" #include "runtime/atomic.hpp" #include "runtime/os.hpp" +#include "utilities/macros.hpp" #ifdef TARGET_ARCH_x86 # include "bytes_x86.hpp" #endif @@ -227,12 +228,12 @@ // might not be the same as oop. inline narrowOop oopDesc::encode_klass_not_null(Klass* v) { - assert(!is_null(v), "oop value can never be zero"); + assert(!is_null(v), "klass value can never be zero"); assert(check_klass_alignment(v), "Address not aligned"); address base = Universe::narrow_klass_base(); int shift = Universe::narrow_klass_shift(); uint64_t pd = (uint64_t)(pointer_delta((void*)v, (void*)base, 1)); - assert(OopEncodingHeapMax > pd, "change encoding max if new encoding"); + assert(KlassEncodingMetaspaceMax > pd, "change encoding max if new encoding"); uint64_t result = pd >> shift; assert((result & CONST64(0xffffffff00000000)) == 0, "narrow klass pointer overflow"); assert(decode_klass(result) == v, "reversibility"); @@ -760,7 +761,7 @@ ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_ITERATE_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_ITERATE_DEFN) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ \ inline int oopDesc::oop_iterate_backwards(OopClosureType* blk) { \ @@ -770,6 +771,6 @@ ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_ITERATE_BACKWARDS_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_ITERATE_BACKWARDS_DEFN) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS #endif // SHARE_VM_OOPS_OOP_INLINE_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/oop.pcgc.inline.hpp --- a/src/share/vm/oops/oop.pcgc.inline.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/oop.pcgc.inline.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -25,14 +25,15 @@ #ifndef SHARE_VM_OOPS_OOP_PCGC_INLINE_HPP #define SHARE_VM_OOPS_OOP_PCGC_INLINE_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parNew/parNewGeneration.hpp" #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" #include "gc_implementation/parallelScavenge/psCompactionManager.hpp" #include "gc_implementation/parallelScavenge/psParallelCompact.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS inline void oopDesc::update_contents(ParCompactionManager* cm) { // The klass field must be updated before anything else diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/oop.psgc.inline.hpp --- a/src/share/vm/oops/oop.psgc.inline.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/oop.psgc.inline.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -25,11 +25,12 @@ #ifndef SHARE_VM_OOPS_OOP_PSGC_INLINE_HPP #define SHARE_VM_OOPS_OOP_PSGC_INLINE_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS // ParallelScavengeHeap methods diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/symbol.cpp --- a/src/share/vm/oops/symbol.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/symbol.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -152,6 +152,7 @@ } void Symbol::print_symbol_on(outputStream* st) const { + ResourceMark rm; st = st ? st : tty; st->print("%s", as_quoted_ascii()); } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/oops/typeArrayKlass.cpp --- a/src/share/vm/oops/typeArrayKlass.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/oops/typeArrayKlass.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -39,6 +39,7 @@ #include "oops/typeArrayKlass.hpp" #include "oops/typeArrayOop.hpp" #include "runtime/handles.inline.hpp" +#include "utilities/macros.hpp" bool TypeArrayKlass::compute_is_subtype_of(Klass* k) { if (!k->oop_is_typeArray()) { @@ -208,13 +209,13 @@ // know that Universe::TypeArrayKlass never moves. } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void TypeArrayKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) { assert(obj->is_typeArray(),"must be a type array"); // Performance tweak: We skip iterating over the klass pointer since we // know that Universe::TypeArrayKlass never moves. } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS int TypeArrayKlass::oop_adjust_pointers(oop obj) { assert(obj->is_typeArray(),"must be a type array"); @@ -240,7 +241,7 @@ return t->object_size(); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void TypeArrayKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { ShouldNotReachHere(); assert(obj->is_typeArray(),"must be a type array"); @@ -251,7 +252,7 @@ assert(obj->is_typeArray(),"must be a type array"); return typeArrayOop(obj)->object_size(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS void TypeArrayKlass::initialize(TRAPS) { // Nothing to do. Having this function is handy since objArrayKlasses can be diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/bytecodeInfo.cpp --- a/src/share/vm/opto/bytecodeInfo.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/bytecodeInfo.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -47,7 +47,8 @@ _site_invoke_ratio(site_invoke_ratio), _max_inline_level(max_inline_level), _count_inline_bcs(method()->code_size_for_inlining()), - _subtrees(c->comp_arena(), 2, 0, NULL) + _subtrees(c->comp_arena(), 2, 0, NULL), + _msg(NULL) { NOT_PRODUCT(_count_inlines = 0;) if (_caller_jvms != NULL) { @@ -77,7 +78,8 @@ _method(callee_method), _site_invoke_ratio(site_invoke_ratio), _max_inline_level(max_inline_level), - _count_inline_bcs(method()->code_size()) + _count_inline_bcs(method()->code_size()), + _msg(NULL) { NOT_PRODUCT(_count_inlines = 0;) assert(!UseOldInlining, "do not use for old stuff"); @@ -95,8 +97,10 @@ ); } -// positive filter: should callee be inlined? returns NULL, if yes, or rejection msg -const char* InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const { +// positive filter: should callee be inlined? +bool InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_method, + int caller_bci, ciCallProfile& profile, + WarmCallInfo* wci_result) { // Allows targeted inlining if(callee_method->should_inline()) { *wci_result = *(WarmCallInfo::always_hot()); @@ -104,11 +108,10 @@ CompileTask::print_inline_indent(inline_level()); tty->print_cr("Inlined method is hot: "); } - return NULL; + set_msg("force inline by CompilerOracle"); + return true; } - // positive filter: should send be inlined? returns NULL (--> yes) - // or rejection msg int size = callee_method->code_size_for_inlining(); // Check for too many throws (and not too huge) @@ -119,11 +122,13 @@ CompileTask::print_inline_indent(inline_level()); tty->print_cr("Inlined method with many throws (throws=%d):", callee_method->interpreter_throwout_count()); } - return NULL; + set_msg("many throws"); + return true; } if (!UseOldInlining) { - return NULL; // size and frequency are represented in a new way + set_msg("!UseOldInlining"); + return true; // size and frequency are represented in a new way } int default_max_inline_size = C->max_inline_size(); @@ -153,31 +158,44 @@ // 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) - return "already compiled into a medium method"; + set_msg("already compiled into a medium method"); + return false; } if (size > max_inline_size) { - if (max_inline_size > default_max_inline_size) - return "hot method too big"; - return "too big"; + if (max_inline_size > default_max_inline_size) { + set_msg("hot method too big"); + } else { + set_msg("too big"); + } + return false; } - return NULL; + return true; } -// negative filter: should callee NOT be inlined? returns NULL, ok to inline, or rejection msg -const char* InlineTree::should_not_inline(ciMethod *callee_method, ciMethod* caller_method, WarmCallInfo* wci_result) const { - // negative filter: should send NOT be inlined? returns NULL (--> inline) or rejection msg +// negative filter: should callee NOT be inlined? +bool InlineTree::should_not_inline(ciMethod *callee_method, + ciMethod* caller_method, + WarmCallInfo* wci_result) { + + const char* fail_msg = NULL; + + // First check all inlining restrictions which are required for correctness + if ( callee_method->is_abstract()) { + fail_msg = "abstract method"; // // note: we allow ik->is_abstract() + } else if (!callee_method->holder()->is_initialized()) { + fail_msg = "method holder not initialized"; + } else if ( callee_method->is_native()) { + fail_msg = "native method"; + } else if ( callee_method->dont_inline()) { + fail_msg = "don't inline by annotation"; + } + if (!UseOldInlining) { - const char* fail = NULL; - if ( callee_method->is_abstract()) fail = "abstract method"; - // note: we allow ik->is_abstract() - if (!callee_method->holder()->is_initialized()) fail = "method holder not initialized"; - if ( callee_method->is_native()) fail = "native method"; - if ( callee_method->dont_inline()) fail = "don't inline by annotation"; - - if (fail) { + if (fail_msg != NULL) { *wci_result = *(WarmCallInfo::always_cold()); - return fail; + set_msg(fail_msg); + return true; } if (callee_method->has_unloaded_classes_in_signature()) { @@ -199,23 +217,27 @@ // %%% adjust wci_result->size()? } - return NULL; + return false; + } + + // one more inlining restriction + if (fail_msg == NULL && callee_method->has_unloaded_classes_in_signature()) { + fail_msg = "unloaded signature classes"; } - // First check all inlining restrictions which are required for correctness - if ( callee_method->is_abstract()) return "abstract method"; - // note: we allow ik->is_abstract() - if (!callee_method->holder()->is_initialized()) return "method holder not initialized"; - if ( callee_method->is_native()) return "native method"; - if ( callee_method->dont_inline()) return "don't inline by annotation"; - if ( callee_method->has_unloaded_classes_in_signature()) return "unloaded signature classes"; + if (fail_msg != NULL) { + set_msg(fail_msg); + return true; + } + // ignore heuristic controls on inlining if (callee_method->should_inline()) { - // ignore heuristic controls on inlining - return NULL; + set_msg("force inline by CompilerOracle"); + return false; } if (callee_method->should_not_inline()) { - return "disallowed by CompilerOracle"; + set_msg("disallowed by CompilerOracle"); + return false; } // Now perform checks which are heuristic @@ -223,7 +245,8 @@ if (!callee_method->force_inline()) { if (callee_method->has_compiled_code() && callee_method->instructions_size() > InlineSmallCode) { - return "already compiled into a big method"; + set_msg("already compiled into a big method"); + return true; } } @@ -234,17 +257,21 @@ const InlineTree *top = this; while (top->caller_tree() != NULL) top = top->caller_tree(); ciInstanceKlass* k = top->method()->holder(); - if (!k->is_subclass_of(C->env()->Throwable_klass())) - return "exception method"; + if (!k->is_subclass_of(C->env()->Throwable_klass())) { + set_msg("exception method"); + return true; + } } if (callee_method->should_not_inline()) { - return "disallowed by CompilerOracle"; + set_msg("disallowed by CompilerOracle"); + return true; } #ifndef PRODUCT if (ciReplay::should_not_inline(callee_method)) { - return "disallowed by ciReplay"; + set_msg("disallowed by ciReplay"); + return true; } #endif @@ -252,19 +279,23 @@ // Do not inline StringCache::profile() method used only at the beginning. if (callee_method->name() == ciSymbol::profile_name() && callee_method->holder()->name() == ciSymbol::java_lang_StringCache()) { - return "profiling method"; + set_msg("profiling method"); + return true; } } // use frequency-based objections only for non-trivial methods - if (callee_method->code_size() <= MaxTrivialSize) return NULL; + if (callee_method->code_size() <= MaxTrivialSize) { + return false; + } // don't use counts with -Xcomp or CTW if (UseInterpreter && !CompileTheWorld) { if (!callee_method->has_compiled_code() && !callee_method->was_executed_more_than(0)) { - return "never executed"; + set_msg("never executed"); + return true; } if (is_init_with_ea(callee_method, caller_method, C)) { @@ -273,39 +304,44 @@ } else if (!callee_method->was_executed_more_than(MIN2(MinInliningThreshold, CompileThreshold >> 1))) { - return "executed < MinInliningThreshold times"; + set_msg("executed < MinInliningThreshold times"); + return true; } } - return NULL; + return false; } //-----------------------------try_to_inline----------------------------------- -// return NULL if ok, reason for not inlining otherwise +// return true if ok // Relocated from "InliningClosure::try_to_inline" -const char* InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result, bool& should_delay) { - // Old algorithm had funny accumulating BC-size counters +bool InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_method, + int caller_bci, ciCallProfile& profile, + WarmCallInfo* wci_result, bool& should_delay) { + + // Old algorithm had funny accumulating BC-size counters if (UseOldInlining && ClipInlining && (int)count_inline_bcs() >= DesiredMethodLimit) { if (!callee_method->force_inline() || !IncrementalInline) { - return "size > DesiredMethodLimit"; + set_msg("size > DesiredMethodLimit"); + return false; } else if (!C->inlining_incrementally()) { should_delay = true; } } - const char *msg = NULL; - msg = should_inline(callee_method, caller_method, caller_bci, profile, wci_result); - if (msg != NULL) - return msg; - - msg = should_not_inline(callee_method, caller_method, wci_result); - if (msg != NULL) - return msg; + if (!should_inline(callee_method, caller_method, caller_bci, profile, + wci_result)) { + return false; + } + if (should_not_inline(callee_method, caller_method, wci_result)) { + return false; + } if (InlineAccessors && callee_method->is_accessor()) { // accessor methods are not subject to any of the following limits. - return NULL; + set_msg("accessor"); + return true; } // suppress a few checks for accessors and trivial methods @@ -315,7 +351,8 @@ if (C->over_inlining_cutoff()) { if ((!callee_method->force_inline() && !caller_method->is_compiled_lambda_form()) || !IncrementalInline) { - return "NodeCountInliningCutoff"; + set_msg("NodeCountInliningCutoff"); + return false; } else { should_delay = true; } @@ -329,16 +366,19 @@ } else if (profile.count() == 0) { // don't inline unreached call sites - return "call site not reached"; + set_msg("call site not reached"); + return false; } } if (!C->do_inlining() && InlineAccessors) { - return "not an accessor"; + set_msg("not an accessor"); + return false; } if (inline_level() > _max_inline_level) { if (!callee_method->force_inline() || !IncrementalInline) { - return "inlining too deep"; + set_msg("inlining too deep"); + return false; } else if (!C->inlining_incrementally()) { should_delay = true; } @@ -348,15 +388,19 @@ if (!callee_method->is_compiled_lambda_form()) { // count the current method and the callee int inline_level = (method() == callee_method) ? 1 : 0; - if (inline_level > MaxRecursiveInlineLevel) - return "recursively inlining too deep"; + if (inline_level > MaxRecursiveInlineLevel) { + set_msg("recursively inlining too deep"); + return false; + } // count callers of current method and callee JVMState* jvms = caller_jvms(); while (jvms != NULL && jvms->has_method()) { if (jvms->method() == callee_method) { inline_level++; - if (inline_level > MaxRecursiveInlineLevel) - return "recursively inlining too deep"; + if (inline_level > MaxRecursiveInlineLevel) { + set_msg("recursively inlining too deep"); + return false; + } } jvms = jvms->caller(); } @@ -367,14 +411,15 @@ if (UseOldInlining && ClipInlining && (int)count_inline_bcs() + size >= DesiredMethodLimit) { if (!callee_method->force_inline() || !IncrementalInline) { - return "size > DesiredMethodLimit"; + set_msg("size > DesiredMethodLimit"); + return false; } else if (!C->inlining_incrementally()) { should_delay = true; } } // ok, inline this method - return NULL; + return true; } //------------------------------pass_initial_checks---------------------------- @@ -423,14 +468,25 @@ } //------------------------------print_inlining--------------------------------- -// Really, the failure_msg can be a success message also. -void InlineTree::print_inlining(ciMethod* callee_method, int caller_bci, const char* failure_msg) const { - C->print_inlining(callee_method, inline_level(), caller_bci, failure_msg ? failure_msg : "inline"); - if (callee_method == NULL) tty->print(" callee not monotonic or profiled"); - if (Verbose && callee_method) { - const InlineTree *top = this; - while( top->caller_tree() != NULL ) { top = top->caller_tree(); } - //tty->print(" bcs: %d+%d invoked: %d", top->count_inline_bcs(), callee_method->code_size(), callee_method->interpreter_invocation_count()); +void InlineTree::print_inlining(ciMethod* callee_method, int caller_bci, + bool success) const { + const char* inline_msg = msg(); + assert(inline_msg != NULL, "just checking"); + if (C->log() != NULL) { + if (success) { + C->log()->inline_success(inline_msg); + } else { + C->log()->inline_fail(inline_msg); + } + } + if (PrintInlining) { + C->print_inlining(callee_method, inline_level(), caller_bci, inline_msg); + if (callee_method == NULL) tty->print(" callee not monotonic or profiled"); + if (Verbose && callee_method) { + const InlineTree *top = this; + while( top->caller_tree() != NULL ) { top = top->caller_tree(); } + //tty->print(" bcs: %d+%d invoked: %d", top->count_inline_bcs(), callee_method->code_size(), callee_method->interpreter_invocation_count()); + } } } @@ -448,48 +504,50 @@ } assert(_method == jvms->method(), "redundant instance state"); #endif - const char *failure_msg = NULL; int caller_bci = jvms->bci(); - ciMethod *caller_method = jvms->method(); + ciMethod* caller_method = jvms->method(); // Do some initial checks. if (!pass_initial_checks(caller_method, caller_bci, callee_method)) { - if (PrintInlining) print_inlining(callee_method, caller_bci, "failed initial checks"); + set_msg("failed initial checks"); + print_inlining(callee_method, caller_bci, false /* !success */); return NULL; } // Do some parse checks. - failure_msg = check_can_parse(callee_method); - if (failure_msg != NULL) { - if (PrintInlining) print_inlining(callee_method, caller_bci, failure_msg); + set_msg(check_can_parse(callee_method)); + if (msg() != NULL) { + print_inlining(callee_method, caller_bci, false /* !success */); return NULL; } // Check if inlining policy says no. WarmCallInfo wci = *(initial_wci); - failure_msg = try_to_inline(callee_method, caller_method, caller_bci, profile, &wci, should_delay); - if (failure_msg != NULL && C->log() != NULL) { - C->log()->inline_fail(failure_msg); - } + bool success = try_to_inline(callee_method, caller_method, caller_bci, + profile, &wci, should_delay); #ifndef PRODUCT if (UseOldInlining && InlineWarmCalls && (PrintOpto || PrintOptoInlining || PrintInlining)) { bool cold = wci.is_cold(); bool hot = !cold && wci.is_hot(); - bool old_cold = (failure_msg != NULL); + bool old_cold = !success; if (old_cold != cold || (Verbose || WizardMode)) { + if (msg() == NULL) { + set_msg("OK"); + } tty->print(" OldInlining= %4s : %s\n WCI=", - old_cold ? "cold" : "hot", failure_msg ? failure_msg : "OK"); + old_cold ? "cold" : "hot", msg()); wci.print(); } } #endif if (UseOldInlining) { - if (failure_msg == NULL) + if (success) { wci = *(WarmCallInfo::always_hot()); - else + } else { wci = *(WarmCallInfo::always_cold()); + } } if (!InlineWarmCalls) { if (!wci.is_cold() && !wci.is_hot()) { @@ -499,11 +557,11 @@ } if (!wci.is_cold()) { - // In -UseOldInlining, the failure_msg may also be a success message. - if (failure_msg == NULL) failure_msg = "inline (hot)"; - // Inline! - if (PrintInlining) print_inlining(callee_method, caller_bci, failure_msg); + if (msg() == NULL) { + set_msg("inline (hot)"); + } + print_inlining(callee_method, caller_bci, true /* success */); if (UseOldInlining) build_inline_tree_for_callee(callee_method, jvms, caller_bci); if (InlineWarmCalls && !wci.is_hot()) @@ -512,8 +570,10 @@ } // Do not inline - if (failure_msg == NULL) failure_msg = "too cold to inline"; - if (PrintInlining) print_inlining(callee_method, caller_bci, failure_msg); + if (msg() == NULL) { + set_msg("too cold to inline"); + } + print_inlining(callee_method, caller_bci, false /* !success */ ); return NULL; } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/c2_globals.hpp --- a/src/share/vm/opto/c2_globals.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/c2_globals.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -618,6 +618,9 @@ \ product(intx, LiveNodeCountInliningCutoff, 20000, \ "max number of live nodes in a method") \ + \ + diagnostic(bool, OptimizeExpensiveOps, true, \ + "Find best control for expensive operations") \ C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG) diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/callGenerator.cpp --- a/src/share/vm/opto/callGenerator.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/callGenerator.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -305,11 +305,13 @@ void LateInlineCallGenerator::do_late_inline() { // Can't inline it if (call_node() == NULL || call_node()->outcnt() == 0 || - call_node()->in(0) == NULL || call_node()->in(0)->is_top()) + call_node()->in(0) == NULL || call_node()->in(0)->is_top()) { return; + } + const TypeTuple *r = call_node()->tf()->domain(); for (int i1 = 0; i1 < method()->arg_size(); i1++) { - if (call_node()->in(TypeFunc::Parms + i1)->is_top()) { + if (call_node()->in(TypeFunc::Parms + i1)->is_top() && r->field_at(TypeFunc::Parms + i1) != Type::HALF) { assert(Compile::current()->inlining_incrementally(), "shouldn't happen during parsing"); return; } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/compile.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -409,6 +409,13 @@ remove_macro_node(n); } } + // Remove useless expensive node + for (int i = C->expensive_count()-1; i >= 0; i--) { + Node* n = C->expensive_node(i); + if (!useful.member(n)) { + remove_expensive_node(n); + } + } // clean up the late inline lists remove_useless_late_inlines(&_string_late_inlines, useful); remove_useless_late_inlines(&_late_inlines, useful); @@ -1061,6 +1068,7 @@ _intrinsics = NULL; _macro_nodes = new(comp_arena()) GrowableArray(comp_arena(), 8, 0, NULL); _predicate_opaqs = new(comp_arena()) GrowableArray(comp_arena(), 8, 0, NULL); + _expensive_nodes = new(comp_arena()) GrowableArray(comp_arena(), 8, 0, NULL); register_library_intrinsics(); } @@ -1927,6 +1935,10 @@ if (failing()) return; + // No more new expensive nodes will be added to the list from here + // so keep only the actual candidates for optimizations. + cleanup_expensive_nodes(igvn); + // Perform escape analysis if (_do_escape_analysis && ConnectionGraph::has_candidates(this)) { if (has_loops()) { @@ -3010,6 +3022,15 @@ return true; } + // Expensive nodes have their control input set to prevent the GVN + // from freely commoning them. There's no GVN beyond this point so + // no need to keep the control input. We want the expensive nodes to + // be freely moved to the least frequent code path by gcm. + assert(OptimizeExpensiveOps || expensive_count() == 0, "optimization off but list non empty?"); + for (int i = 0; i < expensive_count(); i++) { + _expensive_nodes->at(i)->set_req(0, NULL); + } + Final_Reshape_Counts frc; // Visit everybody reachable! @@ -3525,3 +3546,126 @@ } } } + +int Compile::cmp_expensive_nodes(Node* n1, Node* n2) { + if (n1->Opcode() < n2->Opcode()) return -1; + else if (n1->Opcode() > n2->Opcode()) return 1; + + assert(n1->req() == n2->req(), err_msg_res("can't compare %s nodes: n1->req() = %d, n2->req() = %d", NodeClassNames[n1->Opcode()], n1->req(), n2->req())); + for (uint i = 1; i < n1->req(); i++) { + if (n1->in(i) < n2->in(i)) return -1; + else if (n1->in(i) > n2->in(i)) return 1; + } + + return 0; +} + +int Compile::cmp_expensive_nodes(Node** n1p, Node** n2p) { + Node* n1 = *n1p; + Node* n2 = *n2p; + + return cmp_expensive_nodes(n1, n2); +} + +void Compile::sort_expensive_nodes() { + if (!expensive_nodes_sorted()) { + _expensive_nodes->sort(cmp_expensive_nodes); + } +} + +bool Compile::expensive_nodes_sorted() const { + for (int i = 1; i < _expensive_nodes->length(); i++) { + if (cmp_expensive_nodes(_expensive_nodes->adr_at(i), _expensive_nodes->adr_at(i-1)) < 0) { + return false; + } + } + return true; +} + +bool Compile::should_optimize_expensive_nodes(PhaseIterGVN &igvn) { + if (_expensive_nodes->length() == 0) { + return false; + } + + assert(OptimizeExpensiveOps, "optimization off?"); + + // Take this opportunity to remove dead nodes from the list + int j = 0; + for (int i = 0; i < _expensive_nodes->length(); i++) { + Node* n = _expensive_nodes->at(i); + if (!n->is_unreachable(igvn)) { + assert(n->is_expensive(), "should be expensive"); + _expensive_nodes->at_put(j, n); + j++; + } + } + _expensive_nodes->trunc_to(j); + + // Then sort the list so that similar nodes are next to each other + // and check for at least two nodes of identical kind with same data + // inputs. + sort_expensive_nodes(); + + for (int i = 0; i < _expensive_nodes->length()-1; i++) { + if (cmp_expensive_nodes(_expensive_nodes->adr_at(i), _expensive_nodes->adr_at(i+1)) == 0) { + return true; + } + } + + return false; +} + +void Compile::cleanup_expensive_nodes(PhaseIterGVN &igvn) { + if (_expensive_nodes->length() == 0) { + return; + } + + assert(OptimizeExpensiveOps, "optimization off?"); + + // Sort to bring similar nodes next to each other and clear the + // control input of nodes for which there's only a single copy. + sort_expensive_nodes(); + + int j = 0; + int identical = 0; + int i = 0; + for (; i < _expensive_nodes->length()-1; i++) { + assert(j <= i, "can't write beyond current index"); + if (_expensive_nodes->at(i)->Opcode() == _expensive_nodes->at(i+1)->Opcode()) { + identical++; + _expensive_nodes->at_put(j++, _expensive_nodes->at(i)); + continue; + } + if (identical > 0) { + _expensive_nodes->at_put(j++, _expensive_nodes->at(i)); + identical = 0; + } else { + Node* n = _expensive_nodes->at(i); + igvn.hash_delete(n); + n->set_req(0, NULL); + igvn.hash_insert(n); + } + } + if (identical > 0) { + _expensive_nodes->at_put(j++, _expensive_nodes->at(i)); + } else if (_expensive_nodes->length() >= 1) { + Node* n = _expensive_nodes->at(i); + igvn.hash_delete(n); + n->set_req(0, NULL); + igvn.hash_insert(n); + } + _expensive_nodes->trunc_to(j); +} + +void Compile::add_expensive_node(Node * n) { + assert(!_expensive_nodes->contains(n), "duplicate entry in expensive list"); + assert(n->is_expensive(), "expensive nodes with non-null control here only"); + assert(!n->is_CFG() && !n->is_Mem(), "no cfg or memory nodes here"); + if (OptimizeExpensiveOps) { + _expensive_nodes->append(n); + } else { + // Clear control input and let IGVN optimize expensive nodes if + // OptimizeExpensiveOps is off. + n->set_req(0, NULL); + } +} diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/compile.hpp --- a/src/share/vm/opto/compile.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/compile.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -314,6 +314,7 @@ GrowableArray* _intrinsics; // List of intrinsics. GrowableArray* _macro_nodes; // List of nodes which need to be expanded before matching. GrowableArray* _predicate_opaqs; // List of Opaque1 nodes for the loop predicates. + GrowableArray* _expensive_nodes; // List of nodes that are expensive to compute and that we'd better not let the GVN freely common ConnectionGraph* _congraph; #ifndef PRODUCT IdealGraphPrinter* _printer; @@ -398,6 +399,13 @@ GrowableArray* _print_inlining_list; int _print_inlining; + // Only keep nodes in the expensive node list that need to be optimized + void cleanup_expensive_nodes(PhaseIterGVN &igvn); + // Use for sorting expensive nodes to bring similar nodes together + static int cmp_expensive_nodes(Node** n1, Node** n2); + // Expensive nodes list already sorted? + bool expensive_nodes_sorted() const; + public: outputStream* print_inlining_stream() const { @@ -573,8 +581,10 @@ int macro_count() { return _macro_nodes->length(); } int predicate_count() { return _predicate_opaqs->length();} + int expensive_count() { return _expensive_nodes->length(); } Node* macro_node(int idx) { return _macro_nodes->at(idx); } Node* predicate_opaque1_node(int idx) { return _predicate_opaqs->at(idx);} + Node* expensive_node(int idx) { return _expensive_nodes->at(idx); } ConnectionGraph* congraph() { return _congraph;} void set_congraph(ConnectionGraph* congraph) { _congraph = congraph;} void add_macro_node(Node * n) { @@ -592,6 +602,12 @@ _predicate_opaqs->remove(n); } } + void add_expensive_node(Node * n); + void remove_expensive_node(Node * n) { + if (_expensive_nodes->contains(n)) { + _expensive_nodes->remove(n); + } + } void add_predicate_opaq(Node * n) { assert(!_predicate_opaqs->contains(n), " duplicate entry in predicate opaque1"); assert(_macro_nodes->contains(n), "should have already been in macro list"); @@ -604,6 +620,13 @@ return _predicate_opaqs->contains(n); } + // Are there candidate expensive nodes for optimization? + bool should_optimize_expensive_nodes(PhaseIterGVN &igvn); + // Check whether n1 and n2 are similar + static int cmp_expensive_nodes(Node* n1, Node* n2); + // Sort expensive nodes to locate similar expensive nodes + void sort_expensive_nodes(); + // Compilation environment. Arena* comp_arena() { return &_comp_arena; } ciEnv* env() const { return _env; } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/generateOptoStub.cpp --- a/src/share/vm/opto/generateOptoStub.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/generateOptoStub.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -88,12 +88,12 @@ thread, in_bytes(JavaThread::frame_anchor_offset()) + in_bytes(JavaFrameAnchor::last_Java_pc_offset())); -#if defined(SPARC) || defined(IA64) +#if defined(SPARC) Node* adr_flags = basic_plus_adr(top(), thread, in_bytes(JavaThread::frame_anchor_offset()) + in_bytes(JavaFrameAnchor::flags_offset())); -#endif /* defined(SPARC) || defined(IA64) */ +#endif /* defined(SPARC) */ // Drop in the last_Java_sp. last_Java_fp is not touched. @@ -102,10 +102,8 @@ // users will look at the other fields. // Node *adr_sp = basic_plus_adr(top(), thread, in_bytes(JavaThread::last_Java_sp_offset())); -#ifndef IA64 Node *last_sp = basic_plus_adr(top(), frameptr(), (intptr_t) STACK_BIAS); store_to_memory(NULL, adr_sp, last_sp, T_ADDRESS, NoAlias); -#endif // Set _thread_in_native // The order of stores into TLS is critical! Setting _thread_in_native MUST @@ -210,19 +208,12 @@ //----------------------------- // Clear last_Java_sp -#ifdef IA64 - if( os::is_MP() ) insert_mem_bar(Op_MemBarRelease); -#endif - store_to_memory(NULL, adr_sp, null(), T_ADDRESS, NoAlias); -#ifdef IA64 - if (os::is_MP() && UseMembar) insert_mem_bar(new MemBarVolatileNode()); -#endif // def IA64 // Clear last_Java_pc and (optionally)_flags store_to_memory(NULL, adr_last_Java_pc, null(), T_ADDRESS, NoAlias); -#if defined(SPARC) || defined(IA64) +#if defined(SPARC) store_to_memory(NULL, adr_flags, intcon(0), T_INT, NoAlias); -#endif /* defined(SPARC) || defined(IA64) */ +#endif /* defined(SPARC) */ #ifdef IA64 Node* adr_last_Java_fp = basic_plus_adr(top(), thread, in_bytes(JavaThread::last_Java_fp_offset())); if( os::is_MP() ) insert_mem_bar(Op_MemBarRelease); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/library_call.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1481,10 +1481,10 @@ Node* arg = round_double_node(argument(0)); Node* n; switch (id) { - case vmIntrinsics::_dabs: n = new (C) AbsDNode( arg); break; - case vmIntrinsics::_dsqrt: n = new (C) SqrtDNode(0, arg); break; - case vmIntrinsics::_dlog: n = new (C) LogDNode( arg); break; - case vmIntrinsics::_dlog10: n = new (C) Log10DNode( arg); break; + case vmIntrinsics::_dabs: n = new (C) AbsDNode( arg); break; + case vmIntrinsics::_dsqrt: n = new (C) SqrtDNode(C, control(), arg); break; + case vmIntrinsics::_dlog: n = new (C) LogDNode(C, control(), arg); break; + case vmIntrinsics::_dlog10: n = new (C) Log10DNode(C, control(), arg); break; default: fatal_unexpected_iid(id); break; } set_result(_gvn.transform(n)); @@ -1499,9 +1499,9 @@ Node* n = NULL; switch (id) { - case vmIntrinsics::_dsin: n = new (C) SinDNode(arg); break; - case vmIntrinsics::_dcos: n = new (C) CosDNode(arg); break; - case vmIntrinsics::_dtan: n = new (C) TanDNode(arg); break; + case vmIntrinsics::_dsin: n = new (C) SinDNode(C, control(), arg); break; + case vmIntrinsics::_dcos: n = new (C) CosDNode(C, control(), arg); break; + case vmIntrinsics::_dtan: n = new (C) TanDNode(C, control(), arg); break; default: fatal_unexpected_iid(id); break; } n = _gvn.transform(n); @@ -1653,7 +1653,7 @@ // really odd corner cases (+/- Infinity). Just uncommon-trap them. bool LibraryCallKit::inline_exp() { Node* arg = round_double_node(argument(0)); - Node* n = _gvn.transform(new (C) ExpDNode(0, arg)); + Node* n = _gvn.transform(new (C) ExpDNode(C, control(), arg)); finish_pow_exp(n, arg, NULL, OptoRuntime::Math_D_D_Type(), CAST_FROM_FN_PTR(address, SharedRuntime::dexp), "EXP"); @@ -1688,7 +1688,7 @@ if (!too_many_traps(Deoptimization::Reason_intrinsic)) { // Short form: skip the fancy tests and just check for NaN result. - result = _gvn.transform(new (C) PowDNode(0, x, y)); + result = _gvn.transform(new (C) PowDNode(C, control(), x, y)); } else { // If this inlining ever returned NaN in the past, include all // checks + call to the runtime. @@ -1715,7 +1715,7 @@ Node *complex_path = _gvn.transform( new (C) IfTrueNode(if1) ); // Set fast path result - Node *fast_result = _gvn.transform( new (C) PowDNode(0, x, y) ); + Node *fast_result = _gvn.transform( new (C) PowDNode(C, control(), x, y) ); phi->init_req(3, fast_result); // Complex path @@ -1775,7 +1775,7 @@ // abs(x) Node *absx=_gvn.transform( new (C) AbsDNode(x)); // abs(x)^y - Node *absxpowy = _gvn.transform( new (C) PowDNode(0, absx, y) ); + Node *absxpowy = _gvn.transform( new (C) PowDNode(C, control(), absx, y) ); // -abs(x)^y Node *negabsxpowy = _gvn.transform(new (C) NegDNode (absxpowy)); // (1&(long)y)==1?-DPow(abs(x), y):DPow(abs(x), y) diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/loopnode.cpp --- a/src/share/vm/opto/loopnode.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/loopnode.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -88,9 +88,9 @@ assert( !n->is_Phi() && !n->is_CFG(), "this code only handles data nodes" ); uint i; Node *early; - if( n->in(0) ) { + if (n->in(0) && !n->is_expensive()) { early = n->in(0); - if( !early->is_CFG() ) // Might be a non-CFG multi-def + if (!early->is_CFG()) // Might be a non-CFG multi-def early = get_ctrl(early); // So treat input as a straight data input i = 1; } else { @@ -99,28 +99,28 @@ } uint e_d = dom_depth(early); assert( early, "" ); - for( ; i < n->req(); i++ ) { + for (; i < n->req(); i++) { Node *cin = get_ctrl(n->in(i)); assert( cin, "" ); // Keep deepest dominator depth uint c_d = dom_depth(cin); - if( c_d > e_d ) { // Deeper guy? + if (c_d > e_d) { // Deeper guy? early = cin; // Keep deepest found so far e_d = c_d; - } else if( c_d == e_d && // Same depth? - early != cin ) { // If not equal, must use slower algorithm + } else if (c_d == e_d && // Same depth? + early != cin) { // If not equal, must use slower algorithm // If same depth but not equal, one _must_ dominate the other // and we want the deeper (i.e., dominated) guy. Node *n1 = early; Node *n2 = cin; - while( 1 ) { + while (1) { n1 = idom(n1); // Walk up until break cycle n2 = idom(n2); - if( n1 == cin || // Walked early up to cin - dom_depth(n2) < c_d ) + if (n1 == cin || // Walked early up to cin + dom_depth(n2) < c_d) break; // early is deeper; keep him - if( n2 == early || // Walked cin up to early - dom_depth(n1) < c_d ) { + if (n2 == early || // Walked cin up to early + dom_depth(n1) < c_d) { early = cin; // cin is deeper; keep him break; } @@ -132,9 +132,108 @@ // Return earliest legal location assert(early == find_non_split_ctrl(early), "unexpected early control"); + if (n->is_expensive()) { + assert(n->in(0), "should have control input"); + early = get_early_ctrl_for_expensive(n, early); + } + return early; } +//------------------------------get_early_ctrl_for_expensive--------------------------------- +// Move node up the dominator tree as high as legal while still beneficial +Node *PhaseIdealLoop::get_early_ctrl_for_expensive(Node *n, Node* earliest) { + assert(n->in(0) && n->is_expensive(), "expensive node with control input here"); + assert(OptimizeExpensiveOps, "optimization off?"); + + Node* ctl = n->in(0); + assert(ctl->is_CFG(), "expensive input 0 must be cfg"); + uint min_dom_depth = dom_depth(earliest); +#ifdef ASSERT + if (!is_dominator(ctl, earliest) && !is_dominator(earliest, ctl)) { + dump_bad_graph("Bad graph detected in get_early_ctrl_for_expensive", n, earliest, ctl); + assert(false, "Bad graph detected in get_early_ctrl_for_expensive"); + } +#endif + if (dom_depth(ctl) < min_dom_depth) { + return earliest; + } + + while (1) { + Node *next = ctl; + // Moving the node out of a loop on the projection of a If + // confuses loop predication. So once we hit a Loop in a If branch + // that doesn't branch to an UNC, we stop. The code that process + // expensive nodes will notice the loop and skip over it to try to + // move the node further up. + if (ctl->is_CountedLoop() && ctl->in(1) != NULL && ctl->in(1)->in(0) != NULL && ctl->in(1)->in(0)->is_If()) { + if (!is_uncommon_trap_if_pattern(ctl->in(1)->as_Proj(), Deoptimization::Reason_none)) { + break; + } + next = idom(ctl->in(1)->in(0)); + } else if (ctl->is_Proj()) { + // We only move it up along a projection if the projection is + // the single control projection for its parent: same code path, + // if it's a If with UNC or fallthrough of a call. + Node* parent_ctl = ctl->in(0); + if (parent_ctl == NULL) { + break; + } else if (parent_ctl->is_CountedLoopEnd() && parent_ctl->as_CountedLoopEnd()->loopnode() != NULL) { + next = parent_ctl->as_CountedLoopEnd()->loopnode()->init_control(); + } else if (parent_ctl->is_If()) { + if (!is_uncommon_trap_if_pattern(ctl->as_Proj(), Deoptimization::Reason_none)) { + break; + } + assert(idom(ctl) == parent_ctl, "strange"); + next = idom(parent_ctl); + } else if (ctl->is_CatchProj()) { + if (ctl->as_Proj()->_con != CatchProjNode::fall_through_index) { + break; + } + assert(parent_ctl->in(0)->in(0)->is_Call(), "strange graph"); + next = parent_ctl->in(0)->in(0)->in(0); + } else { + // Check if parent control has a single projection (this + // control is the only possible successor of the parent + // control). If so, we can try to move the node above the + // parent control. + int nb_ctl_proj = 0; + for (DUIterator_Fast imax, i = parent_ctl->fast_outs(imax); i < imax; i++) { + Node *p = parent_ctl->fast_out(i); + if (p->is_Proj() && p->is_CFG()) { + nb_ctl_proj++; + if (nb_ctl_proj > 1) { + break; + } + } + } + + if (nb_ctl_proj > 1) { + break; + } + assert(parent_ctl->is_Start() || parent_ctl->is_MemBar() || parent_ctl->is_Call(), "unexpected node"); + assert(idom(ctl) == parent_ctl, "strange"); + next = idom(parent_ctl); + } + } else { + next = idom(ctl); + } + if (next->is_Root() || next->is_Start() || dom_depth(next) < min_dom_depth) { + break; + } + ctl = next; + } + + if (ctl != n->in(0)) { + _igvn.hash_delete(n); + n->set_req(0, ctl); + _igvn.hash_insert(n); + } + + return ctl; +} + + //------------------------------set_early_ctrl--------------------------------- // Set earliest legal control void PhaseIdealLoop::set_early_ctrl( Node *n ) { @@ -1892,6 +1991,98 @@ } } +//------------------------process_expensive_nodes----------------------------- +// Expensive nodes have their control input set to prevent the GVN +// from commoning them and as a result forcing the resulting node to +// be in a more frequent path. Use CFG information here, to change the +// control inputs so that some expensive nodes can be commoned while +// not executed more frequently. +bool PhaseIdealLoop::process_expensive_nodes() { + assert(OptimizeExpensiveOps, "optimization off?"); + + // Sort nodes to bring similar nodes together + C->sort_expensive_nodes(); + + bool progress = false; + + for (int i = 0; i < C->expensive_count(); ) { + Node* n = C->expensive_node(i); + int start = i; + // Find nodes similar to n + i++; + for (; i < C->expensive_count() && Compile::cmp_expensive_nodes(n, C->expensive_node(i)) == 0; i++); + int end = i; + // And compare them two by two + for (int j = start; j < end; j++) { + Node* n1 = C->expensive_node(j); + if (is_node_unreachable(n1)) { + continue; + } + for (int k = j+1; k < end; k++) { + Node* n2 = C->expensive_node(k); + if (is_node_unreachable(n2)) { + continue; + } + + assert(n1 != n2, "should be pair of nodes"); + + Node* c1 = n1->in(0); + Node* c2 = n2->in(0); + + Node* parent_c1 = c1; + Node* parent_c2 = c2; + + // The call to get_early_ctrl_for_expensive() moves the + // expensive nodes up but stops at loops that are in a if + // branch. See whether we can exit the loop and move above the + // If. + if (c1->is_Loop()) { + parent_c1 = c1->in(1); + } + if (c2->is_Loop()) { + parent_c2 = c2->in(1); + } + + if (parent_c1 == parent_c2) { + _igvn._worklist.push(n1); + _igvn._worklist.push(n2); + continue; + } + + // Look for identical expensive node up the dominator chain. + if (is_dominator(c1, c2)) { + c2 = c1; + } else if (is_dominator(c2, c1)) { + c1 = c2; + } else if (parent_c1->is_Proj() && parent_c1->in(0)->is_If() && + parent_c2->is_Proj() && parent_c1->in(0) == parent_c2->in(0)) { + // Both branches have the same expensive node so move it up + // before the if. + c1 = c2 = idom(parent_c1->in(0)); + } + // Do the actual moves + if (n1->in(0) != c1) { + _igvn.hash_delete(n1); + n1->set_req(0, c1); + _igvn.hash_insert(n1); + _igvn._worklist.push(n1); + progress = true; + } + if (n2->in(0) != c2) { + _igvn.hash_delete(n2); + n2->set_req(0, c2); + _igvn.hash_insert(n2); + _igvn._worklist.push(n2); + progress = true; + } + } + } + } + + return progress; +} + + //============================================================================= //----------------------------build_and_optimize------------------------------- // Create a PhaseLoop. Build the ideal Loop tree. Map each Ideal Node to @@ -1960,7 +2151,9 @@ } // Nothing to do, so get out - if( !C->has_loops() && !skip_loop_opts && !do_split_ifs && !_verify_me && !_verify_only ) { + bool stop_early = !C->has_loops() && !skip_loop_opts && !do_split_ifs && !_verify_me && !_verify_only; + bool do_expensive_nodes = C->should_optimize_expensive_nodes(_igvn); + if (stop_early && !do_expensive_nodes) { _igvn.optimize(); // Cleanup NeverBranches return; } @@ -2058,6 +2251,21 @@ return; } + if (stop_early) { + assert(do_expensive_nodes, "why are we here?"); + if (process_expensive_nodes()) { + // If we made some progress when processing expensive nodes then + // the IGVN may modify the graph in a way that will allow us to + // make some more progress: we need to try processing expensive + // nodes again. + C->set_major_progress(); + } + + _igvn.optimize(); + + return; + } + // Some parser-inserted loop predicates could never be used by loop // predication or they were moved away from loop during some optimizations. // For example, peeling. Eliminate them before next loop optimizations. @@ -2120,6 +2328,10 @@ NOT_PRODUCT( if( VerifyLoopOptimizations ) verify(); ); } + if (!C->major_progress() && do_expensive_nodes && process_expensive_nodes()) { + C->set_major_progress(); + } + // Perform loop predication before iteration splitting if (C->has_loops() && !C->major_progress() && (C->predicate_count() > 0)) { _ltree_root->_child->loop_predication(this); @@ -3299,7 +3511,7 @@ #ifdef ASSERT if (legal->is_Start() && !early->is_Root()) { // Bad graph. Print idom path and fail. - dump_bad_graph(n, early, LCA); + dump_bad_graph("Bad graph detected in build_loop_late", n, early, LCA); assert(false, "Bad graph detected in build_loop_late"); } #endif @@ -3350,8 +3562,8 @@ } #ifdef ASSERT -void PhaseIdealLoop::dump_bad_graph(Node* n, Node* early, Node* LCA) { - tty->print_cr( "Bad graph detected in build_loop_late"); +void PhaseIdealLoop::dump_bad_graph(const char* msg, Node* n, Node* early, Node* LCA) { + tty->print_cr(msg); tty->print("n: "); n->dump(); tty->print("early(n): "); early->dump(); if (n->in(0) != NULL && !n->in(0)->is_top() && diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/loopnode.hpp --- a/src/share/vm/opto/loopnode.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/loopnode.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -263,9 +263,18 @@ bool stride_is_con() const { Node *tmp = stride (); return (tmp != NULL && tmp->is_Con()); } BoolTest::mask test_trip() const { return in(TestValue)->as_Bool()->_test._test; } CountedLoopNode *loopnode() const { + // The CountedLoopNode that goes with this CountedLoopEndNode may + // have been optimized out by the IGVN so be cautious with the + // pattern matching on the graph + if (phi() == NULL) { + return NULL; + } Node *ln = phi()->in(0); - assert( ln->Opcode() == Op_CountedLoop, "malformed loop" ); - return (CountedLoopNode*)ln; } + if (ln->is_CountedLoop() && ln->as_CountedLoop()->loopexit() == this) { + return (CountedLoopNode*)ln; + } + return NULL; + } #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; @@ -598,6 +607,7 @@ // check if transform created new nodes that need _ctrl recorded Node *get_late_ctrl( Node *n, Node *early ); Node *get_early_ctrl( Node *n ); + Node *get_early_ctrl_for_expensive(Node *n, Node* earliest); void set_early_ctrl( Node *n ); void set_subtree_ctrl( Node *root ); void set_ctrl( Node *n, Node *ctrl ) { @@ -905,6 +915,16 @@ void collect_potentially_useful_predicates(IdealLoopTree *loop, Unique_Node_List &predicate_opaque1); void eliminate_useless_predicates(); + // Change the control input of expensive nodes to allow commoning by + // IGVN when it is guaranteed to not result in a more frequent + // execution of the expensive node. Return true if progress. + bool process_expensive_nodes(); + + // Check whether node has become unreachable + bool is_node_unreachable(Node *n) const { + return !has_node(n) || n->is_unreachable(_igvn); + } + // Eliminate range-checks and other trip-counter vs loop-invariant tests. void do_range_check( IdealLoopTree *loop, Node_List &old_new ); @@ -1043,7 +1063,7 @@ void register_new_node( Node *n, Node *blk ); #ifdef ASSERT -void dump_bad_graph(Node* n, Node* early, Node* LCA); + void dump_bad_graph(const char* msg, Node* n, Node* early, Node* LCA); #endif #ifndef PRODUCT diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/memnode.cpp --- a/src/share/vm/opto/memnode.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/memnode.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -320,6 +320,9 @@ if (mem != old_mem) { set_req(MemNode::Memory, mem); + if (can_reshape && old_mem->outcnt() == 0) { + igvn->_worklist.push(old_mem); + } if (phase->type( mem ) == Type::TOP) return NodeSentinel; return this; } @@ -2319,9 +2322,9 @@ if (ReduceFieldZeroing && /*can_reshape &&*/ mem->is_Proj() && mem->in(0)->is_Initialize()) { InitializeNode* init = mem->in(0)->as_Initialize(); - intptr_t offset = init->can_capture_store(this, phase); + intptr_t offset = init->can_capture_store(this, phase, can_reshape); if (offset > 0) { - Node* moved = init->capture_store(this, offset, phase); + Node* moved = init->capture_store(this, offset, phase, can_reshape); // If the InitializeNode captured me, it made a raw copy of me, // and I need to disappear. if (moved != NULL) { @@ -3134,7 +3137,7 @@ // an initialization. Returns zero if a check fails. // On success, returns the (constant) offset to which the store applies, // within the initialized memory. -intptr_t InitializeNode::can_capture_store(StoreNode* st, PhaseTransform* phase) { +intptr_t InitializeNode::can_capture_store(StoreNode* st, PhaseTransform* phase, bool can_reshape) { const int FAIL = 0; if (st->req() != MemNode::ValueIn + 1) return FAIL; // an inscrutable StoreNode (card mark?) @@ -3156,6 +3159,91 @@ if (!detect_init_independence(val, true, complexity_count)) return FAIL; // stored value must be 'simple enough' + // The Store can be captured only if nothing after the allocation + // and before the Store is using the memory location that the store + // overwrites. + bool failed = false; + // If is_complete_with_arraycopy() is true the shape of the graph is + // well defined and is safe so no need for extra checks. + if (!is_complete_with_arraycopy()) { + // We are going to look at each use of the memory state following + // the allocation to make sure nothing reads the memory that the + // Store writes. + const TypePtr* t_adr = phase->type(adr)->isa_ptr(); + int alias_idx = phase->C->get_alias_index(t_adr); + ResourceMark rm; + Unique_Node_List mems; + mems.push(mem); + Node* unique_merge = NULL; + for (uint next = 0; next < mems.size(); ++next) { + Node *m = mems.at(next); + for (DUIterator_Fast jmax, j = m->fast_outs(jmax); j < jmax; j++) { + Node *n = m->fast_out(j); + if (n->outcnt() == 0) { + continue; + } + if (n == st) { + continue; + } else if (n->in(0) != NULL && n->in(0) != ctl) { + // If the control of this use is different from the control + // of the Store which is right after the InitializeNode then + // this node cannot be between the InitializeNode and the + // Store. + continue; + } else if (n->is_MergeMem()) { + if (n->as_MergeMem()->memory_at(alias_idx) == m) { + // We can hit a MergeMemNode (that will likely go away + // later) that is a direct use of the memory state + // following the InitializeNode on the same slice as the + // store node that we'd like to capture. We need to check + // the uses of the MergeMemNode. + mems.push(n); + } + } else if (n->is_Mem()) { + Node* other_adr = n->in(MemNode::Address); + if (other_adr == adr) { + failed = true; + break; + } else { + const TypePtr* other_t_adr = phase->type(other_adr)->isa_ptr(); + if (other_t_adr != NULL) { + int other_alias_idx = phase->C->get_alias_index(other_t_adr); + if (other_alias_idx == alias_idx) { + // A load from the same memory slice as the store right + // after the InitializeNode. We check the control of the + // object/array that is loaded from. If it's the same as + // the store control then we cannot capture the store. + assert(!n->is_Store(), "2 stores to same slice on same control?"); + Node* base = other_adr; + assert(base->is_AddP(), err_msg_res("should be addp but is %s", base->Name())); + base = base->in(AddPNode::Base); + if (base != NULL) { + base = base->uncast(); + if (base->is_Proj() && base->in(0) == alloc) { + failed = true; + break; + } + } + } + } + } + } else { + failed = true; + break; + } + } + } + } + if (failed) { + if (!can_reshape) { + // We decided we couldn't capture the store during parsing. We + // should try again during the next IGVN once the graph is + // cleaner. + phase->C->record_for_igvn(st); + } + return FAIL; + } + return offset; // success } @@ -3266,11 +3354,11 @@ // rawstore1 rawstore2) // Node* InitializeNode::capture_store(StoreNode* st, intptr_t start, - PhaseTransform* phase) { + PhaseTransform* phase, bool can_reshape) { assert(stores_are_sane(phase), ""); if (start < 0) return NULL; - assert(can_capture_store(st, phase) == start, "sanity"); + assert(can_capture_store(st, phase, can_reshape) == start, "sanity"); Compile* C = phase->C; int size_in_bytes = st->memory_size(); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/memnode.hpp --- a/src/share/vm/opto/memnode.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/memnode.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1072,11 +1072,11 @@ // See if this store can be captured; return offset where it initializes. // Return 0 if the store cannot be moved (any sort of problem). - intptr_t can_capture_store(StoreNode* st, PhaseTransform* phase); + intptr_t can_capture_store(StoreNode* st, PhaseTransform* phase, bool can_reshape); // Capture another store; reformat it to write my internal raw memory. // Return the captured copy, else NULL if there is some sort of problem. - Node* capture_store(StoreNode* st, intptr_t start, PhaseTransform* phase); + Node* capture_store(StoreNode* st, intptr_t start, PhaseTransform* phase, bool can_reshape); // Find captured store which corresponds to the range [start..start+size). // Return my own memory projection (meaning the initial zero bits) diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/node.cpp --- a/src/share/vm/opto/node.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/node.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -493,6 +493,8 @@ } if (is_macro()) compile->add_macro_node(n); + if (is_expensive()) + compile->add_expensive_node(n); n->set_idx(compile->next_unique()); // Get new unique index as well debug_only( n->verify_construction() ); @@ -616,6 +618,9 @@ if (is_macro()) { compile->remove_macro_node(this); } + if (is_expensive()) { + compile->remove_expensive_node(this); + } #ifdef ASSERT // We will not actually delete the storage, but we'll make the node unusable. *(address*)this = badAddress; // smash the C++ vtbl, probably @@ -689,6 +694,13 @@ } #endif + +//------------------------------is_unreachable--------------------------------- +bool Node::is_unreachable(PhaseIterGVN &igvn) const { + assert(!is_Mach(), "doesn't work with MachNodes"); + return outcnt() == 0 || igvn.type(this) == Type::TOP || in(0)->is_top(); +} + //------------------------------add_req---------------------------------------- // Add a new required input at the end void Node::add_req( Node *n ) { @@ -1246,6 +1258,10 @@ if (dead->is_macro()) { igvn->C->remove_macro_node(dead); } + if (dead->is_expensive()) { + igvn->C->remove_expensive_node(dead); + } + igvn->C->record_dead_node(dead->_idx); // Kill all inputs to the dead guy for (uint i=0; i < dead->req(); i++) { Node *n = dead->in(i); // Get input to dead guy diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/node.hpp --- a/src/share/vm/opto/node.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/node.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -378,6 +378,8 @@ bool is_dead() const; #define is_not_dead(n) ((n) == NULL || !VerifyIterativeGVN || !((n)->is_dead())) #endif + // Check whether node has become unreachable + bool is_unreachable(PhaseIterGVN &igvn) const; // Set a required input edge, also updates corresponding output edge void add_req( Node *n ); // Append a NEW required input @@ -646,7 +648,8 @@ Flag_may_be_short_branch = Flag_is_dead_loop_safe << 1, Flag_avoid_back_to_back = Flag_may_be_short_branch << 1, Flag_has_call = Flag_avoid_back_to_back << 1, - _max_flags = (Flag_has_call << 1) - 1 // allow flags combination + Flag_is_expensive = Flag_has_call << 1, + _max_flags = (Flag_is_expensive << 1) - 1 // allow flags combination }; private: @@ -819,6 +822,8 @@ // The node is a "macro" node which needs to be expanded before matching bool is_macro() const { return (_flags & Flag_is_macro) != 0; } + // The node is expensive: the best control is set during loop opts + bool is_expensive() const { return (_flags & Flag_is_expensive) != 0 && in(0) != NULL; } //----------------- Optimization diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/parse.hpp --- a/src/share/vm/opto/parse.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/parse.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -58,7 +58,7 @@ GrowableArray _subtrees; void print_impl(outputStream* stj, int indent) const PRODUCT_RETURN; - + const char* _msg; protected: InlineTree(Compile* C, const InlineTree* caller_tree, @@ -70,16 +70,29 @@ InlineTree *build_inline_tree_for_callee(ciMethod* callee_method, JVMState* caller_jvms, int caller_bci); - const char* try_to_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result, bool& should_delay); - const char* should_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const; - const char* should_not_inline(ciMethod* callee_method, ciMethod* caller_method, WarmCallInfo* wci_result) const; - void print_inlining(ciMethod *callee_method, int caller_bci, const char *failure_msg) const; + bool try_to_inline(ciMethod* callee_method, + ciMethod* caller_method, + int caller_bci, + ciCallProfile& profile, + WarmCallInfo* wci_result, + bool& should_delay); + bool should_inline(ciMethod* callee_method, + ciMethod* caller_method, + int caller_bci, + ciCallProfile& profile, + WarmCallInfo* wci_result); + bool should_not_inline(ciMethod* callee_method, + ciMethod* caller_method, + WarmCallInfo* wci_result); + void print_inlining(ciMethod* callee_method, int caller_bci, + bool success) const; - InlineTree *caller_tree() const { return _caller_tree; } + InlineTree* caller_tree() const { return _caller_tree; } InlineTree* callee_at(int bci, ciMethod* m) const; int inline_level() const { return stack_depth(); } int stack_depth() const { return _caller_jvms ? _caller_jvms->depth() : 0; } - + const char* msg() const { return _msg; } + void set_msg(const char* msg) { _msg = msg; } public: static const char* check_can_parse(ciMethod* callee); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/parse3.cpp --- a/src/share/vm/opto/parse3.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/parse3.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -487,7 +487,8 @@ fun, NULL, TypeRawPtr::BOTTOM, makecon(TypeKlassPtr::make(array_klass)), length[0], length[1], length[2], - length[3], length[4]); + (ndimensions > 2) ? length[3] : NULL, + (ndimensions > 3) ? length[4] : NULL); } else { // Create a java array for dimension sizes Node* dims = NULL; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/phaseX.cpp --- a/src/share/vm/opto/phaseX.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/phaseX.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1197,12 +1197,27 @@ assert(!(i < imax), "sanity"); } } + if (ReduceFieldZeroing && dead->is_Load() && i == MemNode::Memory && + in->is_Proj() && in->in(0) != NULL && in->in(0)->is_Initialize()) { + // A Load that directly follows an InitializeNode is + // going away. The Stores that follow are candidates + // again to be captured by the InitializeNode. + for (DUIterator_Fast jmax, j = in->fast_outs(jmax); j < jmax; j++) { + Node *n = in->fast_out(j); + if (n->is_Store()) { + _worklist.push(n); + } + } + } } } 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 (recurse) { continue; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/regmask.cpp --- a/src/share/vm/opto/regmask.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/regmask.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -241,7 +241,8 @@ } else { // Else its a split-pair case if( bit != _A[i] ) return false; // Found many bits, so fail i++; // Skip iteration forward - if( _A[i] != 1 ) return false; // Require 1 lo bit in next word + if( i >= RM_SIZE || _A[i] != 1 ) + return false; // Require 1 lo bit in next word } } } @@ -254,7 +255,7 @@ // Find the lowest-numbered register set in the mask. Return the // HIGHEST register number in the set, or BAD if no sets. // Works also for size 1. -OptoReg::Name RegMask::find_first_set(int size) const { +OptoReg::Name RegMask::find_first_set(const int size) const { verify_sets(size); for (int i = 0; i < RM_SIZE; i++) { if (_A[i]) { // Found some bits @@ -268,7 +269,7 @@ //------------------------------clear_to_sets---------------------------------- // Clear out partial bits; leave only aligned adjacent bit pairs -void RegMask::clear_to_sets(int size) { +void RegMask::clear_to_sets(const int size) { if (size == 1) return; assert(2 <= size && size <= 8, "update low bits table"); assert(is_power_of_2(size), "sanity"); @@ -293,7 +294,7 @@ //------------------------------smear_to_sets---------------------------------- // Smear out partial bits to aligned adjacent bit sets -void RegMask::smear_to_sets(int size) { +void RegMask::smear_to_sets(const int size) { if (size == 1) return; assert(2 <= size && size <= 8, "update low bits table"); assert(is_power_of_2(size), "sanity"); @@ -318,7 +319,7 @@ } //------------------------------is_aligned_set-------------------------------- -bool RegMask::is_aligned_sets(int size) const { +bool RegMask::is_aligned_sets(const int size) const { if (size == 1) return true; assert(2 <= size && size <= 8, "update low bits table"); assert(is_power_of_2(size), "sanity"); @@ -344,7 +345,7 @@ //------------------------------is_bound_set----------------------------------- // Return TRUE if the mask contains one adjacent set of bits and no other bits. // Works also for size 1. -int RegMask::is_bound_set(int size) const { +int RegMask::is_bound_set(const int size) const { if( is_AllStack() ) return false; assert(1 <= size && size <= 8, "update low bits table"); int bit = -1; // Set to hold the one bit allowed @@ -352,7 +353,7 @@ if (_A[i] ) { // Found some bits if (bit != -1) return false; // Already had bits, so fail - bit = _A[i] & -_A[i]; // Extract 1 bit from mask + bit = _A[i] & -_A[i]; // Extract low bit from mask int hi_bit = bit << (size-1); // high bit if (hi_bit != 0) { // Bit set stays in same word? int set = hi_bit + ((hi_bit-1) & ~(bit-1)); @@ -362,12 +363,12 @@ if (((-1) & ~(bit-1)) != _A[i]) return false; // Found many bits, so fail i++; // Skip iteration forward and check high part - assert(size <= 8, "update next code"); // The lower 24 bits should be 0 since it is split case and size <= 8. int set = bit>>24; set = set & -set; // Remove sign extension. set = (((set << size) - 1) >> 8); - if (_A[i] != set) return false; // Require 1 lo bit in next word + if (i >= RM_SIZE || _A[i] != set) + return false; // Require expected low bits in next word } } } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/regmask.hpp --- a/src/share/vm/opto/regmask.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/regmask.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -225,22 +225,22 @@ // Find the lowest-numbered register set in the mask. Return the // HIGHEST register number in the set, or BAD if no sets. // Assert that the mask contains only bit sets. - OptoReg::Name find_first_set(int size) const; + OptoReg::Name find_first_set(const int size) const; // Clear out partial bits; leave only aligned adjacent bit sets of size. - void clear_to_sets(int size); + void clear_to_sets(const int size); // Smear out partial bits to aligned adjacent bit sets. - void smear_to_sets(int size); + void smear_to_sets(const int size); // Verify that the mask contains only aligned adjacent bit sets void verify_sets(int size) const { assert(is_aligned_sets(size), "mask is not aligned, adjacent sets"); } // Test that the mask contains only aligned adjacent bit sets - bool is_aligned_sets(int size) const; + bool is_aligned_sets(const int size) const; // mask is a set of misaligned registers bool is_misaligned_set(int size) const { return (int)Size()==size && !is_aligned_sets(size);} // Test for a single adjacent set - int is_bound_set(int size) const; + int is_bound_set(const int size) const; static bool is_vector(uint ireg); static int num_registers(uint ireg); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/subnode.hpp --- a/src/share/vm/opto/subnode.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/subnode.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -399,7 +399,10 @@ // Cosinus of a double class CosDNode : public Node { public: - CosDNode( Node *in1 ) : Node(0, in1) {} + CosDNode(Compile* C, Node *c, Node *in1) : Node(c, in1) { + init_flags(Flag_is_expensive); + C->add_expensive_node(this); + } virtual int Opcode() const; const Type *bottom_type() const { return Type::DOUBLE; } virtual uint ideal_reg() const { return Op_RegD; } @@ -410,7 +413,10 @@ // Sinus of a double class SinDNode : public Node { public: - SinDNode( Node *in1 ) : Node(0, in1) {} + SinDNode(Compile* C, Node *c, Node *in1) : Node(c, in1) { + init_flags(Flag_is_expensive); + C->add_expensive_node(this); + } virtual int Opcode() const; const Type *bottom_type() const { return Type::DOUBLE; } virtual uint ideal_reg() const { return Op_RegD; } @@ -422,7 +428,10 @@ // tangens of a double class TanDNode : public Node { public: - TanDNode(Node *in1 ) : Node(0, in1) {} + TanDNode(Compile* C, Node *c,Node *in1) : Node(c, in1) { + init_flags(Flag_is_expensive); + C->add_expensive_node(this); + } virtual int Opcode() const; const Type *bottom_type() const { return Type::DOUBLE; } virtual uint ideal_reg() const { return Op_RegD; } @@ -445,7 +454,10 @@ // square root a double class SqrtDNode : public Node { public: - SqrtDNode(Node *c, Node *in1 ) : Node(c, in1) {} + SqrtDNode(Compile* C, Node *c, Node *in1) : Node(c, in1) { + init_flags(Flag_is_expensive); + C->add_expensive_node(this); + } virtual int Opcode() const; const Type *bottom_type() const { return Type::DOUBLE; } virtual uint ideal_reg() const { return Op_RegD; } @@ -456,7 +468,10 @@ // Exponentiate a double class ExpDNode : public Node { public: - ExpDNode( Node *c, Node *in1 ) : Node(c, in1) {} + ExpDNode(Compile* C, Node *c, Node *in1) : Node(c, in1) { + init_flags(Flag_is_expensive); + C->add_expensive_node(this); + } virtual int Opcode() const; const Type *bottom_type() const { return Type::DOUBLE; } virtual uint ideal_reg() const { return Op_RegD; } @@ -467,7 +482,10 @@ // Log_e of a double class LogDNode : public Node { public: - LogDNode( Node *in1 ) : Node(0, in1) {} + LogDNode(Compile* C, Node *c, Node *in1) : Node(c, in1) { + init_flags(Flag_is_expensive); + C->add_expensive_node(this); + } virtual int Opcode() const; const Type *bottom_type() const { return Type::DOUBLE; } virtual uint ideal_reg() const { return Op_RegD; } @@ -478,7 +496,10 @@ // Log_10 of a double class Log10DNode : public Node { public: - Log10DNode( Node *in1 ) : Node(0, in1) {} + Log10DNode(Compile* C, Node *c, Node *in1) : Node(c, in1) { + init_flags(Flag_is_expensive); + C->add_expensive_node(this); + } virtual int Opcode() const; const Type *bottom_type() const { return Type::DOUBLE; } virtual uint ideal_reg() const { return Op_RegD; } @@ -489,7 +510,10 @@ // Raise a double to a double power class PowDNode : public Node { public: - PowDNode(Node *c, Node *in1, Node *in2 ) : Node(c, in1, in2) {} + PowDNode(Compile* C, Node *c, Node *in1, Node *in2 ) : Node(c, in1, in2) { + init_flags(Flag_is_expensive); + C->add_expensive_node(this); + } virtual int Opcode() const; const Type *bottom_type() const { return Type::DOUBLE; } virtual uint ideal_reg() const { return Op_RegD; } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/superword.cpp --- a/src/share/vm/opto/superword.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/superword.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -143,7 +143,8 @@ // Ready the block - construct_bb(); + if (!construct_bb()) + return; // Exit if no interesting nodes or complex graph. dependence_graph(); @@ -615,6 +616,7 @@ if (n == stop) break; preds.push(n); prev = n; + assert(n->is_Mem(), err_msg_res("unexpected node %s", n->Name())); n = n->in(MemNode::Memory); } } @@ -1578,7 +1580,7 @@ //------------------------------construct_bb--------------------------- // Construct reverse postorder list of block members -void SuperWord::construct_bb() { +bool SuperWord::construct_bb() { Node* entry = bb(); assert(_stk.length() == 0, "stk is empty"); @@ -1596,6 +1598,12 @@ Node *n = lpt()->_body.at(i); set_bb_idx(n, i); // Create a temporary map if (in_bb(n)) { + if (n->is_LoadStore() || n->is_MergeMem() || + (n->is_Proj() && !n->as_Proj()->is_CFG())) { + // Bailout if the loop has LoadStore, MergeMem or data Proj + // nodes. Superword optimization does not work with them. + return false; + } bb_ct++; if (!n->is_CFG()) { bool found = false; @@ -1620,6 +1628,10 @@ if (in_bb(n) && (n->is_Phi() && n->bottom_type() == Type::MEMORY)) { Node* n_tail = n->in(LoopNode::LoopBackControl); if (n_tail != n->in(LoopNode::EntryControl)) { + if (!n_tail->is_Mem()) { + assert(n_tail->is_Mem(), err_msg_res("unexpected node for memory slice: %s", n_tail->Name())); + return false; // Bailout + } _mem_slice_head.push(n); _mem_slice_tail.push(n_tail); } @@ -1695,6 +1707,7 @@ } #endif assert(rpo_idx == -1 && bb_ct == _block.length(), "all block members found"); + return (_mem_slice_head.length() > 0) || (_data_entry.length() > 0); } //------------------------------initialize_bb--------------------------- diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/opto/superword.hpp --- a/src/share/vm/opto/superword.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/opto/superword.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -380,7 +380,7 @@ // Is use->in(u_idx) a vector use? bool is_vector_use(Node* use, int u_idx); // Construct reverse postorder list of block members - void construct_bb(); + bool construct_bb(); // Initialize per node info void initialize_bb(); // Insert n into block after pos diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/precompiled/precompiled.hpp --- a/src/share/vm/precompiled/precompiled.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/precompiled/precompiled.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -24,6 +24,7 @@ // Precompiled headers are turned off for Sun Studion, // or if the user passes USE_PRECOMPILED_HEADER=0 to the makefiles. + #ifndef DONT_USE_PRECOMPILED_HEADER # include "asm/assembler.hpp" @@ -288,7 +289,7 @@ #ifdef GRAAL # include "graal/graalGlobals.hpp" #endif // GRAAL -#ifndef SERIALGC +#if INCLUDE_ALL_GCS # include "gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp" # include "gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp" # include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp" @@ -317,6 +318,6 @@ # include "gc_implementation/shared/gcAdaptivePolicyCounters.hpp" # include "gc_implementation/shared/gcPolicyCounters.hpp" # include "gc_implementation/shared/parGCAllocBuffer.hpp" -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #endif // !DONT_USE_PRECOMPILED_HEADER diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jni.cpp --- a/src/share/vm/prims/jni.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jni.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -32,12 +32,13 @@ #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "interpreter/linkResolver.hpp" +#include "utilities/macros.hpp" #ifdef GRAAL #include "graal/graalCompiler.hpp" #endif -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/gcLocker.inline.hpp" @@ -1318,7 +1319,6 @@ } -static bool first_time_InvokeMain = true; static void jni_invoke_static(JNIEnv *env, JavaValue* result, jobject receiver, JNICallType call_type, jmethodID method_id, JNI_ArgumentPusher *args, TRAPS) { methodHandle method(THREAD, Method::resolve_jmethod_id(method_id)); @@ -1327,8 +1327,6 @@ // the jni parser ResourceMark rm(THREAD); int number_of_parameters = method->size_of_parameters(); - - // Invoke the method. Result is returned as oop. JavaCallArguments java_args(number_of_parameters); args->set_java_argument_object(&java_args); @@ -1336,23 +1334,16 @@ // Fill out JavaCallArguments object args->iterate( Fingerprinter(method).fingerprint() ); - // Initialize result type (must be done after args->iterate()) + // Initialize result type result->set_type(args->get_ret_type()); + // Invoke the method. Result is returned as oop. JavaCalls::call(result, method, &java_args, CHECK); // Convert result if (result->get_type() == T_OBJECT || result->get_type() == T_ARRAY) { result->set_jobject(JNIHandles::make_local(env, (oop) result->get_jobject())); } - -#ifdef HIGH_LEVEL_INTERPRETER - if (invoked_main_method) { - assert(THREAD->is_Java_thread(), "other threads must not call into java"); - JavaThread* thread = (JavaThread*)THREAD; - thread->set_high_level_interpreter_in_vm(false); - } -#endif } @@ -2654,7 +2645,7 @@ o = JvmtiExport::jni_GetField_probe(thread, obj, o, k, fieldID, false); } jobject ret = JNIHandles::make_local(env, o->obj_field(offset)); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // If G1 is enabled and we are accessing the value of the referent // field in a reference object then we need to register a non-null // referent with the SATB barrier. @@ -2673,7 +2664,7 @@ G1SATBCardTableModRefBS::enqueue(referent); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #ifndef USDT2 DTRACE_PROBE1(hotspot_jni, GetObjectField__return, ret); #else /* USDT2 */ diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jniCheck.hpp --- a/src/share/vm/prims/jniCheck.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jniCheck.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,7 @@ #ifndef SHARE_VM_PRIMS_JNICHECK_HPP #define SHARE_VM_PRIMS_JNICHECK_HPP -#ifndef KERNEL #include "runtime/thread.hpp" -#endif extern "C" { // Report a JNI failure caught by -Xcheck:jni. Perform a core dump. diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jvm.cpp --- a/src/share/vm/prims/jvm.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jvm.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1575,9 +1575,9 @@ if (!java_lang_Class::is_primitive(JNIHandles::resolve(cls))) { Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve(cls)); if (k->oop_is_instance()) { - Annotations* type_annotations = InstanceKlass::cast(k)->type_annotations(); + AnnotationArray* type_annotations = InstanceKlass::cast(k)->class_type_annotations(); if (type_annotations != NULL) { - typeArrayOop a = Annotations::make_java_array(type_annotations->class_annotations(), CHECK_NULL); + typeArrayOop a = Annotations::make_java_array(type_annotations, CHECK_NULL); return (jbyteArray) JNIHandles::make_local(env, a); } } @@ -1622,7 +1622,7 @@ // For a 0 index, give a NULL symbol Symbol* const sym = 0 != params[i].name_cp_index ? mh->constants()->symbol_at(params[i].name_cp_index) : NULL; - int flags = build_int_from_shorts(params[i].flags_lo, params[i].flags_hi); + int flags = params[i].flags; oop param = Reflection::new_parameter(reflected_method, i, sym, flags, CHECK_NULL); result->obj_at_put(i, param); @@ -2304,6 +2304,15 @@ JVM_END +JVM_QUICK_ENTRY(jboolean, JVM_IsVMGeneratedMethodIx(JNIEnv *env, jclass cls, int method_index)) + JVMWrapper("JVM_IsVMGeneratedMethodIx"); + ResourceMark rm(THREAD); + Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls)); + k = JvmtiThreadState::class_to_verify_considering_redefinition(k, thread); + Method* method = InstanceKlass::cast(k)->methods()->at(method_index); + return method->is_overpass(); +JVM_END + JVM_ENTRY(const char*, JVM_GetMethodIxNameUTF(JNIEnv *env, jclass cls, jint method_index)) JVMWrapper("JVM_GetMethodIxIxUTF"); Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls)); @@ -4521,10 +4530,5 @@ // consider to expose this new capability in the sun.rt.jvmCapabilities jvmstat // counter defined in runtimeService.cpp. info->is_attachable = AttachListener::is_attach_supported(); -#ifdef KERNEL - info->is_kernel_jvm = 1; // true; -#else // KERNEL - info->is_kernel_jvm = 0; // false; -#endif // KERNEL } JVM_END diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jvm.h --- a/src/share/vm/prims/jvm.h Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jvm.h Thu Mar 21 14:11:13 2013 +0100 @@ -860,6 +860,13 @@ JVM_IsConstructorIx(JNIEnv *env, jclass cb, int index); /* + * Is the given method generated by the VM. + * The method is identified by method_index. + */ +JNIEXPORT jboolean JNICALL +JVM_IsVMGeneratedMethodIx(JNIEnv *env, jclass cb, int index); + +/* * Returns the name of a given method in UTF format. * The result remains valid until JVM_ReleaseUTF is called. * @@ -1552,8 +1559,7 @@ * the new bit is also added in the main/baseline. */ unsigned int is_attachable : 1; - unsigned int is_kernel_jvm : 1; - unsigned int : 30; + unsigned int : 31; unsigned int : 32; unsigned int : 32; } jvm_version_info; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jvmtiCodeBlobEvents.hpp --- a/src/share/vm/prims/jvmtiCodeBlobEvents.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jvmtiCodeBlobEvents.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,7 @@ #ifndef SHARE_VM_PRIMS_JVMTICODEBLOBEVENTS_HPP #define SHARE_VM_PRIMS_JVMTICODEBLOBEVENTS_HPP -#ifndef JVMTI_KERNEL #include "jvmtifiles/jvmti.h" -#endif // forward declaration class JvmtiEnv; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jvmtiEnv.cpp --- a/src/share/vm/prims/jvmtiEnv.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jvmtiEnv.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -647,8 +647,6 @@ return JVMTI_ERROR_NONE; } /* end GetJLocationFormat */ -#ifndef JVMTI_KERNEL - // // Thread functions // @@ -3436,5 +3434,3 @@ } return err; } /* end SetSystemProperty */ - -#endif // !JVMTI_KERNEL diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jvmtiEnvBase.cpp --- a/src/share/vm/prims/jvmtiEnvBase.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jvmtiEnvBase.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,10 +74,8 @@ JvmtiManageCapabilities::initialize(); -#ifndef JVMTI_KERNEL // register extension functions and events JvmtiExtensions::register_extensions(); -#endif // !JVMTI_KERNEL #ifdef JVMTI_TRACE JvmtiTrace::initialize(); @@ -236,14 +234,12 @@ // Same situation as with events (see above) set_native_method_prefixes(0, NULL); -#ifndef JVMTI_KERNEL JvmtiTagMap* tag_map_to_deallocate = _tag_map; set_tag_map(NULL); // A tag map can be big, deallocate it now if (tag_map_to_deallocate != NULL) { delete tag_map_to_deallocate; } -#endif // !JVMTI_KERNEL _needs_clean_up = true; } @@ -255,14 +251,12 @@ // There is a small window of time during which the tag map of a // disposed environment could have been reallocated. // Make sure it is gone. -#ifndef JVMTI_KERNEL JvmtiTagMap* tag_map_to_deallocate = _tag_map; set_tag_map(NULL); // A tag map can be big, deallocate it now if (tag_map_to_deallocate != NULL) { delete tag_map_to_deallocate; } -#endif // !JVMTI_KERNEL _magic = BAD_MAGIC; } @@ -593,8 +587,6 @@ return (jclass)jni_reference(k->java_mirror()); } -#ifndef JVMTI_KERNEL - // // Field Information // @@ -1482,5 +1474,3 @@ } } } - -#endif // !JVMTI_KERNEL diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jvmtiEnvBase.hpp --- a/src/share/vm/prims/jvmtiEnvBase.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jvmtiEnvBase.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -35,6 +35,7 @@ #include "runtime/thread.hpp" #include "runtime/vm_operations.hpp" #include "utilities/growableArray.hpp" +#include "utilities/macros.hpp" // // Forward Declarations diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jvmtiExport.cpp --- a/src/share/vm/prims/jvmtiExport.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jvmtiExport.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,9 +50,10 @@ #include "runtime/vframe.hpp" #include "services/attachListener.hpp" #include "services/serviceUtil.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/psMarkSweep.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef JVMTI_TRACE #define EVT_TRACE(evt,out) if ((JvmtiTrace::event_trace_flags(evt) & JvmtiTrace::SHOW_EVENT_SENT) != 0) { SafeResourceMark rm; tty->print_cr out; } @@ -677,7 +678,6 @@ } -#ifndef JVMTI_KERNEL static inline Klass* oop_to_klass(oop obj) { Klass* k = obj->klass(); @@ -2178,7 +2178,6 @@ typedef jint (JNICALL *OnAttachEntry_t)(JavaVM*, char *, void *); } -#ifndef SERVICES_KERNEL jint JvmtiExport::load_agent_library(AttachOperation* op, outputStream* st) { char ebuf[1024]; char buffer[JVM_MAXPATHLEN]; @@ -2259,7 +2258,6 @@ } return result; } -#endif // SERVICES_KERNEL //////////////////////////////////////////////////////////////////////////////////////////////// @@ -2457,4 +2455,3 @@ JvmtiExport::post_garbage_collection_finish(); } } -#endif // JVMTI_KERNEL diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jvmtiExport.hpp --- a/src/share/vm/prims/jvmtiExport.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jvmtiExport.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -34,6 +34,7 @@ #include "runtime/handles.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" +#include "utilities/macros.hpp" // Must be included after jvmti.h. #include "code/jvmticmlr.h" diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jvmtiExtensions.hpp --- a/src/share/vm/prims/jvmtiExtensions.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jvmtiExtensions.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,9 @@ #ifndef SHARE_VM_PRIMS_JVMTIEXTENSIONS_HPP #define SHARE_VM_PRIMS_JVMTIEXTENSIONS_HPP -#ifndef JVMTI_KERNEL #include "jvmtifiles/jvmti.h" #include "jvmtifiles/jvmtiEnv.hpp" #include "memory/allocation.hpp" -#endif // JvmtiExtensions // diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jvmtiImpl.cpp --- a/src/share/vm/prims/jvmtiImpl.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jvmtiImpl.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -905,8 +905,6 @@ #endif } -#ifndef KERNEL - JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_load_event( nmethod* nm) { JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_LOAD); @@ -1098,5 +1096,3 @@ } } } - -#endif // ndef KERNEL diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jvmtiImpl.hpp --- a/src/share/vm/prims/jvmtiImpl.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jvmtiImpl.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -25,8 +25,6 @@ #ifndef SHARE_VM_PRIMS_JVMTIIMPL_HPP #define SHARE_VM_PRIMS_JVMTIIMPL_HPP -#ifndef JVMTI_KERNEL - #include "classfile/systemDictionary.hpp" #include "jvmtifiles/jvmti.h" #include "oops/objArrayOop.hpp" @@ -435,7 +433,6 @@ static void print(); }; -#endif // !JVMTI_KERNEL /** * When a thread (such as the compiler thread or VM thread) cannot post a diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jvmtiRawMonitor.hpp --- a/src/share/vm/prims/jvmtiRawMonitor.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jvmtiRawMonitor.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, 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,10 +25,8 @@ #ifndef SHARE_VM_PRIMS_JVMTIRAWMONITOR_HPP #define SHARE_VM_PRIMS_JVMTIRAWMONITOR_HPP -#ifndef JVMTI_KERNEL #include "runtime/objectMonitor.hpp" #include "utilities/growableArray.hpp" -#endif // // class JvmtiRawMonitor diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/metadataOnStackMark.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/verifier.hpp" #include "code/codeCache.hpp" @@ -115,43 +116,6 @@ return true; } -// Keep track of marked on-stack metadata so it can be cleared. -GrowableArray* _marked_objects = NULL; -NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;) - -// Walk metadata on the stack and mark it so that redefinition doesn't delete -// it. Class unloading also walks the previous versions and might try to -// delete it, so this class is used by class unloading also. -MetadataOnStackMark::MetadataOnStackMark() { - assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); - NOT_PRODUCT(_is_active = true;) - if (_marked_objects == NULL) { - _marked_objects = new (ResourceObj::C_HEAP, mtClass) GrowableArray(1000, true); - } - Threads::metadata_do(Metadata::mark_on_stack); - CodeCache::alive_nmethods_do(nmethod::mark_on_stack); - CompileBroker::mark_on_stack(); -} - -MetadataOnStackMark::~MetadataOnStackMark() { - assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); - // Unmark everything that was marked. Can't do the same walk because - // redefine classes messes up the code cache so the set of methods - // might not be the same. - for (int i = 0; i< _marked_objects->length(); i++) { - _marked_objects->at(i)->set_on_stack(false); - } - _marked_objects->clear(); // reuse growable array for next time. - NOT_PRODUCT(_is_active = false;) -} - -// Record which objects are marked so we can unmark the same objects. -void MetadataOnStackMark::record(Metadata* m) { - assert(_is_active, "metadata on stack marking is active"); - _marked_objects->push(m); -} - - void VM_RedefineClasses::doit() { Thread *thread = Thread::current(); @@ -190,8 +154,15 @@ // See jvmtiExport.hpp for detailed explanation. JvmtiExport::set_has_redefined_a_class(); -#ifdef ASSERT - SystemDictionary::classes_do(check_class, thread); +// check_class() is optionally called for product bits, but is +// always called for non-product bits. +#ifdef PRODUCT + if (RC_TRACE_ENABLED(0x00004000)) { +#endif + RC_TRACE_WITH_THREAD(0x00004000, thread, ("calling check_class")); + SystemDictionary::classes_do(check_class, thread); +#ifdef PRODUCT + } #endif } @@ -314,76 +285,23 @@ case JVM_CONSTANT_NameAndType: { int name_ref_i = scratch_cp->name_ref_index_at(scratch_i); - int new_name_ref_i = 0; - bool match = (name_ref_i < *merge_cp_length_p) && - scratch_cp->compare_entry_to(name_ref_i, *merge_cp_p, name_ref_i, - THREAD); - if (!match) { - // forward reference in *merge_cp_p or not a direct match - - int found_i = scratch_cp->find_matching_entry(name_ref_i, *merge_cp_p, - THREAD); - if (found_i != 0) { - guarantee(found_i != name_ref_i, - "compare_entry_to() and find_matching_entry() do not agree"); - - // Found a matching entry somewhere else in *merge_cp_p so - // just need a mapping entry. - new_name_ref_i = found_i; - map_index(scratch_cp, name_ref_i, found_i); - } else { - // no match found so we have to append this entry to *merge_cp_p - append_entry(scratch_cp, name_ref_i, merge_cp_p, merge_cp_length_p, - THREAD); - // The above call to append_entry() can only append one entry - // so the post call query of *merge_cp_length_p is only for - // the sake of consistency. - new_name_ref_i = *merge_cp_length_p - 1; - } - } + int new_name_ref_i = find_or_append_indirect_entry(scratch_cp, name_ref_i, merge_cp_p, + merge_cp_length_p, THREAD); int signature_ref_i = scratch_cp->signature_ref_index_at(scratch_i); - int new_signature_ref_i = 0; - match = (signature_ref_i < *merge_cp_length_p) && - scratch_cp->compare_entry_to(signature_ref_i, *merge_cp_p, - signature_ref_i, THREAD); - if (!match) { - // forward reference in *merge_cp_p or not a direct match - - int found_i = scratch_cp->find_matching_entry(signature_ref_i, - *merge_cp_p, THREAD); - if (found_i != 0) { - guarantee(found_i != signature_ref_i, - "compare_entry_to() and find_matching_entry() do not agree"); - - // Found a matching entry somewhere else in *merge_cp_p so - // just need a mapping entry. - new_signature_ref_i = found_i; - map_index(scratch_cp, signature_ref_i, found_i); - } else { - // no match found so we have to append this entry to *merge_cp_p - append_entry(scratch_cp, signature_ref_i, merge_cp_p, - merge_cp_length_p, THREAD); - // The above call to append_entry() can only append one entry - // so the post call query of *merge_cp_length_p is only for - // the sake of consistency. - new_signature_ref_i = *merge_cp_length_p - 1; - } - } + int new_signature_ref_i = find_or_append_indirect_entry(scratch_cp, signature_ref_i, + merge_cp_p, merge_cp_length_p, + THREAD); // If the referenced entries already exist in *merge_cp_p, then // both new_name_ref_i and new_signature_ref_i will both be 0. // In that case, all we are appending is the current entry. - if (new_name_ref_i == 0) { - new_name_ref_i = name_ref_i; - } else { + if (new_name_ref_i != name_ref_i) { RC_TRACE(0x00080000, ("NameAndType entry@%d name_ref_index change: %d to %d", *merge_cp_length_p, name_ref_i, new_name_ref_i)); } - if (new_signature_ref_i == 0) { - new_signature_ref_i = signature_ref_i; - } else { + if (new_signature_ref_i != signature_ref_i) { RC_TRACE(0x00080000, ("NameAndType entry@%d signature_ref_index change: %d to %d", *merge_cp_length_p, signature_ref_i, new_signature_ref_i)); @@ -405,76 +323,12 @@ case JVM_CONSTANT_Methodref: { int klass_ref_i = scratch_cp->uncached_klass_ref_index_at(scratch_i); - int new_klass_ref_i = 0; - bool match = (klass_ref_i < *merge_cp_length_p) && - scratch_cp->compare_entry_to(klass_ref_i, *merge_cp_p, klass_ref_i, - THREAD); - if (!match) { - // forward reference in *merge_cp_p or not a direct match - - int found_i = scratch_cp->find_matching_entry(klass_ref_i, *merge_cp_p, - THREAD); - if (found_i != 0) { - guarantee(found_i != klass_ref_i, - "compare_entry_to() and find_matching_entry() do not agree"); - - // Found a matching entry somewhere else in *merge_cp_p so - // just need a mapping entry. - new_klass_ref_i = found_i; - map_index(scratch_cp, klass_ref_i, found_i); - } else { - // no match found so we have to append this entry to *merge_cp_p - append_entry(scratch_cp, klass_ref_i, merge_cp_p, merge_cp_length_p, - THREAD); - // The above call to append_entry() can only append one entry - // so the post call query of *merge_cp_length_p is only for - // the sake of consistency. Without the optimization where we - // use JVM_CONSTANT_UnresolvedClass, then up to two entries - // could be appended. - new_klass_ref_i = *merge_cp_length_p - 1; - } - } - - int name_and_type_ref_i = - scratch_cp->uncached_name_and_type_ref_index_at(scratch_i); - int new_name_and_type_ref_i = 0; - match = (name_and_type_ref_i < *merge_cp_length_p) && - scratch_cp->compare_entry_to(name_and_type_ref_i, *merge_cp_p, - name_and_type_ref_i, THREAD); - if (!match) { - // forward reference in *merge_cp_p or not a direct match - - int found_i = scratch_cp->find_matching_entry(name_and_type_ref_i, - *merge_cp_p, THREAD); - if (found_i != 0) { - guarantee(found_i != name_and_type_ref_i, - "compare_entry_to() and find_matching_entry() do not agree"); - - // Found a matching entry somewhere else in *merge_cp_p so - // just need a mapping entry. - new_name_and_type_ref_i = found_i; - map_index(scratch_cp, name_and_type_ref_i, found_i); - } else { - // no match found so we have to append this entry to *merge_cp_p - append_entry(scratch_cp, name_and_type_ref_i, merge_cp_p, - merge_cp_length_p, THREAD); - // The above call to append_entry() can append more than - // one entry so the post call query of *merge_cp_length_p - // is required in order to get the right index for the - // JVM_CONSTANT_NameAndType entry. - new_name_and_type_ref_i = *merge_cp_length_p - 1; - } - } - - // If the referenced entries already exist in *merge_cp_p, then - // both new_klass_ref_i and new_name_and_type_ref_i will both be - // 0. In that case, all we are appending is the current entry. - if (new_klass_ref_i == 0) { - new_klass_ref_i = klass_ref_i; - } - if (new_name_and_type_ref_i == 0) { - new_name_and_type_ref_i = name_and_type_ref_i; - } + int new_klass_ref_i = find_or_append_indirect_entry(scratch_cp, klass_ref_i, + merge_cp_p, merge_cp_length_p, THREAD); + + int name_and_type_ref_i = scratch_cp->uncached_name_and_type_ref_index_at(scratch_i); + int new_name_and_type_ref_i = find_or_append_indirect_entry(scratch_cp, name_and_type_ref_i, + merge_cp_p, merge_cp_length_p, THREAD); const char *entry_name; switch (scratch_cp->tag_at(scratch_i).value()) { @@ -517,6 +371,72 @@ (*merge_cp_length_p)++; } break; + // this is an indirect CP entry so it needs special handling + case JVM_CONSTANT_MethodType: + { + int ref_i = scratch_cp->method_type_index_at(scratch_i); + int new_ref_i = find_or_append_indirect_entry(scratch_cp, ref_i, merge_cp_p, + merge_cp_length_p, THREAD); + if (new_ref_i != ref_i) { + RC_TRACE(0x00080000, + ("MethodType entry@%d ref_index change: %d to %d", + *merge_cp_length_p, ref_i, new_ref_i)); + } + (*merge_cp_p)->method_type_index_at_put(*merge_cp_length_p, new_ref_i); + if (scratch_i != *merge_cp_length_p) { + // The new entry in *merge_cp_p is at a different index than + // the new entry in scratch_cp so we need to map the index values. + map_index(scratch_cp, scratch_i, *merge_cp_length_p); + } + (*merge_cp_length_p)++; + } break; + + // this is an indirect CP entry so it needs special handling + case JVM_CONSTANT_MethodHandle: + { + int ref_kind = scratch_cp->method_handle_ref_kind_at(scratch_i); + int ref_i = scratch_cp->method_handle_index_at(scratch_i); + int new_ref_i = find_or_append_indirect_entry(scratch_cp, ref_i, merge_cp_p, + merge_cp_length_p, THREAD); + if (new_ref_i != ref_i) { + RC_TRACE(0x00080000, + ("MethodHandle entry@%d ref_index change: %d to %d", + *merge_cp_length_p, ref_i, new_ref_i)); + } + (*merge_cp_p)->method_handle_index_at_put(*merge_cp_length_p, ref_kind, new_ref_i); + if (scratch_i != *merge_cp_length_p) { + // The new entry in *merge_cp_p is at a different index than + // the new entry in scratch_cp so we need to map the index values. + map_index(scratch_cp, scratch_i, *merge_cp_length_p); + } + (*merge_cp_length_p)++; + } break; + + // this is an indirect CP entry so it needs special handling + case JVM_CONSTANT_InvokeDynamic: + { + // TBD: cross-checks and possible extra appends into CP and bsm operands + // are needed as well. This issue is tracked by a separate bug 8007037. + int bss_idx = scratch_cp->invoke_dynamic_bootstrap_specifier_index(scratch_i); + + int ref_i = scratch_cp->invoke_dynamic_name_and_type_ref_index_at(scratch_i); + int new_ref_i = find_or_append_indirect_entry(scratch_cp, ref_i, merge_cp_p, + merge_cp_length_p, THREAD); + if (new_ref_i != ref_i) { + RC_TRACE(0x00080000, + ("InvokeDynamic entry@%d name_and_type ref_index change: %d to %d", + *merge_cp_length_p, ref_i, new_ref_i)); + } + + (*merge_cp_p)->invoke_dynamic_at_put(*merge_cp_length_p, bss_idx, new_ref_i); + if (scratch_i != *merge_cp_length_p) { + // The new entry in *merge_cp_p is at a different index than + // the new entry in scratch_cp so we need to map the index values. + map_index(scratch_cp, scratch_i, *merge_cp_length_p); + } + (*merge_cp_length_p)++; + } break; + // At this stage, Class or UnresolvedClass could be here, but not // ClassIndex case JVM_CONSTANT_ClassIndex: // fall through @@ -543,24 +463,33 @@ } // end append_entry() -void VM_RedefineClasses::swap_all_method_annotations(int i, int j, instanceKlassHandle scratch_class, TRAPS) { - AnnotationArray* save; - - Annotations* sca = scratch_class->annotations(); - if (sca == NULL) return; - - save = sca->get_method_annotations_of(i); - sca->set_method_annotations_of(scratch_class, i, sca->get_method_annotations_of(j), CHECK); - sca->set_method_annotations_of(scratch_class, j, save, CHECK); - - save = sca->get_method_parameter_annotations_of(i); - sca->set_method_parameter_annotations_of(scratch_class, i, sca->get_method_parameter_annotations_of(j), CHECK); - sca->set_method_parameter_annotations_of(scratch_class, j, save, CHECK); - - save = sca->get_method_default_annotations_of(i); - sca->set_method_default_annotations_of(scratch_class, i, sca->get_method_default_annotations_of(j), CHECK); - sca->set_method_default_annotations_of(scratch_class, j, save, CHECK); -} +int VM_RedefineClasses::find_or_append_indirect_entry(constantPoolHandle scratch_cp, + int ref_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS) { + + int new_ref_i = ref_i; + bool match = (ref_i < *merge_cp_length_p) && + scratch_cp->compare_entry_to(ref_i, *merge_cp_p, ref_i, THREAD); + + if (!match) { + // forward reference in *merge_cp_p or not a direct match + int found_i = scratch_cp->find_matching_entry(ref_i, *merge_cp_p, THREAD); + if (found_i != 0) { + guarantee(found_i != ref_i, "compare_entry_to() and find_matching_entry() do not agree"); + // Found a matching entry somewhere else in *merge_cp_p so just need a mapping entry. + new_ref_i = found_i; + map_index(scratch_cp, ref_i, found_i); + } else { + // no match found so we have to append this entry to *merge_cp_p + append_entry(scratch_cp, ref_i, merge_cp_p, merge_cp_length_p, THREAD); + // The above call to append_entry() can only append one entry + // so the post call query of *merge_cp_length_p is only for + // the sake of consistency. + new_ref_i = *merge_cp_length_p - 1; + } + } + + return new_ref_i; +} // end find_or_append_indirect_entry() jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( @@ -744,10 +673,9 @@ idnum_owner->set_method_idnum(new_num); } k_new_method->set_method_idnum(old_num); - swap_all_method_annotations(old_num, new_num, scratch_class, thread); - if (thread->has_pending_exception()) { - return JVMTI_ERROR_OUT_OF_MEMORY; - } + if (thread->has_pending_exception()) { + return JVMTI_ERROR_OUT_OF_MEMORY; + } } } RC_TRACE(0x00008000, ("Method matched: new: %s [%d] == old: %s [%d]", @@ -780,7 +708,6 @@ idnum_owner->set_method_idnum(new_num); } k_new_method->set_method_idnum(num); - swap_all_method_annotations(new_num, num, scratch_class, thread); if (thread->has_pending_exception()) { return JVMTI_ERROR_OUT_OF_MEMORY; } @@ -1158,6 +1085,8 @@ } } // end for each old_cp entry + ConstantPool::copy_operands(old_cp, *merge_cp_p, CHECK_0); + // We don't need to sanity check that *merge_cp_length_p is within // *merge_cp_p bounds since we have the minimum on-entry check above. (*merge_cp_length_p) = old_i; @@ -1341,8 +1270,12 @@ _index_map_count = 0; _index_map_p = new intArray(scratch_cp->length(), -1); + // reference to the cp holder is needed for copy_operands() + merge_cp->set_pool_holder(scratch_class()); bool result = merge_constant_pools(old_cp, scratch_cp, &merge_cp, &merge_cp_length, THREAD); + merge_cp->set_pool_holder(NULL); + if (!result) { // The merge can fail due to memory allocation failure or due // to robustness checks. @@ -1594,6 +1527,7 @@ case Bytecodes::_getfield : // fall through case Bytecodes::_getstatic : // fall through case Bytecodes::_instanceof : // fall through + case Bytecodes::_invokedynamic : // fall through case Bytecodes::_invokeinterface: // fall through case Bytecodes::_invokespecial : // fall through case Bytecodes::_invokestatic : // fall through @@ -1615,15 +1549,27 @@ bcp, cp_index, new_index)); // Rewriter::rewrite_method() uses put_native_u2() in this // situation because it is reusing the constant pool index - // location for a native index into the constantPoolCache. + // location for a native index into the ConstantPoolCache. // Since we are updating the constant pool index prior to - // verification and constantPoolCache initialization, we + // verification and ConstantPoolCache initialization, we // need to keep the new index in Java byte order. Bytes::put_Java_u2(p, new_index); } } break; } } // end for each bytecode + + // We also need to rewrite the parameter name indexes, if there is + // method parameter data present + if(method->has_method_parameters()) { + const int len = method->method_parameters_length(); + MethodParametersElement* elem = method->method_parameters_start(); + + for (int i = 0; i < len; i++) { + const u2 cp_index = elem[i].name_cp_index; + elem[i].name_cp_index = find_new_index(cp_index); + } + } } // end rewrite_cp_refs_in_method() @@ -1939,10 +1885,7 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_fields_annotations( instanceKlassHandle scratch_class, TRAPS) { - Annotations* sca = scratch_class->annotations(); - if (sca == NULL) return true; - - Array* fields_annotations = sca->fields_annotations(); + Array* fields_annotations = scratch_class->fields_annotations(); if (fields_annotations == NULL || fields_annotations->length() == 0) { // no fields_annotations so nothing to do @@ -1977,21 +1920,10 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_methods_annotations( instanceKlassHandle scratch_class, TRAPS) { - Annotations* sca = scratch_class->annotations(); - if (sca == NULL) return true; - - Array* methods_annotations = sca->methods_annotations(); - - if (methods_annotations == NULL || methods_annotations->length() == 0) { - // no methods_annotations so nothing to do - return true; - } - - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("methods_annotations length=%d", methods_annotations->length())); - - for (int i = 0; i < methods_annotations->length(); i++) { - AnnotationArray* method_annotations = methods_annotations->at(i); + for (int i = 0; i < scratch_class->methods()->length(); i++) { + Method* m = scratch_class->methods()->at(i); + AnnotationArray* method_annotations = m->constMethod()->method_annotations(); + if (method_annotations == NULL || method_annotations->length() == 0) { // this method does not have any annotations so skip it continue; @@ -2027,24 +1959,9 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_methods_parameter_annotations( instanceKlassHandle scratch_class, TRAPS) { - Annotations* sca = scratch_class->annotations(); - if (sca == NULL) return true; - - Array* methods_parameter_annotations = - sca->methods_parameter_annotations(); - - if (methods_parameter_annotations == NULL - || methods_parameter_annotations->length() == 0) { - // no methods_parameter_annotations so nothing to do - return true; - } - - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("methods_parameter_annotations length=%d", - methods_parameter_annotations->length())); - - for (int i = 0; i < methods_parameter_annotations->length(); i++) { - AnnotationArray* method_parameter_annotations = methods_parameter_annotations->at(i); + for (int i = 0; i < scratch_class->methods()->length(); i++) { + Method* m = scratch_class->methods()->at(i); + AnnotationArray* method_parameter_annotations = m->constMethod()->parameter_annotations(); if (method_parameter_annotations == NULL || method_parameter_annotations->length() == 0) { // this method does not have any parameter annotations so skip it @@ -2094,24 +2011,9 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_methods_default_annotations( instanceKlassHandle scratch_class, TRAPS) { - Annotations* sca = scratch_class->annotations(); - if (sca == NULL) return true; - - Array* methods_default_annotations = - sca->methods_default_annotations(); - - if (methods_default_annotations == NULL - || methods_default_annotations->length() == 0) { - // no methods_default_annotations so nothing to do - return true; - } - - RC_TRACE_WITH_THREAD(0x02000000, THREAD, - ("methods_default_annotations length=%d", - methods_default_annotations->length())); - - for (int i = 0; i < methods_default_annotations->length(); i++) { - AnnotationArray* method_default_annotations = methods_default_annotations->at(i); + for (int i = 0; i < scratch_class->methods()->length(); i++) { + Method* m = scratch_class->methods()->at(i); + AnnotationArray* method_default_annotations = m->constMethod()->default_annotations(); if (method_default_annotations == NULL || method_default_annotations->length() == 0) { // this method does not have any default annotations so skip it @@ -2416,13 +2318,14 @@ assert(version != 0, "sanity check"); smaller_cp->set_version(version); + // attach klass to new constant pool + // reference to the cp holder is needed for copy_operands() + smaller_cp->set_pool_holder(scratch_class()); + scratch_cp->copy_cp_to(1, scratch_cp_length - 1, smaller_cp, 1, THREAD); scratch_cp = smaller_cp; // attach new constant pool to klass - scratch_cp->set_pool_holder(scratch_class()); - - // attach klass to new constant pool scratch_class->set_constants(scratch_cp()); int i; // for portability @@ -3115,6 +3018,31 @@ } +void VM_RedefineClasses::swap_annotations(instanceKlassHandle the_class, + instanceKlassHandle scratch_class) { + // Since there is currently no rewriting of type annotations indexes + // into the CP, we null out type annotations on scratch_class before + // we swap annotations with the_class rather than facing the + // possibility of shipping annotations with broken indexes to + // Java-land. + ClassLoaderData* loader_data = scratch_class->class_loader_data(); + AnnotationArray* new_class_type_annotations = scratch_class->class_type_annotations(); + if (new_class_type_annotations != NULL) { + MetadataFactory::free_array(loader_data, new_class_type_annotations); + scratch_class->annotations()->set_class_type_annotations(NULL); + } + Array* new_field_type_annotations = scratch_class->fields_type_annotations(); + if (new_field_type_annotations != NULL) { + Annotations::free_contents(loader_data, new_field_type_annotations); + scratch_class->annotations()->set_fields_type_annotations(NULL); + } + + // Swap annotation fields values + Annotations* old_annotations = the_class->annotations(); + the_class->set_annotations(scratch_class->annotations()); + scratch_class->set_annotations(old_annotations); +} + // Install the redefinition of a class: // - house keeping (flushing breakpoints and caches, deoptimizing @@ -3140,11 +3068,9 @@ Klass* the_class_oop = java_lang_Class::as_Klass(the_class_mirror); instanceKlassHandle the_class = instanceKlassHandle(THREAD, the_class_oop); -#ifndef JVMTI_KERNEL // Remove all breakpoints in methods of this class JvmtiBreakpoints& jvmti_breakpoints = JvmtiCurrentBreakpoints::get_jvmti_breakpoints(); jvmti_breakpoints.clearall_in_class_at_safepoint(the_class_oop); -#endif // !JVMTI_KERNEL if (the_class_oop == Universe::reflect_invoke_cache()->klass()) { // We are redefining java.lang.reflect.Method. Method.invoke() is @@ -3327,23 +3253,7 @@ the_class->set_access_flags(flags); } - // Since there is currently no rewriting of type annotations indexes - // into the CP, we null out type annotations on scratch_class before - // we swap annotations with the_class rather than facing the - // possibility of shipping annotations with broken indexes to - // Java-land. - Annotations* new_annotations = scratch_class->annotations(); - if (new_annotations != NULL) { - Annotations* new_type_annotations = new_annotations->type_annotations(); - if (new_type_annotations != NULL) { - MetadataFactory::free_metadata(scratch_class->class_loader_data(), new_type_annotations); - new_annotations->set_type_annotations(NULL); - } - } - // Swap annotation fields values - Annotations* old_annotations = the_class->annotations(); - the_class->set_annotations(scratch_class->annotations()); - scratch_class->set_annotations(old_annotations); + swap_annotations(the_class, scratch_class); // Replace minor version number of class file u2 old_minor_version = the_class->minor_version(); @@ -3423,7 +3333,6 @@ } } -#ifndef PRODUCT void VM_RedefineClasses::check_class(Klass* k_oop, ClassLoaderData* initiating_loader, TRAPS) { @@ -3431,82 +3340,110 @@ if (k->oop_is_instance()) { HandleMark hm(THREAD); InstanceKlass *ik = (InstanceKlass *) k; - - if (ik->vtable_length() > 0) { - ResourceMark rm(THREAD); - if (!ik->vtable()->check_no_old_entries()) { - tty->print_cr("klassVtable::check_no_old_entries failure -- OLD method found -- class: %s", ik->signature_name()); + bool no_old_methods = true; // be optimistic + ResourceMark rm(THREAD); + + // a vtable should never contain old or obsolete methods + if (ik->vtable_length() > 0 && + !ik->vtable()->check_no_old_or_obsolete_entries()) { + if (RC_TRACE_ENABLED(0x00004000)) { + RC_TRACE_WITH_THREAD(0x00004000, THREAD, + ("klassVtable::check_no_old_or_obsolete_entries failure" + " -- OLD or OBSOLETE method found -- class: %s", + ik->signature_name())); ik->vtable()->dump_vtable(); - assert(false, "OLD method found"); } + no_old_methods = false; } - if (ik->itable_length() > 0) { - ResourceMark rm(THREAD); - if (!ik->itable()->check_no_old_entries()) { - tty->print_cr("klassItable::check_no_old_entries failure -- OLD method found -- class: %s", ik->signature_name()); - assert(false, "OLD method found"); + + // an itable should never contain old or obsolete methods + if (ik->itable_length() > 0 && + !ik->itable()->check_no_old_or_obsolete_entries()) { + if (RC_TRACE_ENABLED(0x00004000)) { + RC_TRACE_WITH_THREAD(0x00004000, THREAD, + ("klassItable::check_no_old_or_obsolete_entries failure" + " -- OLD or OBSOLETE method found -- class: %s", + ik->signature_name())); + ik->itable()->dump_itable(); } + no_old_methods = false; } - // Check that the constant pool cache has no deleted entries. + + // the constant pool cache should never contain old or obsolete methods if (ik->constants() != NULL && ik->constants()->cache() != NULL && - !ik->constants()->cache()->check_no_old_entries()) { - tty->print_cr("klassVtable::check_no_old_entries failure -- OLD method found -- class: %s", ik->signature_name()); - assert(false, "OLD method found"); + !ik->constants()->cache()->check_no_old_or_obsolete_entries()) { + if (RC_TRACE_ENABLED(0x00004000)) { + RC_TRACE_WITH_THREAD(0x00004000, THREAD, + ("cp-cache::check_no_old_or_obsolete_entries failure" + " -- OLD or OBSOLETE method found -- class: %s", + ik->signature_name())); + ik->constants()->cache()->dump_cache(); + } + no_old_methods = false; + } + + if (!no_old_methods) { + if (RC_TRACE_ENABLED(0x00004000)) { + dump_methods(); + } else { + tty->print_cr("INFO: use the '-XX:TraceRedefineClasses=16384' option " + "to see more info about the following guarantee() failure."); + } + guarantee(false, "OLD and/or OBSOLETE method(s) found"); } } } void VM_RedefineClasses::dump_methods() { - int j; - tty->print_cr("_old_methods --"); - for (j = 0; j < _old_methods->length(); ++j) { - Method* m = _old_methods->at(j); - tty->print("%4d (%5d) ", j, m->vtable_index()); - m->access_flags().print_on(tty); - tty->print(" -- "); - m->print_name(tty); - tty->cr(); - } - tty->print_cr("_new_methods --"); - for (j = 0; j < _new_methods->length(); ++j) { - Method* m = _new_methods->at(j); - tty->print("%4d (%5d) ", j, m->vtable_index()); - m->access_flags().print_on(tty); - tty->print(" -- "); - m->print_name(tty); - tty->cr(); - } - tty->print_cr("_matching_(old/new)_methods --"); - for (j = 0; j < _matching_methods_length; ++j) { - Method* m = _matching_old_methods[j]; - tty->print("%4d (%5d) ", j, m->vtable_index()); - m->access_flags().print_on(tty); - tty->print(" -- "); - m->print_name(tty); - tty->cr(); - m = _matching_new_methods[j]; - tty->print(" (%5d) ", m->vtable_index()); - m->access_flags().print_on(tty); - tty->cr(); - } - tty->print_cr("_deleted_methods --"); - for (j = 0; j < _deleted_methods_length; ++j) { - Method* m = _deleted_methods[j]; - tty->print("%4d (%5d) ", j, m->vtable_index()); - m->access_flags().print_on(tty); - tty->print(" -- "); - m->print_name(tty); - tty->cr(); - } - tty->print_cr("_added_methods --"); - for (j = 0; j < _added_methods_length; ++j) { - Method* m = _added_methods[j]; - tty->print("%4d (%5d) ", j, m->vtable_index()); - m->access_flags().print_on(tty); - tty->print(" -- "); - m->print_name(tty); - tty->cr(); - } + int j; + RC_TRACE(0x00004000, ("_old_methods --")); + for (j = 0; j < _old_methods->length(); ++j) { + Method* m = _old_methods->at(j); + RC_TRACE_NO_CR(0x00004000, ("%4d (%5d) ", j, m->vtable_index())); + m->access_flags().print_on(tty); + tty->print(" -- "); + m->print_name(tty); + tty->cr(); + } + RC_TRACE(0x00004000, ("_new_methods --")); + for (j = 0; j < _new_methods->length(); ++j) { + Method* m = _new_methods->at(j); + RC_TRACE_NO_CR(0x00004000, ("%4d (%5d) ", j, m->vtable_index())); + m->access_flags().print_on(tty); + tty->print(" -- "); + m->print_name(tty); + tty->cr(); + } + RC_TRACE(0x00004000, ("_matching_(old/new)_methods --")); + for (j = 0; j < _matching_methods_length; ++j) { + Method* m = _matching_old_methods[j]; + RC_TRACE_NO_CR(0x00004000, ("%4d (%5d) ", j, m->vtable_index())); + m->access_flags().print_on(tty); + tty->print(" -- "); + m->print_name(tty); + tty->cr(); + m = _matching_new_methods[j]; + RC_TRACE_NO_CR(0x00004000, (" (%5d) ", m->vtable_index())); + m->access_flags().print_on(tty); + tty->cr(); + } + RC_TRACE(0x00004000, ("_deleted_methods --")); + for (j = 0; j < _deleted_methods_length; ++j) { + Method* m = _deleted_methods[j]; + RC_TRACE_NO_CR(0x00004000, ("%4d (%5d) ", j, m->vtable_index())); + m->access_flags().print_on(tty); + tty->print(" -- "); + m->print_name(tty); + tty->cr(); + } + RC_TRACE(0x00004000, ("_added_methods --")); + for (j = 0; j < _added_methods_length; ++j) { + Method* m = _added_methods[j]; + RC_TRACE_NO_CR(0x00004000, ("%4d (%5d) ", j, m->vtable_index())); + m->access_flags().print_on(tty); + tty->print(" -- "); + m->print_name(tty); + tty->cr(); + } } -#endif diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jvmtiRedefineClasses.hpp --- a/src/share/vm/prims/jvmtiRedefineClasses.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jvmtiRedefineClasses.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -384,11 +384,6 @@ jvmtiError compare_and_normalize_class_versions( instanceKlassHandle the_class, instanceKlassHandle scratch_class); - // Swap annotations[i] with annotations[j] - // Used by compare_and_normalize_class_versions() when normalizing - // overloaded methods or changing idnum as when adding or deleting methods. - void swap_all_method_annotations(int i, int j, instanceKlassHandle scratch_class, TRAPS); - // Figure out which new methods match old methods in name and signature, // which methods have been added, and which are no longer present void compute_added_deleted_matching_methods(); @@ -417,14 +412,18 @@ void redefine_single_class(jclass the_jclass, Klass* scratch_class_oop, TRAPS); + void swap_annotations(instanceKlassHandle new_class, + instanceKlassHandle scratch_class); + // Increment the classRedefinedCount field in the specific InstanceKlass // and in all direct and indirect subclasses. void increment_class_counter(InstanceKlass *ik, TRAPS); - // Support for constant pool merging (these routines are in alpha - // order): + // Support for constant pool merging (these routines are in alpha order): void append_entry(constantPoolHandle scratch_cp, int scratch_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS); + int find_or_append_indirect_entry(constantPoolHandle scratch_cp, int scratch_i, + constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS); int find_new_index(int old_index); bool is_unresolved_class_mismatch(constantPoolHandle cp1, int index1, constantPoolHandle cp2, int index2); @@ -467,9 +466,9 @@ void flush_dependent_code(instanceKlassHandle k_h, TRAPS); - static void check_class(Klass* k_oop, ClassLoaderData* initiating_loader, TRAPS) PRODUCT_RETURN; - - static void dump_methods() PRODUCT_RETURN; + static void check_class(Klass* k_oop, ClassLoaderData* initiating_loader, + TRAPS); + static void dump_methods(); public: VM_RedefineClasses(jint class_count, @@ -487,17 +486,4 @@ // and redefine implementation static bool is_modifiable_class(oop klass_mirror); }; - - -// Helper class to mark and unmark metadata used on the stack as either handles -// or executing methods, so that it can't be deleted during class redefinition -// and class unloading. -class MetadataOnStackMark : public StackObj { - NOT_PRODUCT(static bool _is_active;) - public: - MetadataOnStackMark() NOT_JVMTI_RETURN; - ~MetadataOnStackMark() NOT_JVMTI_RETURN; - static void record(Metadata* m) NOT_JVMTI_RETURN; -}; - #endif // SHARE_VM_PRIMS_JVMTIREDEFINECLASSES_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jvmtiRedefineClassesTrace.hpp --- a/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jvmtiRedefineClassesTrace.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,7 @@ // 0x00000800 | 2048 - previous class breakpoint mgmt // 0x00001000 | 4096 - detect calls to obsolete methods // 0x00002000 | 8192 - fail a guarantee() in addition to detection -// 0x00004000 | 16384 - unused +// 0x00004000 | 16384 - detect old/obsolete methods in metadata // 0x00008000 | 32768 - old/new method matching/add/delete // 0x00010000 | 65536 - impl details: CP size info // 0x00020000 | 131072 - impl details: CP merge pass info @@ -82,6 +82,13 @@ 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); \ diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jvmtiTagMap.cpp --- a/src/share/vm/prims/jvmtiTagMap.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jvmtiTagMap.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -45,9 +45,10 @@ #include "runtime/vmThread.hpp" #include "runtime/vm_operations.hpp" #include "services/serviceUtil.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" -#endif +#endif // INCLUDE_ALL_GCS // JvmtiTagHashmapEntry // diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/jvmtiTagMap.hpp --- a/src/share/vm/prims/jvmtiTagMap.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/jvmtiTagMap.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,12 @@ #ifndef SHARE_VM_PRIMS_JVMTITAGMAP_HPP #define SHARE_VM_PRIMS_JVMTITAGMAP_HPP -#ifndef JVMTI_KERNEL #include "gc_interface/collectedHeap.hpp" #include "jvmtifiles/jvmti.h" #include "jvmtifiles/jvmtiEnv.hpp" #include "memory/allocation.hpp" #include "memory/genCollectedHeap.hpp" #include "memory/universe.hpp" -#endif // forward references class JvmtiTagHashmap; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/nativeLookup.cpp --- a/src/share/vm/prims/nativeLookup.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/nativeLookup.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -40,6 +40,7 @@ #include "runtime/javaCalls.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" +#include "utilities/macros.hpp" #ifdef TARGET_OS_FAMILY_linux # include "os_linux.inline.hpp" #endif diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/unsafe.cpp --- a/src/share/vm/prims/unsafe.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/unsafe.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -24,9 +24,10 @@ #include "precompiled.hpp" #include "classfile/vmSymbols.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #include "memory/allocation.inline.hpp" #include "prims/jni.h" #include "prims/jvm.h" @@ -189,7 +190,7 @@ if (obj == NULL) THROW_0(vmSymbols::java_lang_NullPointerException()); GET_OOP_FIELD(obj, offset, v) jobject ret = JNIHandles::make_local(env, v); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // We could be accessing the referent field in a reference // object. If G1 is enabled then we need to register a non-null // referent with the SATB barrier. @@ -212,7 +213,7 @@ G1SATBCardTableModRefBS::enqueue(referent); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS return ret; UNSAFE_END @@ -247,7 +248,7 @@ UnsafeWrapper("Unsafe_GetObject"); GET_OOP_FIELD(obj, offset, v) jobject ret = JNIHandles::make_local(env, v); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // We could be accessing the referent field in a reference // object. If G1 is enabled then we need to register non-null // referent with the SATB barrier. @@ -270,7 +271,7 @@ G1SATBCardTableModRefBS::enqueue(referent); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS return ret; UNSAFE_END diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/wbtestmethods/parserTests.hpp --- a/src/share/vm/prims/wbtestmethods/parserTests.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/wbtestmethods/parserTests.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -27,6 +27,6 @@ #include "prims/jni.h" #include "prims/whitebox.hpp" -WB_METHOD_DECLARE WB_ParseCommandLine(JNIEnv* env, jobject o, jstring args, jobjectArray arguments); +WB_METHOD_DECLARE(jobjectArray) WB_ParseCommandLine(JNIEnv* env, jobject o, jstring args, jobjectArray arguments); #endif //SHARE_VM_PRIMS_WBTESTMETHODS_PARSERTESTS_H diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/whitebox.cpp --- a/src/share/vm/prims/whitebox.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/whitebox.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -36,12 +36,19 @@ #include "runtime/interfaceSupport.hpp" #include "runtime/os.hpp" #include "utilities/debug.hpp" +#include "utilities/macros.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/concurrentMark.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS + +#ifdef INCLUDE_NMT +#include "services/memTracker.hpp" +#endif // INCLUDE_NMT + +#include "compiler/compileBroker.hpp" bool WhiteBox::_used = false; @@ -85,7 +92,7 @@ return closure.found(); WB_END -#ifndef SERIALGC +#if INCLUDE_ALL_GCS WB_ENTRY(jboolean, WB_G1IsHumongous(JNIEnv* env, jobject o, jobject obj)) G1CollectedHeap* g1 = G1CollectedHeap::heap(); oop result = JNIHandles::resolve(obj); @@ -108,7 +115,144 @@ WB_ENTRY(jint, WB_G1RegionSize(JNIEnv* env, jobject o)) return (jint)HeapRegion::GrainBytes; WB_END -#endif // !SERIALGC +#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; + + if (!MemTracker::is_on() || MemTracker::shutdown_in_progress()) { + return false; + } + + // 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; +WB_END + +// Free the memory allocated by NMTAllocTest +WB_ENTRY(jboolean, WB_NMTFreeTestMemory(JNIEnv* env)) + + if (nmtMtTest1 == NULL || nmtMtTest2 == NULL || nmtMtTest3 == NULL) { + return false; + } + + os::free(nmtMtTest1, mtTest); + nmtMtTest1 = NULL; + os::free(nmtMtTest2, mtTest); + nmtMtTest2 = NULL; + os::free(nmtMtTest3, mtTest); + nmtMtTest3 = NULL; + + return true; +WB_END + +// Block until the current generation of NMT data to be merged, used to reliably test the NMT feature +WB_ENTRY(jboolean, WB_NMTWaitForDataMerge(JNIEnv* env)) + + if (!MemTracker::is_on() || MemTracker::shutdown_in_progress()) { + return false; + } + + return MemTracker::wbtest_wait_for_data_merge(); +WB_END + +#endif // INCLUDE_NMT + +static jmethodID reflected_method_to_jmid(JavaThread* thread, JNIEnv* env, jobject method) { + assert(method != NULL, "method should not be null"); + ThreadToNativeFromVM ttn(thread); + return env->FromReflectedMethod(method); +} + +WB_ENTRY(void, WB_DeoptimizeAll(JNIEnv* env, jobject o)) + MutexLockerEx mu(Compile_lock); + CodeCache::mark_all_nmethods_for_deoptimization(); + VM_Deoptimize op; + VMThread::execute(&op); +WB_END + +WB_ENTRY(jint, WB_DeoptimizeMethod(JNIEnv* env, jobject o, jobject method)) + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + MutexLockerEx mu(Compile_lock); + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + int result = 0; + nmethod* code = mh->code(); + if (code != NULL) { + code->mark_for_deoptimization(); + ++result; + } + result += CodeCache::mark_for_deoptimization(mh()); + if (result > 0) { + VM_Deoptimize op; + VMThread::execute(&op); + } + return result; +WB_END + +WB_ENTRY(jboolean, WB_IsMethodCompiled(JNIEnv* env, jobject o, jobject method)) + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + MutexLockerEx mu(Compile_lock); + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + nmethod* code = mh->code(); + if (code == NULL) { + return JNI_FALSE; + } + return (code->is_alive() && !code->is_marked_for_deoptimization()); +WB_END + +WB_ENTRY(jboolean, WB_IsMethodCompilable(JNIEnv* env, jobject o, jobject method)) + 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(); +WB_END + +WB_ENTRY(jboolean, WB_IsMethodQueuedForCompilation(JNIEnv* env, jobject o, jobject method)) + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + MutexLockerEx mu(Compile_lock); + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + return mh->queued_for_compilation(); +WB_END + +WB_ENTRY(jint, WB_GetMethodCompilationLevel(JNIEnv* env, jobject o, jobject method)) + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + nmethod* code = mh->code(); + return (code != NULL ? code->comp_level() : CompLevel_none); +WB_END + + +WB_ENTRY(void, WB_MakeMethodNotCompilable(JNIEnv* env, jobject o, jobject method)) + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + mh->set_not_compilable(); +WB_END + +WB_ENTRY(jboolean, WB_SetDontInlineMethod(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(); + mh->set_dont_inline(value == JNI_TRUE); + return result; +WB_END + +WB_ENTRY(jint, WB_GetCompileQueuesSize(JNIEnv* env, jobject o)) + return CompileBroker::queue_size(CompLevel_full_optimization) /* C2 */ + + CompileBroker::queue_size(CompLevel_full_profile) /* C1 */; +WB_END //Some convenience methods to deal with objects from java int WhiteBox::offset_for_field(const char* field_name, oop object, @@ -166,17 +310,39 @@ static JNINativeMethod methods[] = { {CC"getObjectAddress", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress }, {CC"getHeapOopSize", CC"()I", (void*)&WB_GetHeapOopSize }, - {CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive }, - {CC "parseCommandLine", - CC "(Ljava/lang/String;[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;", + {CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive }, + {CC"parseCommandLine", + CC"(Ljava/lang/String;[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;", (void*) &WB_ParseCommandLine }, -#ifndef SERIALGC +#if INCLUDE_ALL_GCS {CC"g1InConcurrentMark", CC"()Z", (void*)&WB_G1InConcurrentMark}, {CC"g1IsHumongous", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous }, {CC"g1NumFreeRegions", CC"()J", (void*)&WB_G1NumFreeRegions }, {CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize }, -#endif // !SERIALGC +#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}, +#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", + (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"getMethodCompilationLevel", + CC"(Ljava/lang/reflect/Method;)I", (void*)&WB_GetMethodCompilationLevel}, + {CC"getCompileQueuesSize", + CC"()I", (void*)&WB_GetCompileQueuesSize}, }; #undef CC diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/prims/whitebox.hpp --- a/src/share/vm/prims/whitebox.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/prims/whitebox.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -34,7 +34,7 @@ #define WB_ENTRY(result_type, header) JNI_ENTRY(result_type, header) #define WB_END JNI_END -#define WB_METHOD_DECLARE extern "C" jobjectArray JNICALL +#define WB_METHOD_DECLARE(result_type) extern "C" result_type JNICALL class WhiteBox : public AllStatic { private: diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/arguments.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -38,6 +38,7 @@ #include "services/management.hpp" #include "services/memTracker.hpp" #include "utilities/defaultStream.hpp" +#include "utilities/macros.hpp" #include "utilities/taskqueue.hpp" #ifdef TARGET_OS_FAMILY_linux # include "os_linux.inline.hpp" @@ -51,9 +52,9 @@ #ifdef TARGET_OS_FAMILY_bsd # include "os_bsd.inline.hpp" #endif -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp" -#endif +#endif // INCLUDE_ALL_GCS // Note: This is a special bug reporting site for the JVM #define DEFAULT_VENDOR_URL_BUG "http://bugreport.sun.com/bugreport/crash.jsp" @@ -104,9 +105,6 @@ SystemProperty *Arguments::_java_home = NULL; SystemProperty *Arguments::_java_class_path = NULL; SystemProperty *Arguments::_sun_boot_class_path = NULL; -#ifdef GRAAL -SystemProperty *Arguments::_compiler_class_path = NULL; -#endif char* Arguments::_meta_index_path = NULL; char* Arguments::_meta_index_dir = NULL; @@ -168,9 +166,6 @@ _java_library_path = new SystemProperty("java.library.path", NULL, true); _java_home = new SystemProperty("java.home", NULL, true); _sun_boot_class_path = new SystemProperty("sun.boot.class.path", NULL, true); -#ifdef GRAAL - _compiler_class_path = new SystemProperty("compiler.class.path", NULL, true); -#endif _java_class_path = new SystemProperty("java.class.path", "", true); @@ -182,9 +177,6 @@ PropertyList_add(&_system_properties, _java_home); PropertyList_add(&_system_properties, _java_class_path); PropertyList_add(&_system_properties, _sun_boot_class_path); -#ifdef GRAAL - PropertyList_add(&_system_properties, _compiler_class_path); -#endif // Set OS specific system properties values os::init_system_properties_values(); @@ -845,7 +837,8 @@ return true; } - const char * const argname = *arg == '+' || *arg == '-' ? arg + 1 : arg; + bool has_plus_minus = (*arg == '+' || *arg == '-'); + const char* const argname = has_plus_minus ? arg + 1 : arg; if (is_newly_obsolete(arg, &since)) { char version[256]; since.to_string(version, sizeof(version)); @@ -856,13 +849,29 @@ // For locked flags, report a custom error message if available. // Otherwise, report the standard unrecognized VM option. - Flag* locked_flag = Flag::find_flag((char*)argname, strlen(argname), true); - if (locked_flag != NULL) { + size_t arg_len; + const char* equal_sign = strchr(argname, '='); + if (equal_sign == NULL) { + arg_len = strlen(argname); + } else { + arg_len = equal_sign - argname; + } + + Flag* found_flag = Flag::find_flag((char*)argname, arg_len, true); + if (found_flag != NULL) { char locked_message_buf[BUFLEN]; - locked_flag->get_locked_message(locked_message_buf, BUFLEN); + found_flag->get_locked_message(locked_message_buf, BUFLEN); if (strlen(locked_message_buf) == 0) { - jio_fprintf(defaultStream::error_stream(), - "Unrecognized VM option '%s'\n", argname); + if (found_flag->is_bool() && !has_plus_minus) { + jio_fprintf(defaultStream::error_stream(), + "Missing +/- setting for VM option '%s'\n", argname); + } else if (!found_flag->is_bool() && has_plus_minus) { + jio_fprintf(defaultStream::error_stream(), + "Unexpected +/- setting in VM option '%s'\n", argname); + } else { + jio_fprintf(defaultStream::error_stream(), + "Improperly specified VM option '%s'\n", argname); + } } else { jio_fprintf(defaultStream::error_stream(), "%s", locked_message_buf); } @@ -1086,11 +1095,11 @@ } // Increase the code cache size - tiered compiles a lot more. if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) { - FLAG_SET_DEFAULT(ReservedCodeCacheSize, ReservedCodeCacheSize * 2); + FLAG_SET_DEFAULT(ReservedCodeCacheSize, ReservedCodeCacheSize * 5); } } -#if INCLUDE_ALTERNATE_GCS +#if INCLUDE_ALL_GCS static void disable_adaptive_size_policy(const char* collector_name) { if (UseAdaptiveSizePolicy) { if (FLAG_IS_CMDLINE(UseAdaptiveSizePolicy)) { @@ -1257,7 +1266,7 @@ // prefer minuscule survivor spaces so as not to waste // space for (non-existent) survivors if (FLAG_IS_DEFAULT(SurvivorRatio) && MaxTenuringThreshold == 0) { - FLAG_SET_ERGO(intx, SurvivorRatio, MAX2((intx)1024, SurvivorRatio)); + FLAG_SET_ERGO(uintx, SurvivorRatio, MAX2((uintx)1024, SurvivorRatio)); } // If OldPLABSize is set and CMSParPromoteBlocksToClaim is not, // set CMSParPromoteBlocksToClaim equal to OldPLABSize. @@ -1302,7 +1311,7 @@ tty->print_cr("ConcGCThreads: %u", ConcGCThreads); } } -#endif // INCLUDE_ALTERNATE_GCS +#endif // INCLUDE_ALL_GCS void set_object_alignment() { // Object alignment. @@ -1319,10 +1328,10 @@ // Oop encoding heap max OopEncodingHeapMax = (uint64_t(max_juint) + 1) << LogMinObjAlignmentInBytes; -#if INCLUDE_ALTERNATE_GCS +#if INCLUDE_ALL_GCS // Set CMS global values CompactibleFreeListSpace::set_cms_values(); -#endif // INCLUDE_ALTERNATE_GCS +#endif // INCLUDE_ALL_GCS } bool verify_object_alignment() { @@ -1447,13 +1456,18 @@ } // Set the ClassMetaspaceSize to something that will not need to be // expanded, since it cannot be expanded. - if (UseCompressedKlassPointers && FLAG_IS_DEFAULT(ClassMetaspaceSize)) { - // 100,000 classes seems like a good size, so 100M assumes around 1K - // per klass. The vtable and oopMap is embedded so we don't have a fixed - // size per klass. Eventually, this will be parameterized because it - // would also be useful to determine the optimal size of the - // systemDictionary. - FLAG_SET_ERGO(uintx, ClassMetaspaceSize, 100*M); + if (UseCompressedKlassPointers) { + if (ClassMetaspaceSize > KlassEncodingMetaspaceMax) { + warning("Class metaspace size is too large for UseCompressedKlassPointers"); + FLAG_SET_DEFAULT(UseCompressedKlassPointers, false); + } else if (FLAG_IS_DEFAULT(ClassMetaspaceSize)) { + // 100,000 classes seems like a good size, so 100M assumes around 1K + // per klass. The vtable and oopMap is embedded so we don't have a fixed + // size per klass. Eventually, this will be parameterized because it + // would also be useful to determine the optimal size of the + // systemDictionary. + FLAG_SET_ERGO(uintx, ClassMetaspaceSize, 100*M); + } } } // Also checks that certain machines are slower with compressed oops @@ -1733,16 +1747,6 @@ return false; } -static void force_serial_gc() { - FLAG_SET_DEFAULT(UseSerialGC, true); - FLAG_SET_DEFAULT(UseParNewGC, false); - FLAG_SET_DEFAULT(UseConcMarkSweepGC, false); - FLAG_SET_DEFAULT(CMSIncrementalMode, false); // special CMS suboption - FLAG_SET_DEFAULT(UseParallelGC, false); - FLAG_SET_DEFAULT(UseParallelOldGC, false); - FLAG_SET_DEFAULT(UseG1GC, false); -} - static bool verify_serial_gc_flags() { return (UseSerialGC && !(UseParNewGC || (UseConcMarkSweepGC || CMSIncrementalMode) || UseG1GC || @@ -1892,6 +1896,24 @@ // Keeping the heap 100% free is hard ;-) so limit it to 99%. MinHeapFreeRatio = MIN2(MinHeapFreeRatio, (uintx) 99); + // Min/MaxMetaspaceFreeRatio + status = status && verify_percentage(MinMetaspaceFreeRatio, "MinMetaspaceFreeRatio"); + status = status && verify_percentage(MaxMetaspaceFreeRatio, "MaxMetaspaceFreeRatio"); + + if (MinMetaspaceFreeRatio > MaxMetaspaceFreeRatio) { + jio_fprintf(defaultStream::error_stream(), + "MinMetaspaceFreeRatio (%s" UINTX_FORMAT ") must be less than or " + "equal to MaxMetaspaceFreeRatio (%s" UINTX_FORMAT ")\n", + FLAG_IS_DEFAULT(MinMetaspaceFreeRatio) ? "Default: " : "", + MinMetaspaceFreeRatio, + FLAG_IS_DEFAULT(MaxMetaspaceFreeRatio) ? "Default: " : "", + MaxMetaspaceFreeRatio); + status = false; + } + + // Trying to keep 100% free is not practical + MinMetaspaceFreeRatio = MIN2(MinMetaspaceFreeRatio, (uintx) 99); + if (FullGCALot && FLAG_IS_DEFAULT(MarkSweepAlwaysCompactCount)) { MarkSweepAlwaysCompactCount = 1; // Move objects every gc. } @@ -1899,7 +1921,7 @@ if (UseParallelOldGC && ParallelOldGCSplitALot) { // Settings to encourage splitting. if (!FLAG_IS_CMDLINE(NewRatio)) { - FLAG_SET_CMDLINE(intx, NewRatio, 2); + FLAG_SET_CMDLINE(uintx, NewRatio, 2); } if (!FLAG_IS_CMDLINE(ScavengeBeforeFullGC)) { FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false); @@ -1994,7 +2016,7 @@ status = status && verify_min_value(ParGCArrayScanChunk, 1, "ParGCArrayScanChunk"); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseG1GC) { status = status && verify_percentage(InitiatingHeapOccupancyPercent, "InitiatingHeapOccupancyPercent"); @@ -2003,7 +2025,7 @@ status = status && verify_min_value((intx)G1ConcMarkStepDurationMillis, 1, "G1ConcMarkStepDurationMillis"); } -#endif +#endif // INCLUDE_ALL_GCS status = status && verify_interval(RefDiscoveryPolicy, ReferenceProcessor::DiscoveryPolicyMin, @@ -2048,18 +2070,28 @@ } #ifdef GRAAL if (UseCompressedOops) { - jio_fprintf(defaultStream::error_stream(), + if (IgnoreUnrecognizedVMOptions) { + warning("UseCompressedOops is disabled, because it is not supported by Graal"); + FLAG_SET_CMDLINE(bool, UseCompressedOops, false); + } else { + jio_fprintf(defaultStream::error_stream(), "CompressedOops are not supported in Graal at the moment\n"); - status = false; + status = false; + } } else { // This prevents the flag being set to true by set_ergonomics_flags() FLAG_SET_CMDLINE(bool, UseCompressedOops, false); } if (UseCompressedKlassPointers) { - jio_fprintf(defaultStream::error_stream(), + if (IgnoreUnrecognizedVMOptions) { + warning("UseCompressedKlassPointers is disabled, because it is not supported by Graal"); + FLAG_SET_CMDLINE(bool, UseCompressedKlassPointers, false); + } else { + jio_fprintf(defaultStream::error_stream(), "UseCompressedKlassPointers are not supported in Graal at the moment\n"); - status = false; + status = false; + } } else { // This prevents the flag being set to true by set_ergonomics_flags() FLAG_SET_CMDLINE(bool, UseCompressedKlassPointers, false); @@ -2150,58 +2182,6 @@ } // Parse JavaVMInitArgs structure -#ifdef GRAAL -static void prepend_to_graal_classpath(SysClassPath &cp, const char* path) { - cp.add_prefix(path); -} - -static void prepend_to_graal_classpath(SysClassPath &cp, const char* graal_dir, const char* project) { - const int BUFFER_SIZE = 1024; - char path[BUFFER_SIZE]; - - const char fileSep = *os::file_separator(); - sprintf(path, "%s%c%s%cbin", graal_dir, fileSep, project, fileSep); - - DIR* dir = os::opendir(path); - if (dir == NULL) { - jio_fprintf(defaultStream::output_stream(), "Error while starting Graal VM: The Graal class directory %s could not be opened.\n", path); - vm_exit(1); - } - os::closedir(dir); - prepend_to_graal_classpath(cp, path); -} - -// Walk up the directory hierarchy starting from JAVA_HOME looking -// for a directory named "graal". If found, then the full path to -// this directory is returned in graal_dir. -static bool find_graal_dir(char* graal_dir) { - strcpy(graal_dir, Arguments::get_java_home()); - char* end = graal_dir + strlen(graal_dir); - const char fileSep = *os::file_separator(); - while (end != graal_dir) { - if (fileSep == '/') - strcat(graal_dir, "/graal"); - else { - assert(fileSep == '\\', "unexpected separator char"); - strcat(graal_dir, "\\graal"); - } - DIR* dir = os::opendir(graal_dir); - if (dir != NULL) { - os::closedir(dir); - return true; - } - *end = 0; - while (end != graal_dir) { - if (*end == fileSep) { - *end = 0; - break; - } - end--; - } - } - return false; -} -#endif jint Arguments::parse_vm_init_args(const JavaVMInitArgs* args) { // For components of the system classpath. @@ -2229,72 +2209,6 @@ return result; } -#ifdef GRAAL - if (PrintVMOptions) { - tty->print_cr("Running Graal VM... "); - } - - SysClassPath scp_compiler(""); - - if (GraalClassPath != NULL) { - prepend_to_graal_classpath(scp_compiler, GraalClassPath); - } else { - const int BUFFER_SIZE = 1024; - char graal_dir[BUFFER_SIZE]; - if (!os::getenv("GRAAL", graal_dir, sizeof(graal_dir))) { - if (find_graal_dir(graal_dir) == false) { - jio_fprintf(defaultStream::output_stream(), "Error while starting Graal VM: The GRAAL environment variable needs to point to the directory containing the Graal projects.\n"); - vm_exit(0); - } - } - if (PrintVMOptions) tty->print_cr("GRAAL=%s", graal_dir); - - // this declaration is checked for correctness by 'mx build' - only - // modify its entries, not its name or shape - const char* graal_projects[] = { - #ifdef AMD64 - "com.oracle.graal.amd64", - "com.oracle.graal.asm.amd64", - "com.oracle.graal.lir.amd64", - "com.oracle.graal.compiler.amd64", - "com.oracle.graal.hotspot.amd64", - #endif - "com.oracle.graal.api.runtime", - "com.oracle.graal.api.meta", - "com.oracle.graal.api.code", - "com.oracle.graal.hotspot", - "com.oracle.graal.asm", - "com.oracle.graal.alloc", - "com.oracle.graal.word", - "com.oracle.graal.snippets", - "com.oracle.graal.compiler", - "com.oracle.graal.loop", - "com.oracle.graal.phases", - "com.oracle.graal.phases.common", - "com.oracle.graal.virtual", - "com.oracle.graal.nodes", - "com.oracle.graal.printer", - "com.oracle.graal.debug", - "com.oracle.graal.graph", - "com.oracle.graal.lir", - "com.oracle.graal.bytecode", - "com.oracle.graal.java" - }; - - const int len = sizeof(graal_projects) / sizeof(char*); - for (int i = 0; i < len; i++) { - if (PrintVMOptions) { - tty->print_cr("Adding project directory %s to bootclasspath", graal_projects[i]); - } - prepend_to_graal_classpath(scp_compiler, graal_dir, graal_projects[i]); - } - } - - scp_compiler.expand_endorsed(); - Arguments::set_compilerclasspath(scp_compiler.combined_path()); - -#endif - if (AggressiveOpts) { // Insert alt-rt.jar between user-specified bootclasspath // prefix and the default bootclasspath. os::set_boot_path() @@ -2310,19 +2224,6 @@ FREE_C_HEAP_ARRAY(char, altclasses_path, mtInternal); } - if (WhiteBoxAPI) { - // Append wb.jar to bootclasspath if enabled - const char* wb_jar = "wb.jar"; - size_t wb_path_len = strlen(get_meta_index_dir()) + 1 + - strlen(wb_jar); - char* wb_path = NEW_C_HEAP_ARRAY(char, wb_path_len, mtInternal); - strcpy(wb_path, get_meta_index_dir()); - strcat(wb_path, wb_jar); - scp.add_suffix(wb_path); - scp_assembly_required = true; - FREE_C_HEAP_ARRAY(char, wb_path, mtInternal); - } - // Parse _JAVA_OPTIONS environment variable (if present) (mimics classic VM) result = parse_java_options_environment_variable(&scp, &scp_assembly_required); if (result != JNI_OK) { @@ -2617,7 +2518,12 @@ } // Out of the box management support if (match_option(option, "-Dcom.sun.management", &tail)) { +#if INCLUDE_MANAGEMENT FLAG_SET_CMDLINE(bool, ManagementServer, true); +#else + vm_exit_during_initialization( + "-Dcom.sun.management is not supported in this VM.", NULL); +#endif } // -Xint } else if (match_option(option, "-Xint", &tail)) { @@ -2632,10 +2538,7 @@ // -Xshare:dump } else if (match_option(option, "-Xshare:dump", &tail)) { -#if defined(KERNEL) - vm_exit_during_initialization( - "Dumping a shared archive is not supported on the Kernel JVM.", NULL); -#elif !INCLUDE_CDS +#if !INCLUDE_CDS vm_exit_during_initialization( "Dumping a shared archive is not supported in this VM.", NULL); #else @@ -2966,6 +2869,11 @@ // away and will cause VM initialization failures! warning("-XX:+UseVMInterruptibleIO is obsolete and will be removed in a future release."); 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); +#endif // INCLUDE_MANAGEMENT } else if (match_option(option, "-XX:", &tail)) { // -XX:xxxx // Skip -XX:Flags= since that case has already been handled if (strncmp(tail, "Flags=", strlen("Flags=")) != 0) { @@ -3205,6 +3113,27 @@ } \ } while(0) + +#define UNSUPPORTED_GC_OPTION(gc) \ +do { \ + if (gc) { \ + if (FLAG_IS_CMDLINE(gc)) { \ + warning(#gc " is not supported in this VM. Using Serial GC."); \ + } \ + FLAG_SET_DEFAULT(gc, false); \ + } \ +} while(0) + +static void force_serial_gc() { + FLAG_SET_DEFAULT(UseSerialGC, true); + FLAG_SET_DEFAULT(CMSIncrementalMode, false); // special CMS suboption + UNSUPPORTED_GC_OPTION(UseG1GC); + UNSUPPORTED_GC_OPTION(UseParallelGC); + UNSUPPORTED_GC_OPTION(UseParallelOldGC); + UNSUPPORTED_GC_OPTION(UseConcMarkSweepGC); + UNSUPPORTED_GC_OPTION(UseParNewGC); +} + // Parse entry point called from JNI_CreateJavaVM jint Arguments::parse(const JavaVMInitArgs* args) { @@ -3320,28 +3249,15 @@ hotspotrc, hotspotrc); } -#if (defined JAVASE_EMBEDDED || defined ARM) - UNSUPPORTED_OPTION(UseG1GC, "G1 GC"); -#endif - #ifdef _ALLBSD_SOURCE // UseLargePages is not yet supported on BSD. UNSUPPORTED_OPTION(UseLargePages, "-XX:+UseLargePages"); #endif -#if !INCLUDE_ALTERNATE_GCS - if (UseParallelGC) { - warning("Parallel GC is not supported in this VM. Using Serial GC."); - } - if (UseParallelOldGC) { - warning("Parallel Old GC is not supported in this VM. Using Serial GC."); - } - if (UseConcMarkSweepGC) { - warning("Concurrent Mark Sweep GC is not supported in this VM. Using Serial GC."); - } - if (UseParNewGC) { - warning("Par New GC is not supported in this VM. Using Serial GC."); - } -#endif // INCLUDE_ALTERNATE_GCS +#if INCLUDE_ALL_GCS + #if (defined JAVASE_EMBEDDED || defined ARM) + UNSUPPORTED_OPTION(UseG1GC, "G1 GC"); + #endif +#endif #ifndef PRODUCT if (TraceBytecodesAt != 0) { @@ -3388,9 +3304,9 @@ // Set object alignment values. set_object_alignment(); -#ifdef SERIALGC +#if !INCLUDE_ALL_GCS force_serial_gc(); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #if !INCLUDE_CDS no_shared_spaces(); #endif // INCLUDE_CDS @@ -3418,7 +3334,7 @@ // Set heap size based on available physical memory set_heap_size(); -#if INCLUDE_ALTERNATE_GCS +#if INCLUDE_ALL_GCS // Set per-collector flags if (UseParallelGC || UseParallelOldGC) { set_parallel_gc_flags(); @@ -3430,11 +3346,9 @@ set_g1_gc_flags(); } check_deprecated_gcs(); -#endif // INCLUDE_ALTERNATE_GCS - -#ifdef SERIALGC +#else // INCLUDE_ALL_GCS assert(verify_serial_gc_flags(), "SerialGC unset"); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Set bytecode rewriting flags set_bytecode_flags(); @@ -3531,7 +3445,7 @@ } jint Arguments::adjust_after_os() { -#if INCLUDE_ALTERNATE_GCS +#if INCLUDE_ALL_GCS if (UseParallelGC || UseParallelOldGC) { if (UseNUMA) { if (FLAG_IS_DEFAULT(MinHeapDeltaBytes)) { @@ -3542,7 +3456,7 @@ UseNUMAInterleaving = true; } } -#endif +#endif // INCLUDE_ALL_GCS return JNI_OK; } @@ -3637,36 +3551,6 @@ PropertyList_add(plist, k, v); } -#ifdef KERNEL -char *Arguments::get_kernel_properties() { - // Find properties starting with kernel and append them to string - // We need to find out how long they are first because the URL's that they - // might point to could get long. - int length = 0; - SystemProperty* prop; - for (prop = _system_properties; prop != NULL; prop = prop->next()) { - if (strncmp(prop->key(), "kernel.", 7 ) == 0) { - length += (strlen(prop->key()) + strlen(prop->value()) + 5); // "-D =" - } - } - // Add one for null terminator. - char *props = AllocateHeap(length + 1, mtInternal); - if (length != 0) { - int pos = 0; - for (prop = _system_properties; prop != NULL; prop = prop->next()) { - if (strncmp(prop->key(), "kernel.", 7 ) == 0) { - jio_snprintf(&props[pos], length-pos, - "-D%s=%s ", prop->key(), prop->value()); - pos = strlen(props); - } - } - } - // null terminate props in case of null - props[length] = '\0'; - return props; -} -#endif // KERNEL - // Copies src into buf, replacing "%%" with "%" and "%p" with pid // Returns true if all of the source pointed by src has been copied over to // the destination buffer pointed by buf. Otherwise, returns false. diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/arguments.hpp --- a/src/share/vm/runtime/arguments.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/arguments.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -247,9 +247,6 @@ static SystemProperty *_java_home; static SystemProperty *_java_class_path; static SystemProperty *_sun_boot_class_path; -#ifdef GRAAL - static SystemProperty *_compiler_class_path; -#endif // Meta-index for knowing what packages are in the boot class path static char* _meta_index_path; @@ -537,9 +534,6 @@ static void set_ext_dirs(char *value) { _java_ext_dirs->set_value(value); } static void set_endorsed_dirs(char *value) { _java_endorsed_dirs->set_value(value); } static void set_sysclasspath(char *value) { _sun_boot_class_path->set_value(value); } -#ifdef GRAAL - static void set_compilerclasspath(char *value) { _compiler_class_path->set_value(value); } -#endif static void append_sysclasspath(const char *value) { _sun_boot_class_path->append_value(value); } static void set_meta_index_path(char* meta_index_path, char* meta_index_dir) { _meta_index_path = meta_index_path; @@ -550,9 +544,6 @@ static char *get_dll_dir() { return _sun_boot_library_path->value(); } static char *get_endorsed_dir() { return _java_endorsed_dirs->value(); } static char *get_sysclasspath() { return _sun_boot_class_path->value(); } -#ifdef GRAAL - static char *get_compilerclasspath() { return _compiler_class_path->value(); } -#endif static char* get_meta_index_path() { return _meta_index_path; } static char* get_meta_index_dir() { return _meta_index_dir; } @@ -561,11 +552,6 @@ // Utility: copies src into buf, replacing "%%" with "%" and "%p" with pid. static bool copy_expand_pid(const char* src, size_t srclen, char* buf, size_t buflen); - -#ifdef KERNEL - // For java kernel vm, return property string for kernel properties. - static char *get_kernel_properties(); -#endif // KERNEL }; #endif // SHARE_VM_RUNTIME_ARGUMENTS_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/atomic.hpp --- a/src/share/vm/runtime/atomic.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/atomic.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -29,10 +29,17 @@ class Atomic : AllStatic { public: + // Atomic operations on jlong types are not available on all 32-bit + // platforms. If atomic ops on jlongs are defined here they must only + // be used from code that verifies they are available at runtime and + // can provide an alternative action if not - see supports_cx8() for + // a means to test availability. + // Atomically store to a location inline static void store (jbyte store_value, jbyte* dest); inline static void store (jshort store_value, jshort* dest); inline static void store (jint store_value, jint* dest); + // See comment above about using jlong atomics on 32-bit platforms inline static void store (jlong store_value, jlong* dest); inline static void store_ptr(intptr_t store_value, intptr_t* dest); inline static void store_ptr(void* store_value, void* dest); @@ -40,17 +47,19 @@ inline static void store (jbyte store_value, volatile jbyte* dest); inline static void store (jshort store_value, volatile jshort* dest); inline static void store (jint store_value, volatile jint* dest); + // See comment above about using jlong atomics on 32-bit platforms inline static void store (jlong store_value, volatile jlong* dest); inline static void store_ptr(intptr_t store_value, volatile intptr_t* dest); inline static void store_ptr(void* store_value, volatile void* dest); + // See comment above about using jlong atomics on 32-bit platforms inline static jlong load(volatile jlong* src); // Atomically add to a location, return updated value inline static jint add (jint add_value, volatile jint* dest); inline static intptr_t add_ptr(intptr_t add_value, volatile intptr_t* dest); inline static void* add_ptr(intptr_t add_value, volatile void* dest); - + // See comment above about using jlong atomics on 32-bit platforms static jlong add (jlong add_value, volatile jlong* dest); // Atomically increment location @@ -75,6 +84,7 @@ // barrier across the cmpxchg. I.e., it's really a 'fence_cmpxchg_acquire'. static jbyte cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value); inline static jint cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value); + // See comment above about using jlong atomics on 32-bit platforms inline static jlong cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value); static unsigned int cmpxchg(unsigned int exchange_value, diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/basicLock.hpp --- a/src/share/vm/runtime/basicLock.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/basicLock.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -63,7 +63,6 @@ public: // Manipulation oop obj() const { return _obj; } - oop* obj_addr() { return &_obj; } void set_obj(oop obj) { _obj = obj; } BasicLock* lock() { return &_lock; } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/compilationPolicy.cpp --- a/src/share/vm/runtime/compilationPolicy.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/compilationPolicy.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -60,7 +60,7 @@ break; case 1: -#if defined(COMPILER2) +#ifdef COMPILER2 CompilationPolicy::set_policy(new StackWalkCompPolicy()); #else Unimplemented(); @@ -81,7 +81,7 @@ #endif break; case 4: -#if defined(GRAALVM) +#ifdef GRAALVM CompilationPolicy::set_policy(new GraalCompPolicy()); #else Unimplemented(); @@ -188,7 +188,6 @@ #endif #ifdef COMPILER1 - GRAALVM_ONLY(ShouldNotReachHere();) if (is_c1_compile(comp_level)) { return _compiler_count; } else { @@ -212,7 +211,6 @@ } void NonTieredCompPolicy::reset_counter_for_back_branch_event(methodHandle m) { -// GRAAL_ONLY(assert(false, "unexpected")); // Delay next back-branch event but pump up invocation counter to triger // whole method compilation. InvocationCounter* i = m->invocation_counter(); @@ -510,7 +508,7 @@ // StackWalkCompPolicy - walk up stack to find a suitable method to compile -#if defined(COMPILER2) +#ifdef COMPILER2 const char* StackWalkCompPolicy::_msg = NULL; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/compilationPolicy.hpp --- a/src/share/vm/runtime/compilationPolicy.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/compilationPolicy.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -126,7 +126,7 @@ // StackWalkCompPolicy - existing C2 policy -#if defined(COMPILER2) +#ifdef COMPILER2 class StackWalkCompPolicy : public NonTieredCompPolicy { public: virtual void method_invocation_event(methodHandle m, JavaThread* thread); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/deoptimization.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1312,24 +1312,14 @@ if (TraceDeoptimization) { tty->print_cr(" bci=%d pc=%d, relative_pc=%d, method=%s", trap_scope->bci(), fr.pc(), fr.pc() - nm->code_begin(), trap_scope->method()->name()->as_C_string()); -#ifdef GRAAL - if (thread->graal_deopt_info() != NULL) { - oop deopt_info = thread->graal_deopt_info(); - if (java_lang_String::is_instance(deopt_info)) { - char buf[O_BUFLEN]; - java_lang_String::as_utf8_string(deopt_info, buf, O_BUFLEN); - tty->print_cr("deopt info: %s", buf); - } else { - tty->print_cr("deopt info:"); - deopt_info->print(); - } - thread->set_graal_deopt_info(NULL); - } -#endif } methodHandle trap_method = trap_scope->method(); int trap_bci = trap_scope->bci(); + if (trap_bci == SynchronizationEntryBCI) { + trap_bci = 0; + Thread::current()->set_pending_monitorenter(true); + } Bytecodes::Code trap_bc = trap_method->java_code_at(trap_bci); if (trap_scope->rethrow_exception()) { @@ -1339,7 +1329,7 @@ GrowableArray* expressions = trap_scope->expressions(); guarantee(expressions != NULL, "must have exception to throw"); ScopeValue* topOfStack = expressions->top(); - Handle topOfStackObj = cvf->create_stack_value(topOfStack)->get_obj(); + Handle topOfStackObj = StackValue::create_stack_value(&fr, ®_map, topOfStack)->get_obj(); THREAD->set_pending_exception(topOfStackObj(), NULL, 0); } @@ -1637,7 +1627,7 @@ if (trap_method() == nm->method()) { make_not_compilable = true; } else { - trap_method->set_not_compilable(CompLevel_full_optimization); + trap_method->set_not_compilable(CompLevel_full_optimization, true, "overflow_recompile_count > PerBytecodeRecompilationCutoff"); // But give grace to the enclosing nm->method(). } } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/deoptimization.hpp --- a/src/share/vm/runtime/deoptimization.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/deoptimization.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -37,7 +37,7 @@ friend class VMStructs; public: - // What condition caused the deoptimization + // What condition caused the deoptimization? enum DeoptReason { Reason_many = -1, // indicates presence of several reasons Reason_none = 0, // indicates absence of a relevant deopt. @@ -85,7 +85,7 @@ // Note: Reason_RECORDED_LIMIT should be < 8 to fit into 3 bits of // DataLayout::trap_bits. This dependency is enforced indirectly // via asserts, to avoid excessive direct header-to-header dependencies. - // See Deoptimization::trap_state_reason and class DataLayout + // See Deoptimization::trap_state_reason and class DataLayout. }; // What action must be taken by the runtime? @@ -132,7 +132,7 @@ // executing in a particular CodeBlob if UseBiasedLocking is enabled static void revoke_biases_of_monitors(CodeBlob* cb); -//#ifdef COMPILER2 +#if defined(COMPILER2) || defined(GRAAL) // Support for restoring non-escaping objects static bool realloc_objects(JavaThread* thread, frame* fr, GrowableArray* objects, TRAPS); static void reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type); @@ -140,7 +140,7 @@ static void reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray* objects); static void relock_objects(GrowableArray* monitors, JavaThread* thread); NOT_PRODUCT(static void print_objects(GrowableArray* objects);) -//#endif // COMPILER2 +#endif // COMPILER2 || GRAAL public: static vframeArray* create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray* chunk); @@ -319,12 +319,11 @@ assert((1 << _reason_bits) >= Reason_LIMIT, "enough bits"); assert((1 << _action_bits) >= Action_LIMIT, "enough bits"); int trap_request; - if (index != -1) { + if (index != -1) trap_request = index; - } else { + else trap_request = (~(((reason) << _reason_shift) + ((action) << _action_shift))); - } assert(reason == trap_request_reason(trap_request), "valid reason"); assert(action == trap_request_action(trap_request), "valid action"); assert(index == trap_request_index(trap_request), "valid index"); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/fieldDescriptor.cpp --- a/src/share/vm/runtime/fieldDescriptor.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/fieldDescriptor.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,13 +67,10 @@ AnnotationArray* fieldDescriptor::type_annotations() const { InstanceKlass* ik = field_holder(); - Annotations* type_annos = ik->type_annotations(); + Array* type_annos = ik->fields_type_annotations(); if (type_annos == NULL) return NULL; - Array* md = type_annos->fields_annotations(); - if (md == NULL) - return NULL; - return md->at(index()); + return type_annos->at(index()); } constantTag fieldDescriptor::initial_value_tag() const { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/fieldDescriptor.hpp --- a/src/share/vm/runtime/fieldDescriptor.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/fieldDescriptor.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -25,10 +25,7 @@ #ifndef SHARE_VM_RUNTIME_FIELDDESCRIPTOR_HPP #define SHARE_VM_RUNTIME_FIELDDESCRIPTOR_HPP -#include "oops/annotations.hpp" #include "oops/constantPool.hpp" -#include "oops/fieldInfo.hpp" -#include "oops/instanceKlass.hpp" #include "oops/symbol.hpp" #include "runtime/fieldType.hpp" #include "utilities/accessFlags.hpp" diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/fprofiler.hpp --- a/src/share/vm/runtime/fprofiler.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/fprofiler.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -25,6 +25,7 @@ #ifndef SHARE_VM_RUNTIME_FPROFILER_HPP #define SHARE_VM_RUNTIME_FPROFILER_HPP +#include "utilities/macros.hpp" #include "runtime/timer.hpp" // a simple flat profiler for Java diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/frame.cpp --- a/src/share/vm/runtime/frame.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/frame.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -597,67 +597,44 @@ void frame::interpreter_frame_print_on(outputStream* st) const { #ifndef PRODUCT assert(is_interpreted_frame(), "Not an interpreted frame"); - assert(interpreter_frame_method() != NULL && interpreter_frame_method()->contains(interpreter_frame_bcp()), "must be"); jint i; - st->print_cr(" - sp = " INTPTR_FORMAT, sp()); - // expressions + for (i = 0; i < interpreter_frame_method()->max_locals(); i++ ) { + intptr_t x = *interpreter_frame_local_at(i); + st->print(" - local [" INTPTR_FORMAT "]", x); + st->fill_to(23); + st->print_cr("; #%d", i); + } for (i = interpreter_frame_expression_stack_size() - 1; i >= 0; --i ) { - intptr_t* x = interpreter_frame_expression_stack_at(i); - st->print(" - stack at " INTPTR_FORMAT " = " INTPTR_FORMAT, x, *x); - st->fill_to(70); + intptr_t x = *interpreter_frame_expression_stack_at(i); + st->print(" - stack [" INTPTR_FORMAT "]", x); + st->fill_to(23); st->print_cr("; #%d", i); } // locks for synchronization - st->print_cr(" - monitorend = " INTPTR_FORMAT, interpreter_frame_monitor_end()); for (BasicObjectLock* current = interpreter_frame_monitor_end(); current < interpreter_frame_monitor_begin(); current = next_monitor_in_interpreter_frame(current)) { - st->print (" - lock at " INTPTR_FORMAT " = ", current->lock()); + st->print(" - obj ["); + current->obj()->print_value_on(st); + st->print_cr("]"); + st->print(" - lock ["); current->lock()->print_on(st); - st->cr(); - st->print (" - obj at " INTPTR_FORMAT " = " INTPTR_FORMAT " ", current->obj_addr(), *current->obj_addr()); - current->obj()->print_value_on(st); - st->cr(); + st->print_cr("]"); } - st->print_cr(" - monitorbegin = " INTPTR_FORMAT, interpreter_frame_monitor_begin()); - - // bcp/bcx - st->print (" - bcp at " INTPTR_FORMAT " = " INTPTR_FORMAT, interpreter_frame_bcx_addr(), interpreter_frame_bcp()); - st->fill_to(70); - st->print_cr("; @%d - %s", interpreter_frame_bci(), Bytecodes::name(interpreter_frame_method()->code_at(interpreter_frame_bci()))); + // monitor + st->print_cr(" - monitor[" INTPTR_FORMAT "]", interpreter_frame_monitor_begin()); + // bcp + st->print(" - bcp [" INTPTR_FORMAT "]", interpreter_frame_bcp()); + st->fill_to(23); + st->print_cr("; @%d", interpreter_frame_bci()); // locals - st->print_cr(" - locals at " INTPTR_FORMAT " = " INTPTR_FORMAT, interpreter_frame_locals_addr(), *interpreter_frame_locals_addr()); - // constant pool cache - st->print_cr(" - constant pool at " INTPTR_FORMAT " = " INTPTR_FORMAT, interpreter_frame_cache_addr(), *interpreter_frame_cache_addr()); - // method data - st->print_cr(" - method data at " INTPTR_FORMAT " = " INTPTR_FORMAT, interpreter_frame_mdx_addr(), *interpreter_frame_mdx_addr()); + st->print_cr(" - locals [" INTPTR_FORMAT "]", interpreter_frame_local_at(0)); // method - st->print (" - method at " INTPTR_FORMAT " = " INTPTR_FORMAT, interpreter_frame_method_addr(), *interpreter_frame_method_addr()); - st->fill_to(70); + st->print(" - method [" INTPTR_FORMAT "]", (address)interpreter_frame_method()); + st->fill_to(23); st->print("; "); interpreter_frame_method()->print_name(st); st->cr(); -#ifdef AMD64 - // last sp - st->print_cr(" - last sp at " INTPTR_FORMAT " = " INTPTR_FORMAT, interpreter_frame_last_sp_addr(), *interpreter_frame_last_sp_addr()); -#endif - // sender sp - st->print_cr(" - sender sp at " INTPTR_FORMAT " = " INTPTR_FORMAT, interpreter_frame_sender_sp_addr(), *interpreter_frame_sender_sp_addr()); - // old fp - st->print_cr(" - old fp at " INTPTR_FORMAT " = " INTPTR_FORMAT, link_addr(), *link_addr()); - // return address - st->print_cr(" - return pc at " INTPTR_FORMAT " = " INTPTR_FORMAT, sender_pc_addr(), *sender_pc_addr()); - - // locals - for (i = interpreter_frame_method()->max_locals() - 1; i >= 0; i--) { - intptr_t* x = interpreter_frame_local_at(i); - st->print (" - local at " INTPTR_FORMAT " = " INTPTR_FORMAT, x, *x); - st->fill_to(70); - st->print_cr("; #%d", i); - } - - // fp - st->print_cr(" - fp = " INTPTR_FORMAT, fp()); #endif } @@ -735,9 +712,8 @@ } else if (_cb->is_nmethod()) { Method* m = ((nmethod *)_cb)->method(); if (m != NULL) { - address code = _cb->code_begin(); m->name_and_sig_as_C_string(buf, buflen); - st->print("J %s [" PTR_FORMAT "+%d]", buf, code, pc() - code); + st->print("J %s", buf); } else { st->print("J " PTR_FORMAT, pc()); } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/frame.hpp --- a/src/share/vm/runtime/frame.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/frame.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -204,11 +204,9 @@ public: // Link (i.e., the pointer to the previous frame) intptr_t* link() const; - intptr_t** link_addr() const; void set_link(intptr_t* addr); // Return address - address* sender_pc_addr() const; address sender_pc() const; // Support for deoptimization @@ -305,7 +303,6 @@ jint interpreter_frame_expression_stack_size() const; intptr_t* interpreter_frame_sender_sp() const; - intptr_t** interpreter_frame_sender_sp_addr() const; #ifndef CC_INTERP // template based interpreter deoptimization support diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/globals.cpp --- a/src/share/vm/runtime/globals.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/globals.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,10 +29,11 @@ #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" #include "utilities/ostream.hpp" +#include "utilities/macros.hpp" #include "utilities/top.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1_globals.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 #include "c1/c1_globals.hpp" #endif @@ -71,7 +72,10 @@ } bool Flag::is_unlocked() const { - if (strcmp(kind, "{diagnostic}") == 0) { + if (strcmp(kind, "{diagnostic}") == 0 || + strcmp(kind, "{C2 diagnostic}") == 0 || + strcmp(kind, "{ARCH diagnostic}") == 0 || + strcmp(kind, "{Shark diagnostic}") == 0) { if (strcmp(name, "EnableInvokeDynamic") == 0 && UnlockExperimentalVMOptions && !UnlockDiagnosticVMOptions) { // transitional logic to allow tests to run until they are changed static int warned; @@ -80,7 +84,9 @@ } return UnlockDiagnosticVMOptions; } else if (strcmp(kind, "{experimental}") == 0 || - strcmp(kind, "{C2 experimental}") == 0) { + strcmp(kind, "{C2 experimental}") == 0 || + strcmp(kind, "{ARCH experimental}") == 0 || + strcmp(kind, "{Shark experimental}") == 0) { return UnlockExperimentalVMOptions; } else { return is_unlocked_ext(); @@ -271,9 +277,9 @@ static Flag flagTable[] = { RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, RUNTIME_PD_DEVELOP_FLAG_STRUCT, RUNTIME_PRODUCT_FLAG_STRUCT, RUNTIME_PD_PRODUCT_FLAG_STRUCT, RUNTIME_DIAGNOSTIC_FLAG_STRUCT, RUNTIME_EXPERIMENTAL_FLAG_STRUCT, RUNTIME_NOTPRODUCT_FLAG_STRUCT, RUNTIME_MANAGEABLE_FLAG_STRUCT, RUNTIME_PRODUCT_RW_FLAG_STRUCT, RUNTIME_LP64_PRODUCT_FLAG_STRUCT) RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, RUNTIME_PD_DEVELOP_FLAG_STRUCT, RUNTIME_PRODUCT_FLAG_STRUCT, RUNTIME_PD_PRODUCT_FLAG_STRUCT, RUNTIME_DIAGNOSTIC_FLAG_STRUCT, RUNTIME_NOTPRODUCT_FLAG_STRUCT) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS G1_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, RUNTIME_PD_DEVELOP_FLAG_STRUCT, RUNTIME_PRODUCT_FLAG_STRUCT, RUNTIME_PD_PRODUCT_FLAG_STRUCT, RUNTIME_DIAGNOSTIC_FLAG_STRUCT, RUNTIME_EXPERIMENTAL_FLAG_STRUCT, RUNTIME_NOTPRODUCT_FLAG_STRUCT, RUNTIME_MANAGEABLE_FLAG_STRUCT, RUNTIME_PRODUCT_RW_FLAG_STRUCT) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, C1_PD_DEVELOP_FLAG_STRUCT, C1_PRODUCT_FLAG_STRUCT, C1_PD_PRODUCT_FLAG_STRUCT, C1_NOTPRODUCT_FLAG_STRUCT) #endif diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/globals.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1218,9 +1218,6 @@ notproduct(bool, TraceJVMCalls, false, \ "Trace JVM calls") \ \ - product(bool, TraceSignals, false, \ - "Trace signals and implicit exception handling") \ - \ product(ccstr, TraceJVMTI, NULL, \ "Trace flags for JVMTI functions and events") \ \ @@ -1252,7 +1249,7 @@ develop(bool, TraceClassInitialization, false, \ "Trace class initialization") \ \ - product(bool, TraceExceptions, false, \ + develop(bool, TraceExceptions, false, \ "Trace exceptions") \ \ develop(bool, TraceICs, false, \ @@ -1822,7 +1819,7 @@ product(bool, ParallelRefProcBalancingEnabled, true, \ "Enable balancing of reference processing queues") \ \ - product(intx, CMSTriggerRatio, 80, \ + product(uintx, CMSTriggerRatio, 80, \ "Percentage of MinHeapFreeRatio in CMS generation that is " \ "allocated before a CMS collection cycle commences") \ \ @@ -1836,7 +1833,7 @@ \ product(uintx, InitiatingHeapOccupancyPercent, 45, \ "Percentage of the (entire) heap occupancy to start a " \ - "concurrent GC cycle. It us used by GCs that trigger a " \ + "concurrent GC cycle. It is used by GCs that trigger a " \ "concurrent GC cycle based on the occupancy of the entire heap, " \ "not just one of the generations (e.g., G1). A value of 0 " \ "denotes 'do constant GC cycles'.") \ @@ -2621,9 +2618,6 @@ diagnostic(bool, PrintInterpreter, false, \ "Prints the generated interpreter code") \ \ - product(bool, PrintMachineCodeToFile, false, \ - "Prints the generated machine code to a file (int + comp)") \ - \ product(bool, UseInterpreter, true, \ "Use interpreter for non-compiled methods") \ \ @@ -3003,10 +2997,10 @@ product(uintx, TLABWasteIncrement, 4, \ "Increment allowed waste at slow allocation") \ \ - product(intx, SurvivorRatio, 8, \ + product(uintx, SurvivorRatio, 8, \ "Ratio of eden/survivor space size") \ \ - product(intx, NewRatio, 2, \ + product(uintx, NewRatio, 2, \ "Ratio of new/old generation sizes") \ \ product_pd(uintx, NewSizeThreadIncrease, \ @@ -3036,10 +3030,16 @@ "Min change in heap space due to GC (in bytes)") \ \ product(uintx, MinMetaspaceExpansion, ScaleForWordSize(256*K), \ - "Min expansion of permanent heap (in bytes)") \ + "Min expansion of Metaspace (in bytes)") \ + \ + product(uintx, MinMetaspaceFreeRatio, 40, \ + "Min percentage of Metaspace free after GC to avoid expansion") \ + \ + product(uintx, MaxMetaspaceFreeRatio, 70, \ + "Max percentage of Metaspace free after GC to avoid shrinking") \ \ product(uintx, MaxMetaspaceExpansion, ScaleForWordSize(4*M), \ - "Max expansion of permanent heap without full GC (in bytes)") \ + "Max expansion of Metaspace without full GC (in bytes)") \ \ product(intx, QueuedAllocationWarningCount, 0, \ "Number of times an allocation that queues behind a GC " \ @@ -3057,7 +3057,7 @@ product(uintx, InitialTenuringThreshold, 7, \ "Initial value for tenuring threshold") \ \ - product(intx, TargetSurvivorRatio, 50, \ + product(uintx, TargetSurvivorRatio, 50, \ "Desired percentage of survivor space used after scavenge") \ \ product(uintx, MarkSweepDeadRatio, 5, \ @@ -3588,7 +3588,7 @@ product(uintx, SharedDummyBlockSize, 0, \ "Size of dummy block used to shift heap addresses (in bytes)") \ \ - diagnostic(bool, EnableInvokeDynamic, false, \ + diagnostic(bool, EnableInvokeDynamic, true, \ "support JSR 292 (method handles, invokedynamic, " \ "anonymous classes") \ \ diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/globals_extension.hpp --- a/src/share/vm/runtime/globals_extension.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/globals_extension.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -26,6 +26,7 @@ #define SHARE_VM_RUNTIME_GLOBALS_EXTENSION_HPP #include "runtime/globals.hpp" +#include "utilities/macros.hpp" #include "utilities/top.hpp" // Construct enum of Flag_ constants. @@ -106,9 +107,9 @@ typedef enum { RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, RUNTIME_PD_DEVELOP_FLAG_MEMBER, RUNTIME_PRODUCT_FLAG_MEMBER, RUNTIME_PD_PRODUCT_FLAG_MEMBER, RUNTIME_DIAGNOSTIC_FLAG_MEMBER, RUNTIME_EXPERIMENTAL_FLAG_MEMBER, RUNTIME_NOTPRODUCT_FLAG_MEMBER, RUNTIME_MANAGEABLE_FLAG_MEMBER, RUNTIME_PRODUCT_RW_FLAG_MEMBER, RUNTIME_LP64_PRODUCT_FLAG_MEMBER) RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, RUNTIME_PD_DEVELOP_FLAG_MEMBER, RUNTIME_PRODUCT_FLAG_MEMBER, RUNTIME_PD_PRODUCT_FLAG_MEMBER, RUNTIME_DIAGNOSTIC_FLAG_MEMBER, RUNTIME_NOTPRODUCT_FLAG_MEMBER) -#if INCLUDE_ALTERNATE_GCS +#if INCLUDE_ALL_GCS G1_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, RUNTIME_PD_DEVELOP_FLAG_MEMBER, RUNTIME_PRODUCT_FLAG_MEMBER, RUNTIME_PD_PRODUCT_FLAG_MEMBER, RUNTIME_DIAGNOSTIC_FLAG_MEMBER, RUNTIME_EXPERIMENTAL_FLAG_MEMBER, RUNTIME_NOTPRODUCT_FLAG_MEMBER, RUNTIME_MANAGEABLE_FLAG_MEMBER, RUNTIME_PRODUCT_RW_FLAG_MEMBER) -#endif // INCLUDE_ALTERNATE_GCS +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 C1_FLAGS(C1_DEVELOP_FLAG_MEMBER, C1_PD_DEVELOP_FLAG_MEMBER, C1_PRODUCT_FLAG_MEMBER, C1_PD_PRODUCT_FLAG_MEMBER, C1_NOTPRODUCT_FLAG_MEMBER) #endif @@ -213,7 +214,7 @@ RUNTIME_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE, RUNTIME_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE, RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE) -#if INCLUDE_ALTERNATE_GCS +#if INCLUDE_ALL_GCS G1_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE, RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE, RUNTIME_PRODUCT_FLAG_MEMBER_WITH_TYPE, @@ -223,7 +224,7 @@ RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE, RUNTIME_MANAGEABLE_FLAG_MEMBER_WITH_TYPE, RUNTIME_PRODUCT_RW_FLAG_MEMBER_WITH_TYPE) -#endif // INCLUDE_ALTERNATE_GCS +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 C1_FLAGS(C1_DEVELOP_FLAG_MEMBER_WITH_TYPE, C1_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE, diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/init.cpp --- a/src/share/vm/runtime/init.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/init.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -34,7 +34,7 @@ #include "runtime/init.hpp" #include "runtime/safepoint.hpp" #include "runtime/sharedRuntime.hpp" -#include "utilities/machineCodePrinter.hpp" +#include "utilities/macros.hpp" // Initialization done by VM thread in vm_init_globals() void check_ThreadShadow(); @@ -87,10 +87,6 @@ mutex_init(); chunkpool_init(); perfMemory_init(); - - if(PrintMachineCodeToFile) { - MachineCodePrinter::initialize(); - } } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/java.cpp --- a/src/share/vm/runtime/java.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/java.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -67,6 +67,7 @@ #include "utilities/dtrace.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/histogram.hpp" +#include "utilities/macros.hpp" #include "utilities/vmError.hpp" #ifdef TARGET_ARCH_x86 # include "vm_version_x86.hpp" @@ -83,11 +84,11 @@ #ifdef TARGET_ARCH_ppc # include "vm_version_ppc.hpp" #endif -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 #include "c1/c1_Compiler.hpp" #include "c1/c1_Runtime1.hpp" @@ -248,13 +249,10 @@ Runtime1::print_statistics(); Deoptimization::print_statistics(); SharedRuntime::print_statistics(); + nmethod::print_statistics(); } #endif /* COMPILER1 */ - if(PrintNMethodStatistics) { - nmethod::print_statistics(); - } - #ifdef COMPILER2 if ((PrintOptoStatistics || LogVMOutput || LogCompilation) && UseCompiler) { FlagSetting fs(DisplayVMOutput, DisplayVMOutput && PrintOptoStatistics); @@ -375,10 +373,6 @@ CompileBroker::print_times(); } - if(PrintNMethodStatistics) { - nmethod::print_statistics(); - } - if (PrintCodeCache) { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); CodeCache::print(); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/javaCalls.cpp --- a/src/share/vm/runtime/javaCalls.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/javaCalls.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -39,21 +39,7 @@ #include "runtime/mutexLocker.hpp" #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" -#ifdef HIGH_LEVEL_INTERPRETER -# include "graal/graalVMToInterpreter.hpp" -#endif -#ifdef TARGET_OS_FAMILY_linux -# include "thread_linux.inline.hpp" -#endif -#ifdef TARGET_OS_FAMILY_solaris -# include "thread_solaris.inline.hpp" -#endif -#ifdef TARGET_OS_FAMILY_windows -# include "thread_windows.inline.hpp" -#endif -#ifdef TARGET_OS_FAMILY_bsd -# include "thread_bsd.inline.hpp" -#endif +#include "runtime/thread.inline.hpp" // ----------------------------------------------------- // Implementation of JavaCallWrapper @@ -335,19 +321,10 @@ assert(THREAD->is_Java_thread(), "only JavaThreads can make JavaCalls"); // Need to wrap each and everytime, since there might be native code down the // stack that has installed its own exception handlers - os::os_exception_wrapper(call_helper, result, &method, NULL, args, THREAD); + os::os_exception_wrapper(call_helper, result, &method, args, THREAD); } -void JavaCalls::call(JavaValue* result, methodHandle method, nmethod* nm, JavaCallArguments* args, TRAPS) { - // Check if we need to wrap a potential OS exception handler around thread - // This is used for e.g. Win32 structured exception handlers - assert(THREAD->is_Java_thread(), "only JavaThreads can make JavaCalls"); - // Need to wrap each and everytime, since there might be native code down the - // stack that has installed its own exception handlers - os::os_exception_wrapper(call_helper, result, &method, nm, args, THREAD); -} - -void JavaCalls::call_helper(JavaValue* result, methodHandle* m, nmethod* nm, JavaCallArguments* args, TRAPS) { +void JavaCalls::call_helper(JavaValue* result, methodHandle* m, JavaCallArguments* args, TRAPS) { methodHandle method = *m; JavaThread* thread = (JavaThread*)THREAD; assert(thread->is_Java_thread(), "must be called by a java thread"); @@ -373,6 +350,7 @@ } #endif + #ifdef ASSERT { InstanceKlass* holder = method->method_holder(); // A klass might not be initialized since JavaCall's might be used during the executing of @@ -427,26 +405,18 @@ os::bang_stack_shadow_pages(); } +#ifdef GRAAL + nmethod* nm = args->alternative_target(); if (nm != NULL) { -#ifdef GRAAL if (nm->is_alive()) { ((JavaThread*) THREAD)->set_graal_alternate_call_target(nm->verified_entry_point()); entry_point = method->adapter()->get_i2c_entry(); } else { THROW(vmSymbols::MethodInvalidatedException()); } -#else - ShouldNotReachHere(); + } #endif - } -#ifdef HIGH_LEVEL_INTERPRETER - if (thread->high_level_interpreter_in_vm() && !method->is_native() && Interpreter::contains(entry_point)) { - assert(nm == NULL || !nm->is_alive(), "otherwise nm should be invoked"); - VMToInterpreter::execute(result, m, args, result->get_type(), thread); - oop_result_flag = false; // result already holds the correct value - } else -#endif // do call { JavaCallWrapper link(method, receiver, result, CHECK); { HandleMark hm(thread); // HandleMark used by HandleMarkCleaner @@ -482,6 +452,7 @@ } } + //-------------------------------------------------------------------------------------- // Implementation of JavaCallArguments diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/javaCalls.hpp --- a/src/share/vm/runtime/javaCalls.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/javaCalls.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -98,6 +98,9 @@ int _size; int _max_size; bool _start_at_zero; // Support late setting of receiver +#ifdef GRAAL + nmethod* _alternative_target; // Nmethod that should be called instead of normal target +#endif void initialize() { // Starts at first element to support set_receiver. @@ -107,6 +110,7 @@ _max_size = _default_size; _size = 0; _start_at_zero = false; + GRAAL_ONLY(_alternative_target = NULL;) } public: @@ -128,11 +132,22 @@ _max_size = max_size; _size = 0; _start_at_zero = false; + GRAAL_ONLY(_alternative_target = NULL;) } else { initialize(); } } +#ifdef GRAAL + void set_alternative_target(nmethod* target) { + _alternative_target = target; + } + + nmethod* alternative_target() { + return _alternative_target; + } +#endif + inline void push_oop(Handle h) { _is_oop[_size] = true; JNITypes::put_obj((oop)h.raw_value(), _value, _size); } @@ -148,12 +163,6 @@ inline void push_float(float f) { _is_oop[_size] = false; JNITypes::put_float(f, _value, _size); } - inline oop* get_raw_oop(int& pos) { return (oop*)JNITypes::get_obj(_value, pos); } - inline jint get_int(int& pos) { return JNITypes::get_int(_value, pos); } - inline jdouble get_double(int& pos) { return JNITypes::get_double(_value, pos); } - inline jlong get_long(int& pos) { return JNITypes::get_long(_value, pos); } - inline jfloat get_float(int& pos) { return JNITypes::get_float(_value, pos); } - // receiver Handle receiver() { assert(_size > 0, "must at least be one argument"); @@ -185,8 +194,8 @@ // class JavaCalls: AllStatic { - static void call_helper(JavaValue* result, methodHandle* method, nmethod* nm, JavaCallArguments* args, TRAPS); -public: + static void call_helper(JavaValue* result, methodHandle* method, JavaCallArguments* args, TRAPS); + public: // Optimized Constuctor call static void call_default_constructor(JavaThread* thread, methodHandle method, Handle receiver, TRAPS); @@ -225,7 +234,6 @@ // Low-level interface static void call(JavaValue* result, methodHandle method, JavaCallArguments* args, TRAPS); - static void call(JavaValue* result, methodHandle method, nmethod* nm, JavaCallArguments* args, TRAPS); }; #endif // SHARE_VM_RUNTIME_JAVACALLS_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/os.cpp --- a/src/share/vm/runtime/os.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/os.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -985,15 +985,28 @@ // if C stack is walkable beyond current frame. The check for fp() is not // necessary on Sparc, but it's harmless. bool os::is_first_C_frame(frame* fr) { -#ifdef IA64 - // In order to walk native frames on Itanium, we need to access the unwind - // table, which is inside ELF. We don't want to parse ELF after fatal error, - // so return true for IA64. If we need to support C stack walking on IA64, - // this function needs to be moved to CPU specific files, as fp() on IA64 - // is register stack, which grows towards higher memory address. +#if defined(IA64) && !defined(_WIN32) + // On IA64 we have to check if the callers bsp is still valid + // (i.e. within the register stack bounds). + // Notice: this only works for threads created by the VM and only if + // we walk the current stack!!! If we want to be able to walk + // arbitrary other threads, we'll have to somehow store the thread + // object in the frame. + Thread *thread = Thread::current(); + if ((address)fr->fp() <= + thread->register_stack_base() HPUX_ONLY(+ 0x0) LINUX_ONLY(+ 0x50)) { + // This check is a little hacky, because on Linux the first C + // frame's ('start_thread') register stack frame starts at + // "register_stack_base + 0x48" while on HPUX, the first C frame's + // ('__pthread_bound_body') register stack frame seems to really + // start at "register_stack_base". + return true; + } else { + return false; + } +#elif defined(IA64) && defined(_WIN32) return true; -#endif - +#else // Load up sp, fp, sender sp and sender fp, check for reasonable values. // Check usp first, because if that's bad the other accessors may fault // on some architectures. Ditto ufp second, etc. @@ -1023,6 +1036,7 @@ if (old_fp - ufp > 64 * K) return true; return false; +#endif } #ifdef ASSERT @@ -1135,6 +1149,9 @@ #ifdef __APPLE__ "%/lib/JObjC.jar:" #endif +#ifdef GRAAL + "%/lib/graal.jar:" +#endif "%/classes"; char* sysclasspath = format_boot_path(classpath_format, home, home_len, fileSep, pathSep); if (sysclasspath == NULL) return false; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/os.hpp --- a/src/share/vm/runtime/os.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/os.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -79,7 +79,7 @@ }; // Typedef for structured exception handling support -typedef void (*java_call_t)(JavaValue* value, methodHandle* method, nmethod* nm, JavaCallArguments* args, Thread* thread); +typedef void (*java_call_t)(JavaValue* value, methodHandle* method, JavaCallArguments* args, Thread* thread); class os: AllStatic { public: @@ -658,7 +658,7 @@ static void init_random(long initval); // initialize random sequence // Structured OS Exception support - static void os_exception_wrapper(java_call_t f, JavaValue* value, methodHandle* method, nmethod* nm, JavaCallArguments* args, Thread* thread); + static void os_exception_wrapper(java_call_t f, JavaValue* value, methodHandle* method, JavaCallArguments* args, Thread* thread); // On Windows this will create an actual minidump, on Linux/Solaris it will simply check core dump limits static void check_or_create_dump(void* exceptionRecord, void* contextRecord, char* buffer, size_t bufferSize); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/reflectionUtils.cpp --- a/src/share/vm/runtime/reflectionUtils.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/reflectionUtils.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -26,9 +26,6 @@ #include "classfile/javaClasses.hpp" #include "memory/universe.inline.hpp" #include "runtime/reflectionUtils.hpp" -#ifdef GRAAL -#include "graal/graalJavaAccess.hpp" -#endif KlassStream::KlassStream(instanceKlassHandle klass, bool local_only, bool classes_only) { _klass = klass; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/safepoint.cpp --- a/src/share/vm/runtime/safepoint.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/safepoint.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -52,6 +52,7 @@ #include "services/memTracker.hpp" #include "services/runtimeService.hpp" #include "utilities/events.hpp" +#include "utilities/macros.hpp" #ifdef TARGET_ARCH_x86 # include "nativeInst_x86.hpp" # include "vmreg_x86.inline.hpp" @@ -72,16 +73,13 @@ # include "nativeInst_ppc.hpp" # include "vmreg_ppc.inline.hpp" #endif -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp" #include "gc_implementation/shared/concurrentGCThread.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 #include "c1/c1_globals.hpp" #endif -#ifdef GRAAL -#include "graal/graalGlobals.hpp" -#endif // -------------------------------------------------------------------------------------------------- // Implementation of Safepoint begin/end @@ -106,7 +104,7 @@ _ts_of_current_safepoint = tty->time_stamp().seconds(); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseConcMarkSweepGC) { // In the future we should investigate whether CMS can use the // more-general mechanism below. DLD (01/05). @@ -114,7 +112,7 @@ } else if (UseG1GC) { ConcurrentGCThread::safepoint_synchronize(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // By getting the Threads_lock, we assure that no threads are about to start or // exit. It is released again in SafepointSynchronize::end(). @@ -483,14 +481,14 @@ Threads_lock->unlock(); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // If there are any concurrent GC threads resume them. if (UseConcMarkSweepGC) { ConcurrentMarkSweepThread::desynchronize(false); } else if (UseG1GC) { ConcurrentGCThread::safepoint_desynchronize(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // record this time so VMThread can keep track how much time has elasped // since last safepoint. _end_of_last_safepoint = os::javaTimeMillis(); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/sharedRuntime.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -56,6 +56,7 @@ #include "utilities/dtrace.hpp" #include "utilities/events.hpp" #include "utilities/hashtable.inline.hpp" +#include "utilities/macros.hpp" #include "utilities/xmlstream.hpp" #ifdef TARGET_ARCH_x86 # include "nativeInst_x86.hpp" @@ -212,7 +213,7 @@ } #endif // PRODUCT -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // G1 write-barrier pre: executed before a pointer store. JRT_LEAF(void, SharedRuntime::g1_wb_pre(oopDesc* orig, JavaThread *thread)) @@ -230,7 +231,7 @@ thread->dirty_card_queue().enqueue(card_addr); JRT_END -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS JRT_LEAF(jlong, SharedRuntime::lmul(jlong y, jlong x)) @@ -772,11 +773,8 @@ #ifdef GRAAL address SharedRuntime::deoptimize_for_implicit_exception(JavaThread* thread, address pc, nmethod* nm, int deopt_reason) { assert(deopt_reason > Deoptimization::Reason_none && deopt_reason < Deoptimization::Reason_LIMIT, "invalid deopt reason"); - if (TraceSignals) { - tty->print_cr(err_msg("Deoptimizing on implicit exception at relative pc=%d in method %s", pc - nm->entry_point(), nm->method()->name()->as_C_string())); - } thread->_ScratchA = (intptr_t)pc; - thread->_ScratchB = Deoptimization::make_trap_request((Deoptimization::DeoptReason)deopt_reason, Deoptimization::Action_reinterpret); + thread->set_pending_deoptimization(Deoptimization::make_trap_request((Deoptimization::DeoptReason)deopt_reason, Deoptimization::Action_reinterpret)); return (SharedRuntime::deopt_blob()->implicit_exception_uncommon_trap()); } #endif @@ -898,9 +896,6 @@ #endif #ifdef GRAAL if (nm->is_compiled_by_graal()) { - if (TraceSignals) { - tty->print_cr("Graal implicit div0"); - } target_pc = deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_div0_check); } else { #endif @@ -2868,10 +2863,6 @@ JRT_LEAF(intptr_t*, SharedRuntime::OSR_migration_begin( JavaThread *thread) ) -#ifdef IA64 - ShouldNotReachHere(); // NYI -#endif /* IA64 */ - // // This code is dependent on the memory layout of the interpreter local // array and the monitors. On all of our platforms the layout is identical diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/sharedRuntime.hpp --- a/src/share/vm/runtime/sharedRuntime.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/sharedRuntime.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -32,6 +32,7 @@ #include "memory/resourceArea.hpp" #include "runtime/threadLocalStorage.hpp" #include "utilities/hashtable.hpp" +#include "utilities/macros.hpp" class AdapterHandlerEntry; class AdapterHandlerTable; @@ -168,11 +169,11 @@ static address raw_exception_handler_for_return_address(JavaThread* thread, address return_address); static address exception_handler_for_return_address(JavaThread* thread, address return_address); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // G1 write barriers static void g1_wb_pre(oopDesc* orig, JavaThread *thread); static void g1_wb_post(void* card_addr, JavaThread* thread); -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS // exception handling and implicit exceptions static address compute_compiled_exc_handler(nmethod* nm, address ret_pc, Handle& exception, diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/stackValue.cpp --- a/src/share/vm/runtime/stackValue.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/stackValue.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -118,22 +118,6 @@ val = (oop)NULL; } #endif -#ifndef PRODUCT - if (val != NULL && !val->is_oop()) { - ResourceMark rm; - tty->print_cr("found wrong oop " INTPTR_FORMAT " at location " INTPTR_FORMAT " (%d):", val, value_addr, val->is_oop()); - if (fr->cb() != NULL) { - CodeBlob* cb = fr->cb(); - if (cb->is_nmethod()) { - nmethod* nm = (nmethod*)cb; - tty->print_cr("method is %s", nm->method()->name()->as_C_string()); - } - } - sv->print(); - tty->print_cr(""); - tty->print_cr("one less %d; one more %d", (*(((oop *)value_addr) - 1))->is_oop(), (*(((oop *)value_addr) + 1))->is_oop()); - } -#endif Handle h(val); // Wrap a handle around the oop return new StackValue(h); } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/synchronizer.cpp --- a/src/share/vm/runtime/synchronizer.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/synchronizer.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -53,7 +53,7 @@ # include "os_bsd.inline.hpp" #endif -#if defined(__GNUC__) && !defined(IA64) +#if defined(__GNUC__) // Need to inhibit inlining for older versions of GCC to avoid build-time failures #define ATTR __attribute__((noinline)) #else diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/thread.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,6 +85,7 @@ #include "utilities/dtrace.hpp" #include "utilities/events.hpp" #include "utilities/preserveException.hpp" +#include "utilities/macros.hpp" #ifdef TARGET_OS_FAMILY_linux # include "os_linux.inline.hpp" #endif @@ -97,11 +98,11 @@ #ifdef TARGET_OS_FAMILY_bsd # include "os_bsd.inline.hpp" #endif -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp" #include "gc_implementation/g1/concurrentMarkThread.inline.hpp" #include "gc_implementation/parallelScavenge/pcTasks.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 #include "c1/c1_Compiler.hpp" #endif @@ -1409,7 +1410,6 @@ // Set the claimed par_id to -1 (ie not claiming any par_ids) set_claimed_par_id(-1); - _env = NULL; _buffer_blob = NULL; set_saved_exception_pc(NULL); set_threadObj(NULL); @@ -1439,12 +1439,7 @@ _doing_unsafe_access = false; _stack_guard_state = stack_guard_unused; #ifdef GRAAL - _graal_deopt_info = NULL; _graal_alternate_call_target = NULL; - _debug_scope = NULL; -#endif -#ifdef HIGH_LEVEL_INTERPRETER - _high_level_interpreter_in_vm = false; #endif _exception_oop = NULL; _exception_pc = 0; @@ -1496,17 +1491,17 @@ pd_initialize(); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS SATBMarkQueueSet JavaThread::_satb_mark_queue_set; DirtyCardQueueSet JavaThread::_dirty_card_queue_set; -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS JavaThread::JavaThread(bool is_attaching_via_jni) : Thread() -#ifndef SERIALGC +#if INCLUDE_ALL_GCS , _satb_mark_queue(&_satb_mark_queue_set), _dirty_card_queue(&_dirty_card_queue_set) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS { initialize(); if (is_attaching_via_jni) { @@ -1514,7 +1509,7 @@ } else { _jni_attach_state = _not_attaching_via_jni; } - assert(_deferred_card_mark.is_empty(), "Default MemRegion ctor"); + assert(deferred_card_mark().is_empty(), "Default MemRegion ctor"); _safepoint_visible = false; } @@ -1561,10 +1556,10 @@ JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) : Thread() -#ifndef SERIALGC +#if INCLUDE_ALL_GCS , _satb_mark_queue(&_satb_mark_queue_set), _dirty_card_queue(&_dirty_card_queue_set) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS { if (TraceThreadEvents) { tty->print_cr("creating thread %p", this); @@ -1910,19 +1905,26 @@ JvmtiExport::cleanup_thread(this); } -#ifndef SERIALGC - // We must flush G1-related buffers before removing a thread from + // We must flush any deferred card marks before removing a thread from // the list of active threads. + Universe::heap()->flush_deferred_store_barrier(this); + assert(deferred_card_mark().is_empty(), "Should have been flushed"); + +#if INCLUDE_ALL_GCS + // We must flush the G1-related buffers before removing a thread + // from the list of active threads. We must do this after any deferred + // card marks have been flushed (above) so that any entries that are + // added to the thread's dirty card queue as a result are not lost. if (UseG1GC) { flush_barrier_queues(); } -#endif +#endif // INCLUDE_ALL_GCS // Remove from list of active threads list, and notify VM thread if we are the last non-daemon thread Threads::remove(this); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Flush G1-related queues. void JavaThread::flush_barrier_queues() { satb_mark_queue().flush(); @@ -1950,7 +1952,7 @@ // active field set to true. assert(dirty_queue.is_active(), "dirty card queue should be active"); } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS void JavaThread::cleanup_failed_attach_current_thread() { if (get_thread_profiler() != NULL) { @@ -1978,11 +1980,11 @@ tlab().make_parsable(true); // retire TLAB, if any } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseG1GC) { flush_barrier_queues(); } -#endif +#endif // INCLUDE_ALL_GCS Threads::remove(this); delete this; @@ -2187,9 +2189,7 @@ // Do not throw asynchronous exceptions against the compiler thread // (the compiler thread should not be a Java thread -- fix in 1.4.2) - - // (thomaswue) May we do this? - //if (is_Compiler_thread()) return; + if (is_Compiler_thread()) return; { // Actually throw the Throwable against the target Thread - however @@ -2776,9 +2776,6 @@ // around using this function f->do_oop((oop*) &_threadObj); f->do_oop((oop*) &_vm_result); -#ifdef GRAAL - f->do_oop((oop*) &_graal_deopt_info); -#endif f->do_oop((oop*) &_exception_oop); f->do_oop((oop*) &_pending_async_exception); @@ -3236,6 +3233,7 @@ // Create a CompilerThread CompilerThread::CompilerThread(CompileQueue* queue, CompilerCounters* counters) : JavaThread(&compiler_thread_entry) { + _env = NULL; _log = NULL; _task = NULL; _queue = queue; @@ -3613,7 +3611,7 @@ vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION)); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Support for ConcurrentMarkSweep. This should be cleaned up // and better encapsulated. The ugly nested if test would go away // once things are properly refactored. XXX YSR @@ -3627,7 +3625,7 @@ vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION)); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Always call even when there are not JVMTI environments yet, since environments // may be attached late and JVMTI must track phases of VM execution @@ -3752,28 +3750,6 @@ name)) { library = os::dll_load(buffer, ebuf, sizeof ebuf); } -#ifdef KERNEL - // Download instrument dll - if (library == NULL && strcmp(name, "instrument") == 0) { - char *props = Arguments::get_kernel_properties(); - char *home = Arguments::get_java_home(); - const char *fmt = "%s/bin/java %s -Dkernel.background.download=false" - " sun.jkernel.DownloadManager -download client_jvm"; - size_t length = strlen(props) + strlen(home) + strlen(fmt) + 1; - char *cmd = NEW_C_HEAP_ARRAY(char, length, mtThread); - jio_snprintf(cmd, length, fmt, home, props); - int status = os::fork_and_exec(cmd); - FreeHeap(props); - if (status == -1) { - warning(cmd); - vm_exit_during_initialization("fork_and_exec failed: %s", - strerror(errno)); - } - FREE_C_HEAP_ARRAY(char, cmd, mtThread); - // when this comes back the instrument.dll should be where it belongs. - library = os::dll_load(buffer, ebuf, sizeof ebuf); - } -#endif // KERNEL if (library == NULL) { // Try the local directory char ns[1] = {0}; if (os::dll_build_name(buffer, sizeof(buffer), ns, name)) { @@ -4222,7 +4198,7 @@ } } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Used by ParallelScavenge void Threads::create_thread_roots_tasks(GCTaskQueue* q) { ALL_JAVA_THREADS(p) { @@ -4238,7 +4214,7 @@ } q->enqueue(new ThreadRootsMarkingTask(VMThread::vm_thread())); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS void Threads::nmethods_do(CodeBlobClosure* cf) { ALL_JAVA_THREADS(p) { @@ -4346,13 +4322,13 @@ ); st->cr(); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Dump concurrent locks ConcurrentLocksDump concurrent_locks; if (print_concurrent_locks) { concurrent_locks.dump_at_safepoint(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS ALL_JAVA_THREADS(p) { ResourceMark rm; @@ -4365,11 +4341,11 @@ } } st->cr(); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (print_concurrent_locks) { concurrent_locks.print_locks_on(p, st); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } VMThread::vm_thread()->print_on(st); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/thread.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -41,6 +41,7 @@ #include "runtime/stubRoutines.hpp" #include "runtime/threadLocalStorage.hpp" #include "runtime/unhandledOops.hpp" +#include "utilities/macros.hpp" #if INCLUDE_NMT #include "services/memRecorder.hpp" @@ -49,10 +50,10 @@ #include "trace/tracing.hpp" #include "utilities/exceptions.hpp" #include "utilities/top.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/dirtyCardQueue.hpp" #include "gc_implementation/g1/satbQueue.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef ZERO #ifdef TARGET_ARCH_zero # include "stack_zero.hpp" @@ -768,13 +769,10 @@ JavaThread* _next; // The next thread in the Threads list oop _threadObj; // The Java level thread object - // (thomaswue) Necessary for holding a compilation buffer and ci environment. + // (thomaswue) Necessary for holding a compilation buffer. // Moved up from CompilerThread to JavaThread in order to enable code // installation from Java application code. BufferBlob* _buffer_blob; - ciEnv* _env; - bool _is_compiling; - #ifdef ASSERT private: int _java_call_counter; @@ -903,14 +901,8 @@ private: #ifdef GRAAL - volatile oop _graal_deopt_info; address _graal_alternate_call_target; - DebugScopedValue* _debug_scope; #endif -#ifdef HIGH_LEVEL_INTERPRETER - bool _high_level_interpreter_in_vm; -#endif - StackGuardState _stack_guard_state; nmethod* _scanned_nmethod; // nmethod being scanned by the sweeper @@ -923,6 +915,9 @@ volatile address _exception_handler_pc; // PC for handler of exception volatile int _is_method_handle_return; // true (== 1) if the current exception PC is a MethodHandle call site. + // support for compilation + bool _is_compiling; // is true if a compilation is active inthis thread (one compilation per thread possible) + // support for JNI critical regions jint _jni_active_critical; // count of entries into JNI critical region @@ -944,7 +939,7 @@ } _jmp_ring[ jump_ring_buffer_size ]; #endif /* PRODUCT */ -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Support for G1 barriers ObjPtrQueue _satb_mark_queue; // Thread-local log for SATB barrier. @@ -956,7 +951,7 @@ static DirtyCardQueueSet _dirty_card_queue_set; void flush_barrier_queues(); -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS friend class VMThread; friend class ThreadWaitTransition; @@ -982,13 +977,7 @@ struct JNINativeInterface_* get_jni_functions() { return (struct JNINativeInterface_ *)_jni_environment.functions; } - - bool is_compiling() const { return _is_compiling; } - void set_compiling(bool b) { _is_compiling = b; } - // Get/set the thread's compilation environment. - ciEnv* env() { return _env; } - void set_env(ciEnv* env) { _env = env; } BufferBlob* get_buffer_blob() { return _buffer_blob; } void set_buffer_blob(BufferBlob* b) { _buffer_blob = b; }; @@ -1018,6 +1007,10 @@ // Testers virtual bool is_Java_thread() const { return true; } + // compilation + void set_is_compiling(bool f) { _is_compiling = f; } + bool is_compiling() const { return _is_compiling; } + // Thread chain operations JavaThread* next() const { return _next; } void set_next(JavaThread* p) { _next = p; } @@ -1282,17 +1275,7 @@ void set_deferred_card_mark(MemRegion mr) { _deferred_card_mark = mr; } #ifdef GRAAL - oop graal_deopt_info() const { return _graal_deopt_info; } - void set_graal_deopt_info(oop o) { _graal_deopt_info = o; } - void set_graal_alternate_call_target(address a) { _graal_alternate_call_target = a; } - - DebugScopedValue* debug_scope() const { return _debug_scope; } - void set_debug_scope(DebugScopedValue* ds) { _debug_scope = ds; } -#endif -#ifdef HIGH_LEVEL_INTERPRETER - bool high_level_interpreter_in_vm() { return _high_level_interpreter_in_vm; } - void set_high_level_interpreter_in_vm(bool value) { _high_level_interpreter_in_vm = value; } #endif // Exception handling for compiled methods @@ -1375,12 +1358,8 @@ static ByteSize saved_exception_pc_offset() { return byte_offset_of(JavaThread, _saved_exception_pc ); } static ByteSize osthread_offset() { return byte_offset_of(JavaThread, _osthread ); } #ifdef GRAAL - static ByteSize graal_deopt_info_offset() { return byte_offset_of(JavaThread, _graal_deopt_info ); } static ByteSize graal_alternate_call_target_offset() { return byte_offset_of(JavaThread, _graal_alternate_call_target); } #endif -#ifdef HIGH_LEVEL_INTERPRETER - static ByteSize high_level_interpreter_in_vm_offset() { return byte_offset_of(JavaThread, _high_level_interpreter_in_vm); } -#endif static ByteSize exception_oop_offset() { return byte_offset_of(JavaThread, _exception_oop ); } static ByteSize exception_pc_offset() { return byte_offset_of(JavaThread, _exception_pc ); } static ByteSize exception_handler_pc_offset() { return byte_offset_of(JavaThread, _exception_handler_pc); } @@ -1393,10 +1372,10 @@ return byte_offset_of(JavaThread, _should_post_on_exceptions_flag); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS static ByteSize satb_mark_queue_offset() { return byte_offset_of(JavaThread, _satb_mark_queue); } static ByteSize dirty_card_queue_offset() { return byte_offset_of(JavaThread, _dirty_card_queue); } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS // Returns the jni environment for this thread JNIEnv* jni_environment() { return &_jni_environment; } @@ -1685,7 +1664,7 @@ _stack_size_at_create = value; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // SATB marking queue support ObjPtrQueue& satb_mark_queue() { return _satb_mark_queue; } static SATBMarkQueueSet& satb_mark_queue_set() { @@ -1697,7 +1676,7 @@ static DirtyCardQueueSet& dirty_card_queue_set() { return _dirty_card_queue_set; } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS // This method initializes the SATB and dirty card queues before a // JavaThread is added to the Java thread list. Right now, we don't @@ -1716,11 +1695,11 @@ // might happen between the JavaThread constructor being called and the // thread being added to the Java thread list (an example of this is // when the structure for the DestroyJavaVM thread is created). -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void initialize_queues(); -#else // !SERIALGC +#else // INCLUDE_ALL_GCS void initialize_queues() { } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS // Machine dependent stuff #ifdef TARGET_OS_ARCH_linux_x86 @@ -1836,6 +1815,7 @@ private: CompilerCounters* _counters; + ciEnv* _env; CompileLog* _log; CompileTask* _task; CompileQueue* _queue; @@ -1849,18 +1829,15 @@ bool is_Compiler_thread() const { return true; } // Hide this compiler thread from external view. - // (thomaswue) For Graal, the compiler thread should be visible. - bool is_hidden_from_external_view() const { -#ifdef GRAALVM - return !DebugGraal; -#else - return true; -#endif - } + bool is_hidden_from_external_view() const { return true; } CompileQueue* queue() { return _queue; } CompilerCounters* counters() { return _counters; } + // Get/set the thread's compilation environment. + ciEnv* env() { return _env; } + void set_env(ciEnv* env) { _env = env; } + // Get/set the thread's logging information CompileLog* log() { return _log; } void init_log(CompileLog* log) { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/vframe.cpp --- a/src/share/vm/runtime/vframe.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/vframe.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -266,8 +266,8 @@ // Get oopmap describing oops and int for current bci InterpreterOopMap oop_mask; - if (PrintDeoptimizationDetails) { - methodHandle m_h(method()); + if (TraceDeoptimization && Verbose) { + methodHandle m_h(thread(), method()); OopMapCache::compute_one_oop_map(m_h, bci(), &oop_mask); } else { method()->mask_for(bci(), &oop_mask); @@ -333,7 +333,7 @@ InterpreterOopMap oop_mask; // Get oopmap describing oops and int for current bci - if (PrintDeoptimizationDetails) { + if (TraceDeoptimization && Verbose) { methodHandle m_h(method()); OopMapCache::compute_one_oop_map(m_h, bci(), &oop_mask); } else { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/vframeArray.cpp --- a/src/share/vm/runtime/vframeArray.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/vframeArray.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -63,7 +63,7 @@ _method = vf->method(); _bci = vf->raw_bci(); _reexecute = vf->should_reexecute(); - + int index; // Get the monitors off-stack @@ -233,8 +233,6 @@ // Force early return from top frame after deoptimization #ifndef CC_INTERP pc = Interpreter::remove_activation_early_entry(state->earlyret_tos()); -#else - // TBD: Need to implement ForceEarlyReturn for CC_INTERP (ia64) #endif } else { // Possibly override the previous pc computation of the top (youngest) frame @@ -288,7 +286,7 @@ _frame.patch_pc(thread, pc); - assert (!method()->is_synchronized() || locks > 0, "synchronized methods must have monitors"); + assert (!method()->is_synchronized() || locks > 0 || raw_bci() == SynchronizationEntryBCI, "synchronized methods must have monitors"); BasicObjectLock* top = iframe()->interpreter_frame_monitor_begin(); for (int index = 0; index < locks; index++) { @@ -431,6 +429,11 @@ RegisterMap map(thread); vframe* f = vframe::new_vframe(iframe(), &map, thread); f->print(); + + tty->print_cr("locals size %d", locals()->size()); + tty->print_cr("expression size %d", expressions()->size()); + + method()->print_value(); tty->cr(); // method()->print_codes(); } else if (TraceDeoptimization) { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/vframe_hp.cpp --- a/src/share/vm/runtime/vframe_hp.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/vframe_hp.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -70,12 +70,6 @@ } } - if (PrintDeoptimizationDetails) { - tty->print_cr("bci=%d length=%d", this->bci(), length); - tty->print_cr(err_msg("method name = %s", this->method()->name()->as_C_string())); - tty->print_cr("relative pc=%d", this->fr().pc() - this->nm()->code_begin()); - } - for( int i = 0; i < length; i++ ) { result->add( create_stack_value(scv_list->at(i)) ); } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/vframe_hp.hpp --- a/src/share/vm/runtime/vframe_hp.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/vframe_hp.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -66,7 +66,7 @@ // Returns SynchronizationEntryBCI or bci() (used for synchronization) int raw_bci() const; - //protected: + protected: ScopeDesc* _scope; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/vmStructs.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,6 +101,7 @@ #include "utilities/array.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/hashtable.hpp" +#include "utilities/macros.hpp" #ifdef TARGET_ARCH_x86 # include "vmStructs_x86.hpp" #endif @@ -146,7 +147,7 @@ #ifdef TARGET_OS_ARCH_bsd_zero # include "vmStructs_bsd_zero.hpp" #endif -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp" #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp" #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp" @@ -161,7 +162,7 @@ #include "gc_implementation/parallelScavenge/psYoungGen.hpp" #include "gc_implementation/parallelScavenge/vmStructs_parallelgc.hpp" #include "gc_implementation/g1/vmStructs_g1.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef COMPILER2 #include "opto/addnode.hpp" #include "opto/block.hpp" @@ -208,7 +209,7 @@ // type name, indicating an "opaque" type to the serviceability agent. // NOTE: there is an interdependency between this file and -// HotSpotJavaTypeDataBase.java, which parses the type strings. +// HotSpotTypeDataBase.java, which parses the type strings. #ifndef REG_COUNT #define REG_COUNT 0 @@ -365,11 +366,10 @@ volatile_nonstatic_field(Method, _from_compiled_entry, address) \ volatile_nonstatic_field(Method, _from_interpreted_entry, address) \ volatile_nonstatic_field(ConstMethod, _fingerprint, uint64_t) \ - nonstatic_field(ConstMethod, _constants, ConstantPool*) \ + nonstatic_field(ConstMethod, _constants, ConstantPool*) \ nonstatic_field(ConstMethod, _stackmap_data, Array*) \ nonstatic_field(ConstMethod, _constMethod_size, int) \ - nonstatic_field(ConstMethod, _interpreter_kind, jbyte) \ - nonstatic_field(ConstMethod, _flags, jbyte) \ + nonstatic_field(ConstMethod, _flags, u2) \ nonstatic_field(ConstMethod, _code_size, u2) \ nonstatic_field(ConstMethod, _name_index, u2) \ nonstatic_field(ConstMethod, _signature_index, u2) \ @@ -1161,6 +1161,7 @@ static_field(Abstract_VM_Version, _vm_major_version, int) \ static_field(Abstract_VM_Version, _vm_minor_version, int) \ static_field(Abstract_VM_Version, _vm_build_number, int) \ + static_field(Abstract_VM_Version, _reserve_for_allocation_prefetch, int) \ \ static_field(JDK_Version, _current, JDK_Version) \ nonstatic_field(JDK_Version, _partially_initialized, bool) \ @@ -2087,8 +2088,7 @@ declare_toplevel_type(FreeBlockDictionary*) \ declare_toplevel_type(FreeList*) \ declare_toplevel_type(FreeList) \ - declare_toplevel_type(MetablockTreeDictionary*) \ - declare_type(MetablockTreeDictionary, FreeBlockDictionary) + declare_type(MetablockTreeDictionary, FreeBlockDictionary) //-------------------------------------------------------------------------------- @@ -2109,8 +2109,6 @@ /* Useful globals */ \ /******************/ \ \ - declare_constant(UseTLAB) \ - declare_constant(EnableInvokeDynamic) \ \ /**************/ \ /* Stack bias */ \ @@ -2260,14 +2258,18 @@ declare_constant(Klass::_lh_array_tag_obj_value) \ \ /********************************/ \ - /* ConstMethod anon-enum */ \ + /* ConstMethod anon-enum */ \ /********************************/ \ \ - declare_constant(ConstMethod::_has_linenumber_table) \ - declare_constant(ConstMethod::_has_checked_exceptions) \ - declare_constant(ConstMethod::_has_localvariable_table) \ - declare_constant(ConstMethod::_has_exception_table) \ - declare_constant(ConstMethod::_has_generic_signature) \ + declare_constant(ConstMethod::_has_linenumber_table) \ + declare_constant(ConstMethod::_has_checked_exceptions) \ + declare_constant(ConstMethod::_has_localvariable_table) \ + declare_constant(ConstMethod::_has_exception_table) \ + declare_constant(ConstMethod::_has_generic_signature) \ + declare_constant(ConstMethod::_has_method_annotations) \ + declare_constant(ConstMethod::_has_parameter_annotations) \ + declare_constant(ConstMethod::_has_default_annotations) \ + declare_constant(ConstMethod::_has_type_annotations) \ \ /*************************************/ \ /* InstanceKlass enum */ \ @@ -2382,32 +2384,26 @@ declare_constant(Location::on_stack) \ declare_constant(Location::in_register) \ \ - /* TODO (chaeubl) those constants should be graal/c1/c2 specific */ \ - /*declare_constant(Deoptimization::Reason_many)*/ \ - /*declare_constant(Deoptimization::Reason_none)*/ \ - /*declare_constant(Deoptimization::Reason_null_check)*/ \ - /*declare_constant(Deoptimization::Reason_range_check)*/ \ - /*declare_constant(Deoptimization::Reason_class_check)*/ \ - /*declare_constant(Deoptimization::Reason_array_check)*/ \ - /*declare_constant(Deoptimization::Reason_unreached)*/ \ - /*declare_constant(Deoptimization::Reason_constraint)*/ \ - /*declare_constant(Deoptimization::Reason_div0_check)*/ \ - /*declare_constant(Deoptimization::Reason_type_checked_inlining)*/ \ - /*declare_constant(Deoptimization::Reason_optimized_type_check)*/ \ - /*declare_constant(Deoptimization::Reason_not_compiled_exception_handler)*/ \ - /*declare_constant(Deoptimization::Reason_unresolved)*/ \ - /*declare_constant(Deoptimization::Reason_jsr_mismatch)*/ \ - /*declare_constant(Deoptimization::Reason_LIMIT)*/ \ - /*declare_constant(Deoptimization::Reason_RECORDED_LIMIT)*/ \ - /*declare_constant(Deoptimization::Reason_null_assert)*/ \ - /*declare_constant(Deoptimization::Reason_intrinsic)*/ \ - /*declare_constant(Deoptimization::Reason_bimorphic)*/ \ - /*declare_constant(Deoptimization::Reason_unloaded)*/ \ - /*declare_constant(Deoptimization::Reason_uninitialized) */ \ - /*declare_constant(Deoptimization::Reason_unhandled)*/ \ - /*declare_constant(Deoptimization::Reason_age)*/ \ - /*declare_constant(Deoptimization::Reason_predicate)*/ \ - /*declare_constant(Deoptimization::Reason_loop_limit_check)*/ \ + declare_constant(Deoptimization::Reason_many) \ + declare_constant(Deoptimization::Reason_none) \ + declare_constant(Deoptimization::Reason_null_check) \ + declare_constant(Deoptimization::Reason_null_assert) \ + declare_constant(Deoptimization::Reason_range_check) \ + declare_constant(Deoptimization::Reason_class_check) \ + declare_constant(Deoptimization::Reason_array_check) \ + declare_constant(Deoptimization::Reason_intrinsic) \ + declare_constant(Deoptimization::Reason_bimorphic) \ + declare_constant(Deoptimization::Reason_unloaded) \ + declare_constant(Deoptimization::Reason_uninitialized) \ + declare_constant(Deoptimization::Reason_unreached) \ + declare_constant(Deoptimization::Reason_unhandled) \ + declare_constant(Deoptimization::Reason_constraint) \ + declare_constant(Deoptimization::Reason_div0_check) \ + declare_constant(Deoptimization::Reason_age) \ + declare_constant(Deoptimization::Reason_predicate) \ + declare_constant(Deoptimization::Reason_loop_limit_check) \ + declare_constant(Deoptimization::Reason_LIMIT) \ + declare_constant(Deoptimization::Reason_RECORDED_LIMIT) \ \ /*********************/ \ /* Matcher (C2 only) */ \ @@ -2792,7 +2788,7 @@ GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS VM_STRUCTS_PARALLELGC(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY) @@ -2802,7 +2798,7 @@ VM_STRUCTS_G1(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS VM_STRUCTS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY, @@ -2836,7 +2832,7 @@ GENERATE_C2_VM_TYPE_ENTRY, GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS VM_TYPES_PARALLELGC(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY) @@ -2847,7 +2843,7 @@ VM_TYPES_G1(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS VM_TYPES_CPU(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY, @@ -2878,11 +2874,11 @@ GENERATE_C2_VM_INT_CONSTANT_ENTRY, GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS VM_INT_CONSTANTS_CMS(GENERATE_VM_INT_CONSTANT_ENTRY) VM_INT_CONSTANTS_PARNEW(GENERATE_VM_INT_CONSTANT_ENTRY) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS VM_INT_CONSTANTS_CPU(GENERATE_VM_INT_CONSTANT_ENTRY, GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, @@ -2936,7 +2932,7 @@ CHECK_NO_OP, CHECK_NO_OP); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS VM_STRUCTS_PARALLELGC(CHECK_NONSTATIC_VM_STRUCT_ENTRY, CHECK_STATIC_VM_STRUCT_ENTRY); @@ -2946,7 +2942,7 @@ VM_STRUCTS_G1(CHECK_NONSTATIC_VM_STRUCT_ENTRY, CHECK_STATIC_VM_STRUCT_ENTRY); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS VM_STRUCTS_CPU(CHECK_NONSTATIC_VM_STRUCT_ENTRY, CHECK_STATIC_VM_STRUCT_ENTRY, @@ -2975,7 +2971,7 @@ CHECK_C2_VM_TYPE_ENTRY, CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS VM_TYPES_PARALLELGC(CHECK_VM_TYPE_ENTRY, CHECK_SINGLE_ARG_VM_TYPE_NO_OP); @@ -2986,7 +2982,7 @@ VM_TYPES_G1(CHECK_VM_TYPE_ENTRY, CHECK_SINGLE_ARG_VM_TYPE_NO_OP); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS VM_TYPES_CPU(CHECK_VM_TYPE_ENTRY, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, @@ -3041,7 +3037,7 @@ ENSURE_C2_FIELD_TYPE_PRESENT, CHECK_NO_OP, CHECK_NO_OP)); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS debug_only(VM_STRUCTS_PARALLELGC(ENSURE_FIELD_TYPE_PRESENT, ENSURE_FIELD_TYPE_PRESENT)); debug_only(VM_STRUCTS_CMS(ENSURE_FIELD_TYPE_PRESENT, @@ -3049,7 +3045,7 @@ ENSURE_FIELD_TYPE_PRESENT)); debug_only(VM_STRUCTS_G1(ENSURE_FIELD_TYPE_PRESENT, ENSURE_FIELD_TYPE_PRESENT)); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS debug_only(VM_STRUCTS_CPU(ENSURE_FIELD_TYPE_PRESENT, ENSURE_FIELD_TYPE_PRESENT, CHECK_NO_OP, diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/vmStructs.hpp --- a/src/share/vm/runtime/vmStructs.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/vmStructs.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,7 @@ #ifndef SHARE_VM_RUNTIME_VMSTRUCTS_HPP #define SHARE_VM_RUNTIME_VMSTRUCTS_HPP -#ifndef VM_STRUCTS_KERNEL #include "utilities/debug.hpp" -#endif #ifdef COMPILER1 #include "c1/c1_Runtime1.hpp" #endif diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/runtime/vm_version.cpp --- a/src/share/vm/runtime/vm_version.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/runtime/vm_version.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -111,9 +111,6 @@ #endif #ifndef VMTYPE - #ifdef KERNEL - #define VMTYPE "Kernel" - #else // KERNEL #ifdef TIERED #define VMTYPE "Server" #else // TIERED @@ -132,7 +129,6 @@ #endif // GRAAL #endif // ZERO #endif // TIERED - #endif // KERNEL #endif #ifndef HOTSPOT_VM_DISTRO diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/attachListener.cpp --- a/src/share/vm/services/attachListener.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/attachListener.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -170,7 +170,6 @@ return JNI_OK; } -#ifndef SERVICES_KERNEL // Heap dumping not supported // Implementation of "dumpheap" command. // See also: HeapDumpDCmd class // @@ -212,7 +211,6 @@ } return JNI_OK; } -#endif // SERVICES_KERNEL // Implementation of "inspectheap" command // See also: ClassHistogramDCmd class @@ -382,9 +380,7 @@ static AttachOperationFunctionInfo funcs[] = { { "agentProperties", get_agent_properties }, { "datadump", data_dump }, -#ifndef SERVICES_KERNEL { "dumpheap", dump_heap }, -#endif // SERVICES_KERNEL { "load", JvmtiExport::load_agent_library }, { "properties", get_system_properties }, { "threaddump", thread_dump }, diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/attachListener.hpp --- a/src/share/vm/services/attachListener.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/attachListener.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "memory/allocation.hpp" #include "utilities/debug.hpp" #include "utilities/ostream.hpp" +#include "utilities/macros.hpp" // The AttachListener thread services a queue of operations that are enqueued // by client tools. Each operation is identified by a name and has up to 3 @@ -38,8 +39,6 @@ // complets the result value and any result data is returned to the client // tool. -#ifndef SERVICES_KERNEL - class AttachOperation; typedef jint (*AttachOperationFunction)(AttachOperation* op, outputStream* out); @@ -48,7 +47,6 @@ const char* name; AttachOperationFunction func; }; -#endif // SERVICES_KERNEL class AttachListener: AllStatic { public: diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/classLoadingService.cpp --- a/src/share/vm/services/classLoadingService.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/classLoadingService.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -31,6 +31,7 @@ #include "services/classLoadingService.hpp" #include "services/memoryService.hpp" #include "utilities/dtrace.hpp" +#include "utilities/macros.hpp" #ifdef DTRACE_ENABLED diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/classLoadingService.hpp --- a/src/share/vm/services/classLoadingService.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/classLoadingService.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -28,6 +28,7 @@ #include "runtime/handles.hpp" #include "runtime/perfData.hpp" #include "utilities/growableArray.hpp" +#include "utilities/macros.hpp" class InstanceKlass; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/diagnosticCommand.cpp --- a/src/share/vm/services/diagnosticCommand.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/diagnosticCommand.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -30,6 +30,7 @@ #include "services/diagnosticFramework.hpp" #include "services/heapDumper.hpp" #include "services/management.hpp" +#include "utilities/macros.hpp" void DCmdRegistrant::register_dcmds(){ // Registration of the diagnostic commands @@ -43,12 +44,12 @@ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true, false)); -#if INCLUDE_SERVICES // Heap dumping supported +#if INCLUDE_SERVICES // Heap dumping/inspection supported DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true, false)); #endif // INCLUDE_SERVICES - DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true, false)); - //Enhanced JMX Agent Support DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true,false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true,false)); @@ -252,7 +253,7 @@ vmSymbols::void_method_signature(), CHECK); } -#if INCLUDE_SERVICES // Heap dumping supported +#if INCLUDE_SERVICES // Heap dumping/inspection supported HeapDumpDCmd::HeapDumpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), _filename("filename","Name of the dump file", "STRING",true), @@ -292,7 +293,6 @@ return 0; } } -#endif // INCLUDE_SERVICES ClassHistogramDCmd::ClassHistogramDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), @@ -319,6 +319,65 @@ } } +#define DEFAULT_COLUMNS "InstBytes,KlassBytes,CpAll,annotations,MethodCount,Bytecodes,MethodAll,ROAll,RWAll,Total" +ClassStatsDCmd::ClassStatsDCmd(outputStream* output, bool heap) : + DCmdWithParser(output, heap), + _csv("-csv", "Print in CSV (comma-separated values) format for spreadsheets", + "BOOLEAN", false, "false"), + _all("-all", "Show all columns", + "BOOLEAN", false, "false"), + _help("-help", "Show meaning of all the columns", + "BOOLEAN", false, "false"), + _columns("columns", "Comma-separated list of all the columns to show. " + "If not specified, the following columns are shown: " DEFAULT_COLUMNS, + "STRING", false) { + _dcmdparser.add_dcmd_option(&_all); + _dcmdparser.add_dcmd_option(&_csv); + _dcmdparser.add_dcmd_option(&_help); + _dcmdparser.add_dcmd_argument(&_columns); +} + +void ClassStatsDCmd::execute(TRAPS) { + if (!UnlockDiagnosticVMOptions) { + output()->print_cr("GC.class_stats command requires -XX:+UnlockDiagnosticVMOptions"); + return; + } + + VM_GC_HeapInspection heapop(output(), + true, /* request_full_gc */ + true /* need_prologue */); + heapop.set_csv_format(_csv.value()); + heapop.set_print_help(_help.value()); + heapop.set_print_class_stats(true); + if (_all.value()) { + if (_columns.has_value()) { + output()->print_cr("Cannot specify -all and individual columns at the same time"); + return; + } else { + heapop.set_columns(NULL); + } + } else { + if (_columns.has_value()) { + heapop.set_columns(_columns.value()); + } else { + heapop.set_columns(DEFAULT_COLUMNS); + } + } + VMThread::execute(&heapop); +} + +int ClassStatsDCmd::num_arguments() { + ResourceMark rm; + ClassStatsDCmd* dcmd = new ClassStatsDCmd(NULL, false); + if (dcmd != NULL) { + DCmdMark mark(dcmd); + return dcmd->_dcmdparser.num_arguments(); + } else { + return 0; + } +} +#endif // INCLUDE_SERVICES + ThreadDumpDCmd::ThreadDumpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), _locks("-l", "print java.util.concurrent locks", "BOOLEAN", false, "false") { @@ -406,7 +465,32 @@ _jmxremote_ssl_config_file ("jmxremote.ssl.config.file", - "set com.sun.management.jmxremote.ssl_config_file", "STRING", false) + "set com.sun.management.jmxremote.ssl_config_file", "STRING", false), + +// JDP Protocol support + _jmxremote_autodiscovery + ("jmxremote.autodiscovery", + "set com.sun.management.jmxremote.autodiscovery", "STRING", false), + + _jdp_port + ("jdp.port", + "set com.sun.management.jdp.port", "INT", false), + + _jdp_address + ("jdp.address", + "set com.sun.management.jdp.address", "STRING", false), + + _jdp_source_addr + ("jdp.source_addr", + "set com.sun.management.jdp.source_addr", "STRING", false), + + _jdp_ttl + ("jdp.ttl", + "set com.sun.management.jdp.ttl", "INT", false), + + _jdp_pause + ("jdp.pause", + "set com.sun.management.jdp.pause", "INT", false) { _dcmdparser.add_dcmd_option(&_config_file); @@ -422,6 +506,12 @@ _dcmdparser.add_dcmd_option(&_jmxremote_ssl_enabled_protocols); _dcmdparser.add_dcmd_option(&_jmxremote_ssl_need_client_auth); _dcmdparser.add_dcmd_option(&_jmxremote_ssl_config_file); + _dcmdparser.add_dcmd_option(&_jmxremote_autodiscovery); + _dcmdparser.add_dcmd_option(&_jdp_port); + _dcmdparser.add_dcmd_option(&_jdp_address); + _dcmdparser.add_dcmd_option(&_jdp_source_addr); + _dcmdparser.add_dcmd_option(&_jdp_ttl); + _dcmdparser.add_dcmd_option(&_jdp_pause); } @@ -436,7 +526,6 @@ } } - void JMXStartRemoteDCmd::execute(TRAPS) { ResourceMark rm(THREAD); HandleMark hm(THREAD); @@ -466,7 +555,9 @@ // file. #define PUT_OPTION(a) \ if ( (a).is_set() ){ \ - options.print("%scom.sun.management.%s=%s", comma, (a).name(), (a).value()); \ + options.print(\ + ( *((a).type()) == 'I' ) ? "%scom.sun.management.%s=%d" : "%scom.sun.management.%s=%s",\ + comma, (a).name(), (a).value()); \ comma[0] = ','; \ } @@ -483,6 +574,12 @@ PUT_OPTION(_jmxremote_ssl_enabled_protocols); PUT_OPTION(_jmxremote_ssl_need_client_auth); PUT_OPTION(_jmxremote_ssl_config_file); + PUT_OPTION(_jmxremote_autodiscovery); + PUT_OPTION(_jdp_port); + PUT_OPTION(_jdp_address); + PUT_OPTION(_jdp_source_addr); + PUT_OPTION(_jdp_ttl); + PUT_OPTION(_jdp_pause); #undef PUT_OPTION diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/diagnosticCommand.hpp --- a/src/share/vm/services/diagnosticCommand.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/diagnosticCommand.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -35,6 +35,7 @@ #include "services/diagnosticCommand.hpp" #include "services/diagnosticFramework.hpp" #include "services/diagnosticCommand_ext.hpp" +#include "utilities/macros.hpp" class HelpDCmd : public DCmdWithParser { protected: @@ -178,7 +179,7 @@ }; #endif // INCLUDE_SERVICES -// See also: inspeactheap in attachListener.cpp +// See also: inspectheap in attachListener.cpp class ClassHistogramDCmd : public DCmdWithParser { protected: DCmdArgument _all; @@ -197,6 +198,27 @@ virtual void execute(TRAPS); }; +class ClassStatsDCmd : public DCmdWithParser { +protected: + DCmdArgument _all; + DCmdArgument _csv; + DCmdArgument _help; + DCmdArgument _columns; +public: + ClassStatsDCmd(outputStream* output, bool heap); + static const char* name() { + return "GC.class_stats"; + } + static const char* description() { + return "Provide statistics about Java class meta data. Requires -XX:+UnlockDiagnosticVMOptions."; + } + static const char* impact() { + return "High: Depends on Java heap size and content."; + } + static int num_arguments(); + virtual void execute(TRAPS); +}; + // See also: thread_dump in attachListener.cpp class ThreadDumpDCmd : public DCmdWithParser { protected: @@ -236,6 +258,16 @@ DCmdArgument _jmxremote_ssl_need_client_auth; DCmdArgument _jmxremote_ssl_config_file; + // JDP support + // Keep autodiscovery char* not bool to pass true/false + // as property value to java level. + DCmdArgument _jmxremote_autodiscovery; + DCmdArgument _jdp_port; + DCmdArgument _jdp_address; + DCmdArgument _jdp_source_addr; + DCmdArgument _jdp_ttl; + DCmdArgument _jdp_pause; + public: JMXStartRemoteDCmd(outputStream *output, bool heap_allocated); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/g1MemoryPool.hpp --- a/src/share/vm/services/g1MemoryPool.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/g1MemoryPool.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -25,11 +25,12 @@ #ifndef SHARE_VM_SERVICES_G1MEMORYPOOL_HPP #define SHARE_VM_SERVICES_G1MEMORYPOOL_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1MonitoringSupport.hpp" #include "services/memoryPool.hpp" #include "services/memoryUsage.hpp" -#endif +#endif // INCLUDE_ALL_GCS // This file contains the three classes that represent the memory // pools of the G1 spaces: G1EdenPool, G1SurvivorPool, and diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/heapDumper.cpp --- a/src/share/vm/services/heapDumper.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/heapDumper.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -40,9 +40,10 @@ #include "services/heapDumper.hpp" #include "services/threadService.hpp" #include "utilities/ostream.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" -#endif +#endif // INCLUDE_ALL_GCS /* * HPROF binary format - description copied from: diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/management.cpp --- a/src/share/vm/services/management.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/management.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -53,6 +53,7 @@ #include "services/memoryService.hpp" #include "services/runtimeService.hpp" #include "services/threadService.hpp" +#include "utilities/macros.hpp" PerfVariable* Management::_begin_vm_creation_time = NULL; PerfVariable* Management::_end_vm_creation_time = NULL; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/memBaseline.cpp --- a/src/share/vm/services/memBaseline.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/memBaseline.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -40,6 +40,7 @@ {mtNMT, "Memory Tracking"}, {mtChunk, "Pooled Free Chunks"}, {mtClassShared,"Shared spaces for classes"}, + {mtTest, "Test"}, {mtNone, "Unknown"} // It can happen when type tagging records are lagging // behind }; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/memPtr.cpp --- a/src/share/vm/services/memPtr.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/memPtr.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -27,8 +27,8 @@ #include "services/memTracker.hpp" volatile jint SequenceGenerator::_seq_number = 1; +volatile unsigned long SequenceGenerator::_generation = 1; NOT_PRODUCT(jint SequenceGenerator::_max_seq_number = 1;) -DEBUG_ONLY(volatile unsigned long SequenceGenerator::_generation = 0;) jint SequenceGenerator::next() { jint seq = Atomic::add(1, &_seq_number); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/memPtr.hpp --- a/src/share/vm/services/memPtr.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/memPtr.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -47,16 +47,16 @@ static void reset() { assert(SafepointSynchronize::is_at_safepoint(), "Safepoint required"); _seq_number = 1; - DEBUG_ONLY(_generation ++;) + _generation ++; }; - DEBUG_ONLY(static unsigned long current_generation() { return (unsigned long)_generation; }) + static unsigned long current_generation() { return _generation; } NOT_PRODUCT(static jint max_seq_num() { return _max_seq_number; }) private: - static volatile jint _seq_number; - NOT_PRODUCT(static jint _max_seq_number; ) - DEBUG_ONLY(static volatile unsigned long _generation; ) + static volatile jint _seq_number; + static volatile unsigned long _generation; + NOT_PRODUCT(static jint _max_seq_number; ) }; /* diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/memRecorder.cpp --- a/src/share/vm/services/memRecorder.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/memRecorder.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -55,7 +55,7 @@ MemRecorder::MemRecorder() { assert(MemTracker::is_on(), "Native memory tracking is off"); Atomic::inc(&_instance_count); - debug_only(set_generation();) + set_generation(); if (MemTracker::track_callsite()) { _pointer_records = new (std::nothrow)FixedSizeMemPointerArrayis_arena_record()) { MemPointerRecord* next = (MemPointerRecord*)malloc_snapshot_itr.peek_next(); - if (next->is_arena_memory_record() && next->is_memory_record_of_arena(matched_rec)) { + if (next != NULL && next->is_arena_memory_record() && + next->is_memory_record_of_arena(matched_rec)) { malloc_snapshot_itr.remove(); } } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/memTrackWorker.cpp --- a/src/share/vm/services/memTrackWorker.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/memTrackWorker.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -91,6 +91,8 @@ MemSnapshot* snapshot = MemTracker::get_snapshot(); assert(snapshot != NULL, "Worker should not be started"); MemRecorder* rec; + unsigned long processing_generation = 0; + bool worker_idle = false; while (!MemTracker::shutdown_in_progress()) { NOT_PRODUCT(_last_gen_in_use = generations_in_use();) @@ -100,6 +102,12 @@ rec = _gen[_head].next_recorder(); } if (rec != NULL) { + if (rec->get_generation() != processing_generation || worker_idle) { + processing_generation = rec->get_generation(); + worker_idle = false; + MemTracker::set_current_processing_generation(processing_generation); + } + // merge the recorder into staging area if (!snapshot->merge(rec)) { MemTracker::shutdown(MemTracker::NMT_out_of_memory); @@ -129,6 +137,9 @@ MemTracker::shutdown(MemTracker::NMT_out_of_memory); } } else { + // worker thread is idle + worker_idle = true; + MemTracker::report_worker_idle(); snapshot->wait(1000); ThreadCritical tc; // check if more data arrived diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/memTrackWorker.hpp --- a/src/share/vm/services/memTrackWorker.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/memTrackWorker.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -107,6 +107,7 @@ NOT_PRODUCT(int _merge_count;) NOT_PRODUCT(int _last_gen_in_use;) + // how many generations are queued inline int generations_in_use() const { return (_tail >= _head ? (_tail - _head + 1) : (MAX_GENERATIONS - (_head - _tail) + 1)); } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/memTracker.cpp --- a/src/share/vm/services/memTracker.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/memTracker.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -29,6 +29,7 @@ #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" #include "runtime/threadCritical.hpp" +#include "runtime/vm_operations.hpp" #include "services/memPtr.hpp" #include "services/memReporter.hpp" #include "services/memTracker.hpp" @@ -65,6 +66,8 @@ MemTracker::ShutdownReason MemTracker::_reason = NMT_shutdown_none; int MemTracker::_thread_count = 255; volatile jint MemTracker::_pooled_recorder_count = 0; +volatile unsigned long MemTracker::_processing_generation = 0; +volatile bool MemTracker::_worker_thread_idle = false; debug_only(intx MemTracker::_main_thread_tid = 0;) NOT_PRODUCT(volatile jint MemTracker::_pending_recorder_count = 0;) @@ -279,7 +282,7 @@ } cur_head->set_next(NULL); Atomic::dec(&_pooled_recorder_count); - debug_only(cur_head->set_generation();) + cur_head->set_generation(); return cur_head; } } @@ -570,6 +573,51 @@ return false; } +// Whitebox API for blocking until the current generation of NMT data has been merged +bool MemTracker::wbtest_wait_for_data_merge() { + // NMT can't be shutdown while we're holding _query_lock + MutexLockerEx lock(_query_lock, true); + assert(_worker_thread != NULL, "Invalid query"); + // the generation at query time, so NMT will spin till this generation is processed + unsigned long generation_at_query_time = SequenceGenerator::current_generation(); + unsigned long current_processing_generation = _processing_generation; + // if generation counter overflown + bool generation_overflown = (generation_at_query_time < current_processing_generation); + long generations_to_wrap = MAX_UNSIGNED_LONG - current_processing_generation; + // spin + while (!shutdown_in_progress()) { + if (!generation_overflown) { + if (current_processing_generation > generation_at_query_time) { + return true; + } + } else { + assert(generations_to_wrap >= 0, "Sanity check"); + long current_generations_to_wrap = MAX_UNSIGNED_LONG - current_processing_generation; + assert(current_generations_to_wrap >= 0, "Sanity check"); + // to overflow an unsigned long should take long time, so to_wrap check should be sufficient + if (current_generations_to_wrap > generations_to_wrap && + current_processing_generation > generation_at_query_time) { + return true; + } + } + + // if worker thread is idle, but generation is not advancing, that means + // there is not safepoint to let NMT advance generation, force one. + if (_worker_thread_idle) { + VM_ForceSafepoint vfs; + VMThread::execute(&vfs); + } + MemSnapshot* snapshot = get_snapshot(); + if (snapshot == NULL) { + return false; + } + snapshot->wait(1000); + current_processing_generation = _processing_generation; + } + // We end up here if NMT is shutting down before our data has been merged + return false; +} + // compare memory usage between current snapshot and baseline bool MemTracker::compare_memory_usage(BaselineOutputer& out, size_t unit, bool summary_only) { MutexLockerEx lock(_query_lock, true); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/memTracker.hpp --- a/src/share/vm/services/memTracker.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/memTracker.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -91,9 +91,10 @@ static bool compare_memory_usage(BaselineOutputer& out, size_t unit, bool summary_only = true) { } + static bool wbtest_wait_for_data_merge() { } + static inline void sync() { } static inline void thread_exiting(JavaThread* thread) { } - }; @@ -111,6 +112,10 @@ extern bool NMT_track_callsite; +#ifndef MAX_UNSIGNED_LONG +#define MAX_UNSIGNED_LONG (unsigned long)(-1) +#endif + #ifdef ASSERT #define DEBUG_CALLER_PC (NMT_track_callsite ? os::get_caller_pc(2) : 0) #else @@ -380,6 +385,11 @@ static bool compare_memory_usage(BaselineOutputer& out, size_t unit, bool summary_only = true); + // the version for whitebox testing support, it ensures that all memory + // activities before this method call, are reflected in the snapshot + // database. + static bool wbtest_wait_for_data_merge(); + // sync is called within global safepoint to synchronize nmt data static void sync(); @@ -432,6 +442,15 @@ static void create_record_in_recorder(address addr, MEMFLAGS type, size_t size, address pc, JavaThread* thread); + static void set_current_processing_generation(unsigned long generation) { + _worker_thread_idle = false; + _processing_generation = generation; + } + + static void report_worker_idle() { + _worker_thread_idle = true; + } + private: // global memory snapshot static MemSnapshot* _snapshot; @@ -483,6 +502,11 @@ static volatile enum NMTStates _state; // the reason for shutting down nmt static enum ShutdownReason _reason; + // the generation that NMT is processing + static volatile unsigned long _processing_generation; + // although NMT is still procesing current generation, but + // there is not more recorder to process, set idle state + static volatile bool _worker_thread_idle; }; #endif // !INCLUDE_NMT diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/memoryPool.cpp --- a/src/share/vm/services/memoryPool.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/memoryPool.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -32,6 +32,7 @@ #include "services/management.hpp" #include "services/memoryManager.hpp" #include "services/memoryPool.hpp" +#include "utilities/macros.hpp" MemoryPool::MemoryPool(const char* name, PoolType type, @@ -208,7 +209,7 @@ return MemoryUsage(initial_size(), used, committed, maxSize); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS CompactibleFreeListSpacePool::CompactibleFreeListSpacePool(CompactibleFreeListSpace* space, const char* name, PoolType type, @@ -225,7 +226,7 @@ return MemoryUsage(initial_size(), used, committed, maxSize); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS GenerationPool::GenerationPool(Generation* gen, const char* name, diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/memoryPool.hpp --- a/src/share/vm/services/memoryPool.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/memoryPool.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -30,9 +30,10 @@ #include "memory/heap.hpp" #include "memory/space.hpp" #include "services/memoryUsage.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp" -#endif +#endif // INCLUDE_ALL_GCS // A memory pool represents the memory area that the VM manages. // The Java virtual machine has at least one memory pool @@ -185,7 +186,7 @@ } }; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS class CompactibleFreeListSpacePool : public CollectedMemoryPool { private: CompactibleFreeListSpace* _space; @@ -199,7 +200,7 @@ MemoryUsage get_memory_usage(); size_t used_in_bytes() { return _space->used(); } }; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS class GenerationPool : public CollectedMemoryPool { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/memoryService.cpp --- a/src/share/vm/services/memoryService.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/memoryService.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -43,7 +43,8 @@ #include "services/memoryPool.hpp" #include "services/memoryService.hpp" #include "utilities/growableArray.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/parNew/parNewGeneration.hpp" @@ -52,7 +53,7 @@ #include "gc_implementation/parallelScavenge/psYoungGen.hpp" #include "services/g1MemoryPool.hpp" #include "services/psMemoryPool.hpp" -#endif +#endif // INCLUDE_ALL_GCS GrowableArray* MemoryService::_pools_list = new (ResourceObj::C_HEAP, mtInternal) GrowableArray(init_pools_list_size, true); @@ -83,7 +84,7 @@ add_gen_collected_heap_info(GenCollectedHeap::heap()); break; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case CollectedHeap::ParallelScavengeHeap : { add_parallel_scavenge_heap_info(ParallelScavengeHeap::heap()); break; @@ -92,7 +93,7 @@ add_g1_heap_info(G1CollectedHeap::heap()); break; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS default: { guarantee(false, "Unrecognized kind of heap"); } @@ -130,22 +131,22 @@ case Generation::DefNew: _minor_gc_manager = MemoryManager::get_copy_memory_manager(); break; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case Generation::ParNew: case Generation::ASParNew: _minor_gc_manager = MemoryManager::get_parnew_memory_manager(); break; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS default: guarantee(false, "Unrecognized generation spec"); break; } if (policy->is_mark_sweep_policy()) { _major_gc_manager = MemoryManager::get_msc_memory_manager(); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS } else if (policy->is_concurrent_mark_sweep_policy()) { _major_gc_manager = MemoryManager::get_cms_memory_manager(); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } else { guarantee(false, "Unknown two-gen policy"); } @@ -159,7 +160,7 @@ add_generation_memory_pool(heap->get_gen(major), _major_gc_manager); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Add memory pools for ParallelScavengeHeap // This function currently only supports two generations collected heap. // The collector for ParallelScavengeHeap will have two memory managers. @@ -185,7 +186,7 @@ add_g1YoungGen_memory_pool(g1h, _major_gc_manager, _minor_gc_manager); add_g1OldGen_memory_pool(g1h, _major_gc_manager); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS MemoryPool* MemoryService::add_gen(Generation* gen, const char* name, @@ -222,7 +223,7 @@ return (MemoryPool*) pool; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS MemoryPool* MemoryService::add_cms_space(CompactibleFreeListSpace* space, const char* name, bool is_heap, @@ -233,7 +234,7 @@ _pools_list->append(pool); return (MemoryPool*) pool; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Add memory pool(s) for one generation void MemoryService::add_generation_memory_pool(Generation* gen, @@ -261,7 +262,7 @@ break; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case Generation::ParNew: case Generation::ASParNew: { @@ -282,7 +283,7 @@ break; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS case Generation::MarkSweepCompact: { assert(major_mgr != NULL && minor_mgr == NULL, "Should have only one manager"); @@ -293,7 +294,7 @@ break; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case Generation::ConcurrentMarkSweep: case Generation::ASConcurrentMarkSweep: { @@ -306,7 +307,7 @@ true /* support_usage_threshold */); break; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS default: assert(false, "should not reach here"); @@ -326,7 +327,7 @@ } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void MemoryService::add_psYoung_memory_pool(PSYoungGen* gen, MemoryManager* major_mgr, MemoryManager* minor_mgr) { assert(major_mgr != NULL && minor_mgr != NULL, "Should have two managers"); @@ -384,7 +385,7 @@ mgr->add_pool(old_gen); _pools_list->append(old_gen); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS void MemoryService::add_code_heap_memory_pool(CodeHeap* heap) { _code_heap_pool = new CodeHeapPool(heap, @@ -534,17 +535,17 @@ TraceMemoryManagerStats::TraceMemoryManagerStats(Generation::Name kind, GCCause::Cause cause) { switch (kind) { case Generation::DefNew: -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case Generation::ParNew: case Generation::ASParNew: -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS _fullGC=false; break; case Generation::MarkSweepCompact: -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case Generation::ConcurrentMarkSweep: case Generation::ASConcurrentMarkSweep: -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS _fullGC=true; break; default: diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/psMemoryPool.hpp --- a/src/share/vm/services/psMemoryPool.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/psMemoryPool.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -25,7 +25,8 @@ #ifndef SHARE_VM_SERVICES_PSMEMORYPOOL_HPP #define SHARE_VM_SERVICES_PSMEMORYPOOL_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/psOldGen.hpp" #include "gc_implementation/parallelScavenge/psYoungGen.hpp" #include "gc_implementation/shared/mutableSpace.hpp" @@ -34,7 +35,7 @@ #include "memory/space.hpp" #include "services/memoryPool.hpp" #include "services/memoryUsage.hpp" -#endif +#endif // INCLUDE_ALL_GCS class PSGenerationPool : public CollectedMemoryPool { private: diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/services/runtimeService.cpp --- a/src/share/vm/services/runtimeService.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/services/runtimeService.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -29,6 +29,7 @@ #include "services/runtimeService.hpp" #include "utilities/dtrace.hpp" #include "utilities/exceptions.hpp" +#include "utilities/macros.hpp" #ifndef USDT2 HS_DTRACE_PROBE_DECL(hs_private, safepoint__begin); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/utilities/accessFlags.cpp --- a/src/share/vm/utilities/accessFlags.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/utilities/accessFlags.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ } while(f != old_flags); } -#ifndef PRODUCT +#if !defined(PRODUCT) || INCLUDE_JVMTI void AccessFlags::print_on(outputStream* st) const { if (is_public ()) st->print("public " ); @@ -80,7 +80,7 @@ if (on_stack ()) st->print("{on_stack} " ); } -#endif +#endif // !PRODUCT || INCLUDE_JVMTI void accessFlags_init() { assert(sizeof(AccessFlags) == sizeof(jint), "just checking size of flags"); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/utilities/accessFlags.hpp --- a/src/share/vm/utilities/accessFlags.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/utilities/accessFlags.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -239,7 +239,11 @@ inline friend AccessFlags accessFlags_from(jint flags); // Printing/debugging +#if INCLUDE_JVMTI + void print_on(outputStream* st) const; +#else void print_on(outputStream* st) const PRODUCT_RETURN; +#endif }; inline AccessFlags accessFlags_from(jint flags) { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/utilities/constantTag.cpp --- a/src/share/vm/utilities/constantTag.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/utilities/constantTag.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,6 @@ case JVM_CONSTANT_StringIndex : case JVM_CONSTANT_MethodHandle : case JVM_CONSTANT_MethodType : - case JVM_CONSTANT_Object : return T_OBJECT; default: ShouldNotReachHere(); @@ -96,8 +95,6 @@ return "MethodType Error"; case JVM_CONSTANT_InvokeDynamic : return "InvokeDynamic"; - case JVM_CONSTANT_Object : - return "Object"; case JVM_CONSTANT_Utf8 : return "Utf8"; case JVM_CONSTANT_UnresolvedClass : diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/utilities/constantTag.hpp --- a/src/share/vm/utilities/constantTag.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/utilities/constantTag.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,8 +43,7 @@ JVM_CONSTANT_UnresolvedClassInError = 103, // Error tag due to resolution error JVM_CONSTANT_MethodHandleInError = 104, // Error tag due to resolution error JVM_CONSTANT_MethodTypeInError = 105, // Error tag due to resolution error - JVM_CONSTANT_Object = 106, // Required for BoundMethodHandle arguments. - JVM_CONSTANT_InternalMax = 106 // Last implementation tag + JVM_CONSTANT_InternalMax = 105 // Last implementation tag }; @@ -84,8 +83,6 @@ bool is_klass_index() const { return _tag == JVM_CONSTANT_ClassIndex; } bool is_string_index() const { return _tag == JVM_CONSTANT_StringIndex; } - bool is_object() const { return _tag == JVM_CONSTANT_Object; } - bool is_klass_reference() const { return is_klass_index() || is_unresolved_klass(); } bool is_klass_or_reference() const{ return is_klass() || is_klass_reference(); } bool is_field_or_method() const { return is_field() || is_method() || is_interface_method(); } @@ -98,7 +95,7 @@ bool is_loadable_constant() const { return ((_tag >= JVM_CONSTANT_Integer && _tag <= JVM_CONSTANT_String) || is_method_type() || is_method_handle() || - is_unresolved_klass() || is_object()); + is_unresolved_klass()); } constantTag() { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/utilities/debug.cpp --- a/src/share/vm/utilities/debug.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/utilities/debug.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -228,28 +228,16 @@ report_vm_error(file, line, "fatal error", message); } -// Used by report_vm_out_of_memory to detect recursion. -static jint _exiting_out_of_mem = 0; - void report_vm_out_of_memory(const char* file, int line, size_t size, const char* message) { if (Debugging) return; - // We try to gather additional information for the first out of memory - // error only; gathering additional data might cause an allocation and a - // recursive out_of_memory condition. - - const jint exiting = 1; - // If we succeed in changing the value, we're the first one in. - bool first_time_here = Atomic::xchg(exiting, &_exiting_out_of_mem) != exiting; + Thread* thread = ThreadLocalStorage::get_thread_slow(); + VMError(thread, file, line, size, message).report_and_die(); - if (first_time_here) { - Thread* thread = ThreadLocalStorage::get_thread_slow(); - VMError(thread, file, line, size, message).report_and_die(); - } - - // Dump core and abort - vm_abort(true); + // The UseOSErrorReporting option in report_and_die() may allow a return + // to here. If so then we'll have to figure out how to handle it. + guarantee(false, "report_and_die() should not return here"); } void report_should_not_call(const char* file, int line) { @@ -842,37 +830,3 @@ #endif #endif // !PRODUCT - -#ifdef GRAAL - -DebugScopedValue::DebugScopedValue(const char* file, int line) { - _file = file; - _line = line; - Thread* thread = Thread::current(); - if (thread != NULL && thread->is_Java_thread()) { - JavaThread* javaThread = (JavaThread*) thread; - _parent = javaThread->debug_scope(); - javaThread->set_debug_scope(this); - } else { - _parent = NULL; - } -} - -DebugScopedValue::~DebugScopedValue() { - Thread* thread = Thread::current(); - if (thread != NULL && thread->is_Java_thread()) { - JavaThread* javaThread = (JavaThread*) thread; - javaThread->set_debug_scope(_parent); - _parent = NULL; - } -} - -void DebugScopedValue::print(outputStream* st) { - st->print("%s:%d: ", _file, _line); - print_on(st); -} - -void DebugScopedScalar::print_on(outputStream* st) { - st->print("int: %d, char: %c, long: %ld, hex: %p", _value, _value, _value, _value); -} -#endif diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/utilities/debug.hpp --- a/src/share/vm/utilities/debug.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/utilities/debug.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -30,35 +30,6 @@ #include -#ifdef GRAAL -// Scopes a value that may be of interest in a crash log. -class DebugScopedValue { -protected: - DebugScopedValue *_parent; - const char* _file; - int _line; -public: - DebugScopedValue(const char* file, int line); - ~DebugScopedValue(); - void print(outputStream* st); - virtual void print_on(outputStream* st) = 0; - DebugScopedValue* parent() { return _parent; } -}; - -class DebugScopedScalar : DebugScopedValue { -private: - void* _value; -public: - DebugScopedScalar(const char* file, int line, void* v) : DebugScopedValue(file, line), _value(v) {} - void print_on(outputStream* st); -}; -#define DS_SCALAR(val) DebugScopedScalar __dss__(__FILE__, __LINE__, (void*) val) -#define DS_SCALAR1(name, val) DebugScopedScalar name(__FILE__, __LINE__, (void*) val) -#else -#define DS_SCALAR(name) do {} while (0) -#define DS_SCALAR1(name, val) do {} while (0) -#endif - // Simple class to format the ctor arguments into a fixed-sized buffer. class FormatBufferBase { protected: diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/utilities/exceptions.hpp --- a/src/share/vm/utilities/exceptions.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/utilities/exceptions.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -61,6 +61,8 @@ friend class VMStructs; protected: + int _pending_deoptimization; + bool _pending_monitorenter; oop _pending_exception; // Thread has gc actions. const char* _exception_file; // file information for exception (debugging only) int _exception_line; // line information for exception (debugging only) @@ -76,12 +78,19 @@ public: oop pending_exception() const { return _pending_exception; } + int pending_deoptimization() const { return _pending_deoptimization; } bool has_pending_exception() const { return _pending_exception != NULL; } const char* exception_file() const { return _exception_file; } int exception_line() const { return _exception_line; } + bool has_pending_monitorenter() const { return _pending_monitorenter; } // Code generation support + static ByteSize pending_deoptimization_offset() { return byte_offset_of(ThreadShadow, _pending_deoptimization); } static ByteSize pending_exception_offset() { return byte_offset_of(ThreadShadow, _pending_exception); } + static ByteSize pending_monitorenter_offset() { return byte_offset_of(ThreadShadow, _pending_monitorenter); } + + void set_pending_monitorenter(bool b) { _pending_monitorenter = b; } + void set_pending_deoptimization(int reason) { _pending_deoptimization = reason; } // use THROW whenever possible! void set_pending_exception(oop exception, const char* file, int line); @@ -90,7 +99,7 @@ void clear_pending_exception(); ThreadShadow() : _pending_exception(NULL), - _exception_file(NULL), _exception_line(0) {} + _exception_file(NULL), _exception_line(0), _pending_monitorenter(false), _pending_deoptimization(-1) {} }; diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/utilities/machineCodePrinter.cpp --- a/src/share/vm/utilities/machineCodePrinter.cpp Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +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. - */ - -#include "precompiled.hpp" -#include "code/stubs.hpp" -#include "compiler/disassembler.hpp" -#include "runtime/thread.hpp" -#include "utilities/machineCodePrinter.hpp" -#include "utilities/ostream.hpp" - -fileStream* MachineCodePrinter::_st = NULL; -volatile int MachineCodePrinter::_write_lock = 0; - -void MachineCodePrinter::initialize() { - _st = new (ResourceObj::C_HEAP, mtInternal) fileStream("machineCode.txt"); -} - -void MachineCodePrinter::print(nmethod* nm) { - lock(); - Disassembler::decode(nm, _st); - unlock(); -} - -void MachineCodePrinter::print(CodeBlob* cb) { - lock(); - Disassembler::decode(cb, _st); - unlock(); -} - -void MachineCodePrinter::print(StubQueue* stub_queue) { - lock(); - stub_queue->print_on(_st); - unlock(); -} - -void MachineCodePrinter::flush() { - _st->flush(); -} - -void MachineCodePrinter::lock() { - Thread::SpinAcquire(&_write_lock, "Put"); -} - -void MachineCodePrinter::unlock() { - Thread::SpinRelease(&_write_lock); -} diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/utilities/machineCodePrinter.hpp --- a/src/share/vm/utilities/machineCodePrinter.hpp Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +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. - */ - -#ifndef SHARE_VM_UTILITIES_MACHINE_CODE_PRINTER_HPP -#define SHARE_VM_UTILITIES_MACHINE_CODE_PRINTER_HPP - -#include "memory/allocation.hpp" -#include "utilities/ostream.hpp" - -class MachineCodePrinter : public AllStatic { -private: - static fileStream* _st; - static volatile int _write_lock; - -public: - static void initialize(); - static void print(nmethod* nm); - static void print(CodeBlob* cb); - static void print(StubQueue* stub_queue); - static void flush(); - -private: - static void lock(); - static void unlock(); -}; - -#endif // SHARE_VM_UTILITIES_MACHINE_CODE_PRINTER_HPP diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/utilities/macros.hpp --- a/src/share/vm/utilities/macros.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/utilities/macros.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -130,23 +130,23 @@ #endif // INCLUDE_MANAGEMENT /* - * When INCLUDE_ALTERNATE_GCS is false the only garbage collectors + * When INCLUDE_ALL_GCS is false the only garbage collectors * included in the JVM are defaultNewGeneration and markCompact. * - * When INCLUDE_ALTERNATE_GCS is true all garbage collectors are + * When INCLUDE_ALL_GCS is true all garbage collectors are * included in the JVM. */ -#ifndef INCLUDE_ALTERNATE_GCS -#define INCLUDE_ALTERNATE_GCS 1 -#endif // INCLUDE_ALTERNATE_GCS +#ifndef INCLUDE_ALL_GCS +#define INCLUDE_ALL_GCS 1 +#endif // INCLUDE_ALL_GCS -#if INCLUDE_ALTERNATE_GCS -#define NOT_ALTERNATE_GCS_RETURN /* next token must be ; */ -#define NOT_ALTERNATE_GCS_RETURN_(code) /* next token must be ; */ +#if INCLUDE_ALL_GCS +#define NOT_ALL_GCS_RETURN /* next token must be ; */ +#define NOT_ALL_GCS_RETURN_(code) /* next token must be ; */ #else -#define NOT_ALTERNATE_GCS_RETURN {} -#define NOT_ALTERNATE_GCS_RETURN_(code) { return code; } -#endif // INCLUDE_ALTERNATE_GCS +#define NOT_ALL_GCS_RETURN {} +#define NOT_ALL_GCS_RETURN_(code) { return code; } +#endif // INCLUDE_ALL_GCS #ifndef INCLUDE_NMT #define INCLUDE_NMT 1 @@ -201,14 +201,6 @@ #define NOT_GRAALVM(code) code #endif // GRAAL -#ifdef HIGH_LEVEL_INTERPRETER -#define HIGH_LEVEL_INTERPRETER_ONLY(code) code -#define NOT_HIGH_LEVEL_INTERPRETER(code) -#else -#define HIGH_LEVEL_INTERPRETER_ONLY(code) -#define NOT_HIGH_LEVEL_INTERPRETER(code) code -#endif // HIGH_LEVEL_INTERPRETER - #ifdef TIERED #define TIERED_ONLY(code) code #define NOT_TIERED(code) diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/utilities/ostream.cpp --- a/src/share/vm/utilities/ostream.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/utilities/ostream.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -102,7 +102,6 @@ result_len = strlen(result); } else { DEBUG_ONLY(warning("increase O_BUFLEN in ostream.hpp -- output truncated");) - result = buffer; result_len = buflen - 1; buffer[result_len] = 0; @@ -432,7 +431,7 @@ rotatingFileStream::rotatingFileStream(const char* file_name) { _cur_file_num = 0; - _bytes_writen = 0L; + _bytes_written = 0L; _file_name = NEW_C_HEAP_ARRAY(char, strlen(file_name)+10, mtInternal); jio_snprintf(_file_name, strlen(file_name)+10, "%s.%d", file_name, _cur_file_num); _file = fopen(_file_name, "w"); @@ -441,7 +440,7 @@ rotatingFileStream::rotatingFileStream(const char* file_name, const char* opentype) { _cur_file_num = 0; - _bytes_writen = 0L; + _bytes_written = 0L; _file_name = NEW_C_HEAP_ARRAY(char, strlen(file_name)+10, mtInternal); jio_snprintf(_file_name, strlen(file_name)+10, "%s.%d", file_name, _cur_file_num); _file = fopen(_file_name, opentype); @@ -449,10 +448,9 @@ } void rotatingFileStream::write(const char* s, size_t len) { - if (_file != NULL) { - // Make an unused local variable to avoid warning from gcc 4.x compiler. + if (_file != NULL) { size_t count = fwrite(s, 1, len, _file); - Atomic::add((jlong)count, &_bytes_writen); + _bytes_written += count; } update_position(s, len); } @@ -466,7 +464,10 @@ // concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log // must be synchronized. void rotatingFileStream::rotate_log() { - if (_bytes_writen < (jlong)GCLogFileSize) return; + if (_bytes_written < (jlong)GCLogFileSize) { + return; + } + #ifdef ASSERT Thread *thread = Thread::current(); assert(thread == NULL || @@ -476,7 +477,7 @@ if (NumberOfGCLogFiles == 1) { // rotate in same file rewind(); - _bytes_writen = 0L; + _bytes_written = 0L; return; } @@ -492,7 +493,7 @@ } _file = fopen(_file_name, "w"); if (_file != NULL) { - _bytes_writen = 0L; + _bytes_written = 0L; _need_close = true; } else { tty->print_cr("failed to open rotation log file %s due to %s\n", @@ -656,9 +657,7 @@ // Print it as a java-style property list. // System properties don't generally contain newlines, so don't bother with unparsing. for (SystemProperty* p = Arguments::system_properties(); p != NULL; p = p->next()) { - xs->text()->print(p->key() ? p->key() : ""); - xs->text()->print("="); - xs->text()->print_cr(p->value() ? p->value() : ""); + xs->text()->print_cr("%s=%s", p->key(), p->value()); } xs->tail("properties"); } diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/utilities/ostream.hpp --- a/src/share/vm/utilities/ostream.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/utilities/ostream.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -231,7 +231,7 @@ class rotatingFileStream : public fileStream { protected: char* _file_name; - jlong _bytes_writen; + jlong _bytes_written; uintx _cur_file_num; // current logfile rotation number, from 0 to MaxGCLogFileNumbers-1 public: rotatingFileStream(const char* file_name); diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/utilities/top.hpp --- a/src/share/vm/utilities/top.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/utilities/top.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -33,18 +33,18 @@ #include "utilities/macros.hpp" #include "utilities/ostream.hpp" #include "utilities/sizes.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1_globals.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 #include "c1/c1_globals.hpp" #endif +#ifdef COMPILER2 +#include "opto/c2_globals.hpp" +#endif #ifdef GRAAL #include "graal/graalGlobals.hpp" #endif -#ifdef COMPILER2 -#include "opto/c2_globals.hpp" -#endif // THIS FILE IS INTESIONALLY LEFT EMPTY // IT IS USED TO MINIMIZE THE NUMBER OF DEPENDENCIES IN includeDB diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/utilities/vmError.cpp --- a/src/share/vm/utilities/vmError.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/utilities/vmError.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -491,30 +491,6 @@ print_bug_submit_message(st, _thread); } -#ifdef GRAAL - STEP(67, "(printing debug scope)" ) - - if (_verbose) { - if (_thread != NULL && _thread->is_Java_thread()) { - JavaThread* javaThread = (JavaThread*) _thread; - DebugScopedValue* ds = javaThread->debug_scope(); - int level = 0; - while (ds != NULL) { - if (level == 0) { - st->cr(); - st->print_cr("--------------- D E B U G S C O P E ---------------"); - st->cr(); - } - st->print("%d: ", level); - ds->print(st); - st->cr(); - ds = ds->parent(); - level++; - } - } - } -#endif - STEP(70, "(printing thread)" ) if (_verbose) { diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/utilities/yieldingWorkgroup.cpp --- a/src/share/vm/utilities/yieldingWorkgroup.cpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/utilities/yieldingWorkgroup.cpp Thu Mar 21 14:11:13 2013 +0100 @@ -23,9 +23,8 @@ */ #include "precompiled.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" #include "utilities/yieldingWorkgroup.hpp" -#endif // Forward declaration of classes declared here. diff -r dee7c8b578c7 -r c3657d00e343 src/share/vm/utilities/yieldingWorkgroup.hpp --- a/src/share/vm/utilities/yieldingWorkgroup.hpp Thu Mar 21 11:30:38 2013 +0100 +++ b/src/share/vm/utilities/yieldingWorkgroup.hpp Thu Mar 21 14:11:13 2013 +0100 @@ -25,9 +25,10 @@ #ifndef SHARE_VM_UTILITIES_YIELDINGWORKGROUP_HPP #define SHARE_VM_UTILITIES_YIELDINGWORKGROUP_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "utilities/workgroup.hpp" -#endif +#endif // INCLUDE_ALL_GCS // Forward declarations diff -r dee7c8b578c7 -r c3657d00e343 test/TEST.ROOT --- a/test/TEST.ROOT Thu Mar 21 11:30:38 2013 +0100 +++ b/test/TEST.ROOT Thu Mar 21 14:11:13 2013 +0100 @@ -28,4 +28,4 @@ # DO NOT EDIT without first contacting hotspot-regtest@sun.com # The list of keywords supported in this test suite -keys=cte_test +keys=cte_test jcmd nmt regression gc diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/5091921/Test6850611.java --- a/test/compiler/5091921/Test6850611.java Thu Mar 21 11:30:38 2013 +0100 +++ b/test/compiler/5091921/Test6850611.java Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -27,7 +27,7 @@ * @bug 6850611 * @summary int / long arithmetic seems to be broken in 1.6.0_14 HotSpot Server VM (Win XP) * - * @run main Test6850611 + * @run main/timeout=480 Test6850611 */ public class Test6850611 { diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/5091921/Test6890943.java --- a/test/compiler/5091921/Test6890943.java Thu Mar 21 11:30:38 2013 +0100 +++ b/test/compiler/5091921/Test6890943.java Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -27,7 +27,7 @@ * @bug 6890943 * @summary JVM mysteriously gives wrong result on 64-bit 1.6 VMs in hotspot mode. * - * @run shell Test6890943.sh + * @run shell/timeout=240 Test6890943.sh */ import java.util.*; import java.io.*; diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/5091921/Test6890943.sh --- a/test/compiler/5091921/Test6890943.sh Thu Mar 21 11:30:38 2013 +0100 +++ b/test/compiler/5091921/Test6890943.sh Thu Mar 21 14:11:13 2013 +0100 @@ -1,6 +1,6 @@ #!/bin/sh # -# 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 @@ -52,7 +52,10 @@ ${TESTJAVA}/bin/javac -d . Test6890943.java -${TESTJAVA}/bin/java -XX:-PrintVMOptions ${TESTVMOPTS} Test6890943 < input6890943.txt > test.out 2>&1 +${TESTJAVA}/bin/java -XX:-PrintVMOptions -XX:+IgnoreUnrecognizedVMOptions ${TESTVMOPTS} Test6890943 < input6890943.txt > pretest.out 2>&1 + +# This test sometimes tickles an unrelated performance warning that interferes with diff. +grep -v 'warning: Performance bug: SystemDictionary' pretest.out > test.out diff output6890943.txt test.out diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/5091921/Test6905845.java --- a/test/compiler/5091921/Test6905845.java Thu Mar 21 11:30:38 2013 +0100 +++ b/test/compiler/5091921/Test6905845.java Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -27,7 +27,7 @@ * @bug 6905845 * @summary Server VM improperly optimizing away loop. * - * @run main Test6905845 + * @run main/timeout=480 Test6905845 */ public class Test6905845 { diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/5091921/Test6992759.java --- a/test/compiler/5091921/Test6992759.java Thu Mar 21 11:30:38 2013 +0100 +++ b/test/compiler/5091921/Test6992759.java Thu Mar 21 14:11:13 2013 +0100 @@ -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 @@ -27,7 +27,7 @@ * @bug 6992759 * @summary Bad code generated for integer <= comparison, fails for Integer.MAX_VALUE * - * @run main Test6992759 + * @run main/timeout=240 Test6992759 */ public class Test6992759 { diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/6852078/Test6852078.java --- a/test/compiler/6852078/Test6852078.java Thu Mar 21 11:30:38 2013 +0100 +++ b/test/compiler/6852078/Test6852078.java Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 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 @@ -27,7 +27,7 @@ * @bug 6852078 * @summary Disable SuperWord optimization for unsafe read/write * - * @run main/othervm Test6852078 + * @run main Test6852078 */ import java.util.*; @@ -50,7 +50,11 @@ } public static void main(String [] args) { + long start = System.currentTimeMillis(); for (int i=0; i<2000; i++) { + // To protect slow systems from test-too-long timeouts + if ((i > 100) && ((System.currentTimeMillis() - start) > 100000)) + break; Test6852078 t = new Test6852078(args); } } diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/7009359/Test7009359.java --- a/test/compiler/7009359/Test7009359.java Thu Mar 21 11:30:38 2013 +0100 +++ b/test/compiler/7009359/Test7009359.java Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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,13 +27,13 @@ * @bug 7009359 * @summary HS with -XX:+AggressiveOpts optimize new StringBuffer(null) so it does not throw NPE as expected * - * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+OptimizeStringConcat -XX:CompileCommand=exclude,Test7009359,main Test7009359 + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+OptimizeStringConcat -XX:CompileCommand=dontinline,Test7009359,stringmakerBUG Test7009359 * */ public class Test7009359 { public static void main (String[] args) { - for(int i = 0; i < 1000000; i++) { + for(int i = 0; i < 100000; i++) { if(!stringmakerBUG(null).equals("NPE")) { System.out.println("StringBuffer(null) does not throw NPE"); System.exit(97); diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/8004741/Test8004741.java --- a/test/compiler/8004741/Test8004741.java Thu Mar 21 11:30:38 2013 +0100 +++ b/test/compiler/8004741/Test8004741.java Thu Mar 21 14:11:13 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,70 +25,160 @@ * @test Test8004741.java * @bug 8004741 * @summary Missing compiled exception handle table entry for multidimensional array allocation + * @run main/othervm -Xmx64m -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:+StressCompiledExceptionHandlers -XX:+SafepointALot -XX:GuaranteedSafepointInterval=100 Test8004741 * @run main/othervm -Xmx64m -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:+StressCompiledExceptionHandlers Test8004741 - * */ import java.util.*; public class Test8004741 extends Thread { + static int passed = 0; + + /** + * Loop forever allocating 2-d arrays. + * Catches and rethrows all exceptions; in the case of ThreadDeath, increments passed. + * Note that passed is incremented here because this is the exception handler with + * the smallest scope; we only want to declare success in the case where it is highly + * likely that the test condition + * (exception in 2-d array alloc interrupted by ThreadDeath) + * actually occurs. + */ static int[][] test(int a, int b) throws Exception { - int[][] ar = null; + int[][] ar; try { ar = new int[a][b]; - } catch (Error e) { - System.out.println("test got Error"); - passed = true; - throw(e); - } catch (Exception e) { - System.out.println("test got Exception"); + } catch (ThreadDeath e) { + System.out.println("test got ThreadDeath"); + passed++; throw(e); } return ar; } - static boolean passed = false; + /* Cookbook wait-notify to track progress of test thread. */ + Object progressLock = new Object(); + private static final int NOT_STARTED = 0; + private static final int RUNNING = 1; + private static final int STOPPING = 2; + + int progressState = NOT_STARTED; - public void run() { - System.out.println("test started"); - try { - while(true) { - test(2,20000); + void toState(int state) { + synchronized (progressLock) { + progressState = state; + progressLock.notify(); + } + } + + void waitFor(int state) { + synchronized (progressLock) { + while (progressState < state) { + try { + progressLock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + System.out.println("unexpected InterruptedException"); + fail(); } - } catch (ThreadDeath e) { - System.out.println("test got ThreadDeath"); - passed = true; - } catch (Error e) { - e.printStackTrace(); - System.out.println("test got Error"); - } catch (Exception e) { - e.printStackTrace(); - System.out.println("test got Exception"); + } + if (progressState > state) { + System.out.println("unexpected test state change, expected " + + state + " but saw " + progressState); + fail(); + } + } + } + + /** + * Loops running test until some sort of an exception or error, + * expects to see ThreadDeath. + */ + public void run() { + try { + // Print before state change, so that other thread is most likely + // to see this thread executing calls to test() in a loop. + System.out.println("thread running"); + toState(RUNNING); + while (true) { + // (2,2) (2,10) (2,100) were observed to tickle the bug; + test(2, 100); } + } catch (ThreadDeath e) { + // nothing to say, passing was incremented by the test. + } catch (Throwable e) { + e.printStackTrace(); + System.out.println("unexpected Throwable " + e); + fail(); + } + toState(STOPPING); + } + + /** + * Runs a single trial of the test in a thread. + * No single trial is definitive, since the ThreadDeath + * exception might not land in the tested region of code. + */ + public static void threadTest() throws InterruptedException { + Test8004741 t = new Test8004741(); + t.start(); + t.waitFor(RUNNING); + Thread.sleep(100); + System.out.println("stopping thread"); + t.stop(); + t.waitFor(STOPPING); + t.join(); } public static void main(String[] args) throws Exception { + // Warm up "test" + // t will never be started. for (int n = 0; n < 11000; n++) { - test(2, 20); + test(2, 100); + } + + // Will this sleep help ensure that the compiler is run? + Thread.sleep(500); + passed = 0; + + try { + test(-1, 100); + System.out.println("Missing NegativeArraySizeException #1"); + fail(); + } catch ( java.lang.NegativeArraySizeException e ) { + System.out.println("Saw expected NegativeArraySizeException #1"); } - // First test exception catch - Test8004741 t = new Test8004741(); + try { + test(100, -1); + fail(); + System.out.println("Missing NegativeArraySizeException #2"); + fail(); + } catch ( java.lang.NegativeArraySizeException e ) { + System.out.println("Saw expected NegativeArraySizeException #2"); + } - passed = false; - t.start(); - Thread.sleep(1000); - t.stop(); + /* Test repetitions. If the test succeeds-mostly, it succeeds, + * as long as it does not crash (the outcome if the exception range + * table entry for the array allocation is missing). + */ + int N = 12; + for (int n = 0; n < N; n++) { + threadTest(); + } - Thread.sleep(5000); - t.join(); - if (passed) { + if (passed > N/2) { + System.out.println("Saw " + passed + " out of " + N + " possible ThreadDeath hits"); System.out.println("PASSED"); } else { - System.out.println("FAILED"); - System.exit(97); + System.out.println("Too few ThreadDeath hits; expected at least " + N/2 + + " but saw only " + passed); + fail(); } } + static void fail() { + System.out.println("FAILED"); + System.exit(97); + } }; diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/8004867/TestIntAtomicCAS.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/8004867/TestIntAtomicCAS.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,969 @@ +/* + * 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 8004867 + * @summary VM crashing with assert "share/vm/opto/node.hpp:357 - assert(i < _max) failed: oob" + * + * @run main/othervm/timeout=300 -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:-OptimizeFill TestIntAtomicCAS + * @run main/othervm/timeout=300 -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:+OptimizeFill TestIntAtomicCAS + */ + +import java.util.concurrent.atomic.AtomicIntegerArray; + +public class TestIntAtomicCAS { + private static final int ARRLEN = 97; + private static final int ITERS = 11000; + private static final int OFFSET = 3; + private static final int SCALE = 2; + private static final int ALIGN_OFF = 8; + private static final int UNALIGN_OFF = 5; + + public static void main(String args[]) { + System.out.println("Testing Integer array atomic CAS operations"); + int errn = test(false); + if (errn > 0) { + System.err.println("FAILED: " + errn + " errors"); + System.exit(97); + } + System.out.println("PASSED"); + } + + static int test(boolean test_only) { + AtomicIntegerArray a1 = new AtomicIntegerArray(ARRLEN); + AtomicIntegerArray a2 = new AtomicIntegerArray(ARRLEN); + // Initialize + for (int i=0; i 0 || test_only) + return errn; + + // Initialize + for (int i=0; i= 0; i-=1) { + a.compareAndSet(i, old, -123); + } + } + static void test_vi_neg(AtomicIntegerArray a, int b, int old) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + a.compareAndSet(i, old, b); + } + } + static void test_cp_neg(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + a.compareAndSet(i, -123, b.get(i)); + } + } + static void test_2ci_neg(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + a.compareAndSet(i, 123, -123); + b.compareAndSet(i, 123, -103); + } + } + static void test_2vi_neg(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + a.compareAndSet(i, -123, c); + b.compareAndSet(i, -103, d); + } + } + static void test_ci_oppos(AtomicIntegerArray a, int old) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + a.compareAndSet((limit-i), old, -123); + } + } + static void test_vi_oppos(AtomicIntegerArray a, int b, int old) { + int limit = ARRLEN-1; + for (int i = limit; i >= 0; i-=1) { + a.compareAndSet((limit-i), old, b); + } + } + static void test_cp_oppos(AtomicIntegerArray a, AtomicIntegerArray b) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + a.compareAndSet(i, -123, b.get(limit-i)); + } + } + static void test_2ci_oppos(AtomicIntegerArray a, AtomicIntegerArray b) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + a.compareAndSet((limit-i), 123, -123); + b.compareAndSet(i, 123, -103); + } + } + static void test_2vi_oppos(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + int limit = ARRLEN-1; + for (int i = limit; i >= 0; i-=1) { + a.compareAndSet(i, -123, c); + b.compareAndSet((limit-i), -103, d); + } + } + static void test_ci_off(AtomicIntegerArray a, int old) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + a.compareAndSet((i+OFFSET), old, -123); + } + } + static void test_vi_off(AtomicIntegerArray a, int b, int old) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + a.compareAndSet((i+OFFSET), old, b); + } + } + static void test_cp_off(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + a.compareAndSet((i+OFFSET), -123, b.get(i+OFFSET)); + } + } + static void test_2ci_off(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + a.compareAndSet((i+OFFSET), 123, -123); + b.compareAndSet((i+OFFSET), 123, -103); + } + } + static void test_2vi_off(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + a.compareAndSet((i+OFFSET), -123, c); + b.compareAndSet((i+OFFSET), -103, d); + } + } + static void test_ci_inv(AtomicIntegerArray a, int k, int old) { + for (int i = 0; i < ARRLEN-k; i+=1) { + a.compareAndSet((i+k), old, -123); + } + } + static void test_vi_inv(AtomicIntegerArray a, int b, int k, int old) { + for (int i = 0; i < ARRLEN-k; i+=1) { + a.compareAndSet((i+k), old, b); + } + } + static void test_cp_inv(AtomicIntegerArray a, AtomicIntegerArray b, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + a.compareAndSet((i+k), -123, b.get(i+k)); + } + } + static void test_2ci_inv(AtomicIntegerArray a, AtomicIntegerArray b, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + a.compareAndSet((i+k), 123, -123); + b.compareAndSet((i+k), 123, -103); + } + } + static void test_2vi_inv(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + a.compareAndSet((i+k), -123, c); + b.compareAndSet((i+k), -103, d); + } + } + static void test_ci_scl(AtomicIntegerArray a, int old) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + a.compareAndSet((i*SCALE), old, -123); + } + } + static void test_vi_scl(AtomicIntegerArray a, int b, int old) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + a.compareAndSet((i*SCALE), old, b); + } + } + static void test_cp_scl(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + a.compareAndSet((i*SCALE), -123, b.get(i*SCALE)); + } + } + static void test_2ci_scl(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + a.compareAndSet((i*SCALE), 123, -123); + b.compareAndSet((i*SCALE), 123, -103); + } + } + static void test_2vi_scl(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + a.compareAndSet((i*SCALE), -123, c); + b.compareAndSet((i*SCALE), -103, d); + } + } + static void test_cp_alndst(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + a.compareAndSet((i+ALIGN_OFF), -1, b.get(i)); + } + } + static void test_cp_alnsrc(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + a.getAndSet(i, b.get(i+ALIGN_OFF)); + } + } + static void test_2ci_aln(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + a.compareAndSet((i+ALIGN_OFF), -1, -123); + b.getAndSet(i, -103); + } + } + static void test_2vi_aln(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + a.getAndSet(i, c); + b.getAndSet((i+ALIGN_OFF), d); + } + } + static void test_cp_unalndst(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + a.compareAndSet((i+UNALIGN_OFF), -1, b.get(i)); + } + } + static void test_cp_unalnsrc(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + a.getAndSet(i, b.get(i+UNALIGN_OFF)); + } + } + static void test_2ci_unaln(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + a.compareAndSet((i+UNALIGN_OFF), -1, -123); + b.getAndSet(i, -103); + } + } + static void test_2vi_unaln(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + a.getAndSet(i, c); + b.getAndSet((i+UNALIGN_OFF), d); + } + } + + static int verify(String text, int i, int elem, int val) { + if (elem != val) { + System.err.println(text + "[" + i + "] = " + elem + " != " + val); + return 1; + } + return 0; + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/8004867/TestIntAtomicOrdered.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/8004867/TestIntAtomicOrdered.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,969 @@ +/* + * 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 8004867 + * @summary VM crashing with assert "share/vm/opto/node.hpp:357 - assert(i < _max) failed: oob" + * + * @run main/othervm/timeout=300 -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:-OptimizeFill TestIntAtomicOrdered + * @run main/othervm/timeout=300 -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:+OptimizeFill TestIntAtomicOrdered + */ + +import java.util.concurrent.atomic.AtomicIntegerArray; + +public class TestIntAtomicOrdered { + private static final int ARRLEN = 97; + private static final int ITERS = 11000; + private static final int OFFSET = 3; + private static final int SCALE = 2; + private static final int ALIGN_OFF = 8; + private static final int UNALIGN_OFF = 5; + + public static void main(String args[]) { + System.out.println("Testing Integer array atomic ordered operations"); + int errn = test(false); + if (errn > 0) { + System.err.println("FAILED: " + errn + " errors"); + System.exit(97); + } + System.out.println("PASSED"); + } + + static int test(boolean test_only) { + AtomicIntegerArray a1 = new AtomicIntegerArray(ARRLEN); + AtomicIntegerArray a2 = new AtomicIntegerArray(ARRLEN); + // Initialize + for (int i=0; i 0 || test_only) + return errn; + + // Initialize + for (int i=0; i= 0; i-=1) { + a.lazySet(i,-123); + } + } + static void test_vi_neg(AtomicIntegerArray a, int b, int old) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + a.lazySet(i, b); + } + } + static void test_cp_neg(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + a.lazySet(i, b.get(i)); + } + } + static void test_2ci_neg(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + a.lazySet(i, -123); + b.lazySet(i, -103); + } + } + static void test_2vi_neg(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + a.lazySet(i, c); + b.lazySet(i, d); + } + } + static void test_ci_oppos(AtomicIntegerArray a, int old) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + a.lazySet((limit-i), -123); + } + } + static void test_vi_oppos(AtomicIntegerArray a, int b, int old) { + int limit = ARRLEN-1; + for (int i = limit; i >= 0; i-=1) { + a.lazySet((limit-i), b); + } + } + static void test_cp_oppos(AtomicIntegerArray a, AtomicIntegerArray b) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + a.lazySet(i, b.get(limit-i)); + } + } + static void test_2ci_oppos(AtomicIntegerArray a, AtomicIntegerArray b) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + a.lazySet((limit-i), -123); + b.lazySet(i, -103); + } + } + static void test_2vi_oppos(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + int limit = ARRLEN-1; + for (int i = limit; i >= 0; i-=1) { + a.lazySet(i, c); + b.lazySet((limit-i), d); + } + } + static void test_ci_off(AtomicIntegerArray a, int old) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + a.lazySet((i+OFFSET), -123); + } + } + static void test_vi_off(AtomicIntegerArray a, int b, int old) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + a.lazySet((i+OFFSET), b); + } + } + static void test_cp_off(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + a.lazySet((i+OFFSET), b.get(i+OFFSET)); + } + } + static void test_2ci_off(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + a.lazySet((i+OFFSET), -123); + b.lazySet((i+OFFSET), -103); + } + } + static void test_2vi_off(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + a.lazySet((i+OFFSET), c); + b.lazySet((i+OFFSET), d); + } + } + static void test_ci_inv(AtomicIntegerArray a, int k, int old) { + for (int i = 0; i < ARRLEN-k; i+=1) { + a.lazySet((i+k),-123); + } + } + static void test_vi_inv(AtomicIntegerArray a, int b, int k, int old) { + for (int i = 0; i < ARRLEN-k; i+=1) { + a.lazySet((i+k), b); + } + } + static void test_cp_inv(AtomicIntegerArray a, AtomicIntegerArray b, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + a.lazySet((i+k), b.get(i+k)); + } + } + static void test_2ci_inv(AtomicIntegerArray a, AtomicIntegerArray b, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + a.lazySet((i+k), -123); + b.lazySet((i+k), -103); + } + } + static void test_2vi_inv(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + a.lazySet((i+k), c); + b.lazySet((i+k), d); + } + } + static void test_ci_scl(AtomicIntegerArray a, int old) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + a.lazySet((i*SCALE), -123); + } + } + static void test_vi_scl(AtomicIntegerArray a, int b, int old) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + a.lazySet((i*SCALE), b); + } + } + static void test_cp_scl(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + a.lazySet((i*SCALE), b.get(i*SCALE)); + } + } + static void test_2ci_scl(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + a.lazySet((i*SCALE), -123); + b.lazySet((i*SCALE), -103); + } + } + static void test_2vi_scl(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + a.lazySet((i*SCALE), c); + b.lazySet((i*SCALE), d); + } + } + static void test_cp_alndst(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + a.lazySet((i+ALIGN_OFF), b.get(i)); + } + } + static void test_cp_alnsrc(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + a.lazySet(i, b.get(i+ALIGN_OFF)); + } + } + static void test_2ci_aln(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + a.lazySet((i+ALIGN_OFF), -123); + b.lazySet(i, -103); + } + } + static void test_2vi_aln(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + a.lazySet(i, c); + b.lazySet((i+ALIGN_OFF), d); + } + } + static void test_cp_unalndst(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + a.lazySet((i+UNALIGN_OFF), b.get(i)); + } + } + static void test_cp_unalnsrc(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + a.lazySet(i, b.get(i+UNALIGN_OFF)); + } + } + static void test_2ci_unaln(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + a.lazySet((i+UNALIGN_OFF), -123); + b.lazySet(i, -103); + } + } + static void test_2vi_unaln(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + a.lazySet(i, c); + b.lazySet((i+UNALIGN_OFF), d); + } + } + + static int verify(String text, int i, int elem, int val) { + if (elem != val) { + System.err.println(text + "[" + i + "] = " + elem + " != " + val); + return 1; + } + return 0; + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/8004867/TestIntAtomicVolatile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/8004867/TestIntAtomicVolatile.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,969 @@ +/* + * 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 8004867 + * @summary VM crashing with assert "share/vm/opto/node.hpp:357 - assert(i < _max) failed: oob" + * + * @run main/othervm/timeout=300 -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:-OptimizeFill TestIntAtomicVolatile + * @run main/othervm/timeout=300 -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:+OptimizeFill TestIntAtomicVolatile + */ + +import java.util.concurrent.atomic.AtomicIntegerArray; + +public class TestIntAtomicVolatile { + private static final int ARRLEN = 97; + private static final int ITERS = 11000; + private static final int OFFSET = 3; + private static final int SCALE = 2; + private static final int ALIGN_OFF = 8; + private static final int UNALIGN_OFF = 5; + + public static void main(String args[]) { + System.out.println("Testing Integer array atomic volatile operations"); + int errn = test(false); + if (errn > 0) { + System.err.println("FAILED: " + errn + " errors"); + System.exit(97); + } + System.out.println("PASSED"); + } + + static int test(boolean test_only) { + AtomicIntegerArray a1 = new AtomicIntegerArray(ARRLEN); + AtomicIntegerArray a2 = new AtomicIntegerArray(ARRLEN); + // Initialize + for (int i=0; i 0 || test_only) + return errn; + + // Initialize + for (int i=0; i= 0; i-=1) { + a.set(i,-123); + } + } + static void test_vi_neg(AtomicIntegerArray a, int b, int old) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + a.set(i, b); + } + } + static void test_cp_neg(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + a.set(i, b.get(i)); + } + } + static void test_2ci_neg(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + a.set(i, -123); + b.set(i, -103); + } + } + static void test_2vi_neg(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + a.set(i, c); + b.set(i, d); + } + } + static void test_ci_oppos(AtomicIntegerArray a, int old) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + a.set((limit-i), -123); + } + } + static void test_vi_oppos(AtomicIntegerArray a, int b, int old) { + int limit = ARRLEN-1; + for (int i = limit; i >= 0; i-=1) { + a.set((limit-i), b); + } + } + static void test_cp_oppos(AtomicIntegerArray a, AtomicIntegerArray b) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + a.set(i, b.get(limit-i)); + } + } + static void test_2ci_oppos(AtomicIntegerArray a, AtomicIntegerArray b) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + a.set((limit-i), -123); + b.set(i, -103); + } + } + static void test_2vi_oppos(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + int limit = ARRLEN-1; + for (int i = limit; i >= 0; i-=1) { + a.set(i, c); + b.set((limit-i), d); + } + } + static void test_ci_off(AtomicIntegerArray a, int old) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + a.set((i+OFFSET), -123); + } + } + static void test_vi_off(AtomicIntegerArray a, int b, int old) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + a.set((i+OFFSET), b); + } + } + static void test_cp_off(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + a.set((i+OFFSET), b.get(i+OFFSET)); + } + } + static void test_2ci_off(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + a.set((i+OFFSET), -123); + b.set((i+OFFSET), -103); + } + } + static void test_2vi_off(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + a.set((i+OFFSET), c); + b.set((i+OFFSET), d); + } + } + static void test_ci_inv(AtomicIntegerArray a, int k, int old) { + for (int i = 0; i < ARRLEN-k; i+=1) { + a.set((i+k),-123); + } + } + static void test_vi_inv(AtomicIntegerArray a, int b, int k, int old) { + for (int i = 0; i < ARRLEN-k; i+=1) { + a.set((i+k), b); + } + } + static void test_cp_inv(AtomicIntegerArray a, AtomicIntegerArray b, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + a.set((i+k), b.get(i+k)); + } + } + static void test_2ci_inv(AtomicIntegerArray a, AtomicIntegerArray b, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + a.set((i+k), -123); + b.set((i+k), -103); + } + } + static void test_2vi_inv(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + a.set((i+k), c); + b.set((i+k), d); + } + } + static void test_ci_scl(AtomicIntegerArray a, int old) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + a.set((i*SCALE), -123); + } + } + static void test_vi_scl(AtomicIntegerArray a, int b, int old) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + a.set((i*SCALE), b); + } + } + static void test_cp_scl(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + a.set((i*SCALE), b.get(i*SCALE)); + } + } + static void test_2ci_scl(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + a.set((i*SCALE), -123); + b.set((i*SCALE), -103); + } + } + static void test_2vi_scl(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + a.set((i*SCALE), c); + b.set((i*SCALE), d); + } + } + static void test_cp_alndst(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + a.set((i+ALIGN_OFF), b.get(i)); + } + } + static void test_cp_alnsrc(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + a.set(i, b.get(i+ALIGN_OFF)); + } + } + static void test_2ci_aln(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + a.set((i+ALIGN_OFF), -123); + b.set(i, -103); + } + } + static void test_2vi_aln(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + a.set(i, c); + b.set((i+ALIGN_OFF), d); + } + } + static void test_cp_unalndst(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + a.set((i+UNALIGN_OFF), b.get(i)); + } + } + static void test_cp_unalnsrc(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + a.set(i, b.get(i+UNALIGN_OFF)); + } + } + static void test_2ci_unaln(AtomicIntegerArray a, AtomicIntegerArray b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + a.set((i+UNALIGN_OFF), -123); + b.set(i, -103); + } + } + static void test_2vi_unaln(AtomicIntegerArray a, AtomicIntegerArray b, int c, int d) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + a.set(i, c); + b.set((i+UNALIGN_OFF), d); + } + } + + static int verify(String text, int i, int elem, int val) { + if (elem != val) { + System.err.println(text + "[" + i + "] = " + elem + " != " + val); + return 1; + } + return 0; + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/8004867/TestIntUnsafeCAS.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/8004867/TestIntUnsafeCAS.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,998 @@ +/* + * 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 8004867 + * @summary VM crashing with assert "share/vm/opto/node.hpp:357 - assert(i < _max) failed: oob" + * + * @run main/othervm/timeout=300 -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:-OptimizeFill TestIntUnsafeCAS + * @run main/othervm/timeout=300 -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:+OptimizeFill TestIntUnsafeCAS + */ + +import sun.misc.Unsafe; +import java.lang.reflect.*; + +public class TestIntUnsafeCAS { + private static final int ARRLEN = 97; + private static final int ITERS = 11000; + private static final int OFFSET = 3; + private static final int SCALE = 2; + private static final int ALIGN_OFF = 8; + private static final int UNALIGN_OFF = 5; + + private static final Unsafe unsafe; + private static final int BASE; + static { + try { + Class c = TestIntUnsafeCAS.class.getClassLoader().loadClass("sun.misc.Unsafe"); + Field f = c.getDeclaredField("theUnsafe"); + f.setAccessible(true); + unsafe = (Unsafe)f.get(c); + BASE = unsafe.arrayBaseOffset(int[].class); + } catch (Exception e) { + InternalError err = new InternalError(); + err.initCause(e); + throw err; + } + } + + public static void main(String args[]) { + System.out.println("Testing Integer array unsafe CAS operations"); + int errn = test(false); + if (errn > 0) { + System.err.println("FAILED: " + errn + " errors"); + System.exit(97); + } + System.out.println("PASSED"); + } + + static int test(boolean test_only) { + int[] a1 = new int[ARRLEN]; + int[] a2 = new int[ARRLEN]; + // Initialize + for (int i=0; i 0 || test_only) + return errn; + + // Initialize + for (int i=0; i= 0; i-=1) { + unsafe.compareAndSwapInt(a, byte_offset(i), old, -123); + } + } + static void test_vi_neg(int[] a, int b, int old) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + unsafe.compareAndSwapInt(a, byte_offset(i), old, b); + } + } + static void test_cp_neg(int[] a, int[] b) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + unsafe.compareAndSwapInt(a, byte_offset(i), -123, b[i]); + } + } + static void test_2ci_neg(int[] a, int[] b) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + unsafe.compareAndSwapInt(a, byte_offset(i), 123, -123); + unsafe.compareAndSwapInt(b, byte_offset(i), 123, -103); + } + } + static void test_2vi_neg(int[] a, int[] b, int c, int d) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + unsafe.compareAndSwapInt(a, byte_offset(i), -123, c); + unsafe.compareAndSwapInt(b, byte_offset(i), -103, d); + } + } + static void test_ci_oppos(int[] a, int old) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(limit-i), old, -123); + } + } + static void test_vi_oppos(int[] a, int b, int old) { + int limit = ARRLEN-1; + for (int i = limit; i >= 0; i-=1) { + unsafe.compareAndSwapInt(a, byte_offset(limit-i), old, b); + } + } + static void test_cp_oppos(int[] a, int[] b) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i), -123, b[limit-i]); + } + } + static void test_2ci_oppos(int[] a, int[] b) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(limit-i), 123, -123); + unsafe.compareAndSwapInt(b, byte_offset(i), 123, -103); + } + } + static void test_2vi_oppos(int[] a, int[] b, int c, int d) { + int limit = ARRLEN-1; + for (int i = limit; i >= 0; i-=1) { + unsafe.compareAndSwapInt(a, byte_offset(i), -123, c); + unsafe.compareAndSwapInt(b, byte_offset(limit-i), -103, d); + } + } + static void test_ci_off(int[] a, int old) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i+OFFSET), old, -123); + } + } + static void test_vi_off(int[] a, int b, int old) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i+OFFSET), old, b); + } + } + static void test_cp_off(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i+OFFSET), -123, b[i+OFFSET]); + } + } + static void test_2ci_off(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i+OFFSET), 123, -123); + unsafe.compareAndSwapInt(b, byte_offset(i+OFFSET), 123, -103); + } + } + static void test_2vi_off(int[] a, int[] b, int c, int d) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i+OFFSET), -123, c); + unsafe.compareAndSwapInt(b, byte_offset(i+OFFSET), -103, d); + } + } + static void test_ci_inv(int[] a, int k, int old) { + for (int i = 0; i < ARRLEN-k; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i+k), old, -123); + } + } + static void test_vi_inv(int[] a, int b, int k, int old) { + for (int i = 0; i < ARRLEN-k; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i+k), old, b); + } + } + static void test_cp_inv(int[] a, int[] b, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i+k), -123, b[i+k]); + } + } + static void test_2ci_inv(int[] a, int[] b, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i+k), 123, -123); + unsafe.compareAndSwapInt(b, byte_offset(i+k), 123, -103); + } + } + static void test_2vi_inv(int[] a, int[] b, int c, int d, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i+k), -123, c); + unsafe.compareAndSwapInt(b, byte_offset(i+k), -103, d); + } + } + static void test_ci_scl(int[] a, int old) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i*SCALE), old, -123); + } + } + static void test_vi_scl(int[] a, int b, int old) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i*SCALE), old, b); + } + } + static void test_cp_scl(int[] a, int[] b) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i*SCALE), -123, b[i*SCALE]); + } + } + static void test_2ci_scl(int[] a, int[] b) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i*SCALE), 123, -123); + unsafe.compareAndSwapInt(b, byte_offset(i*SCALE), 123, -103); + } + } + static void test_2vi_scl(int[] a, int[] b, int c, int d) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i*SCALE), -123, c); + unsafe.compareAndSwapInt(b, byte_offset(i*SCALE), -103, d); + } + } + static void test_cp_alndst(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i+ALIGN_OFF), -1, b[i]); + } + } + static void test_cp_alnsrc(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + int old = unsafe.getIntVolatile(a, byte_offset(i)); + unsafe.compareAndSwapInt(a, byte_offset(i), old, b[i+ALIGN_OFF]); + } + } + static void test_2ci_aln(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i+ALIGN_OFF), -1, -123); + int old = unsafe.getIntVolatile(b, byte_offset(i)); + unsafe.compareAndSwapInt(b, byte_offset(i), old, -103); + } + } + static void test_2vi_aln(int[] a, int[] b, int c, int d) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + int old = unsafe.getIntVolatile(a, byte_offset(i)); + unsafe.compareAndSwapInt(a, byte_offset(i), old, c); + old = unsafe.getIntVolatile(b, byte_offset(i+ALIGN_OFF)); + unsafe.compareAndSwapInt(b, byte_offset(i+ALIGN_OFF), old, d); + } + } + static void test_cp_unalndst(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i+UNALIGN_OFF), -1, b[i]); + } + } + static void test_cp_unalnsrc(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + int old = unsafe.getIntVolatile(a, byte_offset(i)); + unsafe.compareAndSwapInt(a, byte_offset(i), old, b[i+UNALIGN_OFF]); + } + } + static void test_2ci_unaln(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + unsafe.compareAndSwapInt(a, byte_offset(i+UNALIGN_OFF), -1, -123); + int old = unsafe.getIntVolatile(b, byte_offset(i)); + unsafe.compareAndSwapInt(b, byte_offset(i), old, -103); + } + } + static void test_2vi_unaln(int[] a, int[] b, int c, int d) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + int old = unsafe.getIntVolatile(a, byte_offset(i)); + unsafe.compareAndSwapInt(a, byte_offset(i), old, c); + old = unsafe.getIntVolatile(b, byte_offset(i+UNALIGN_OFF)); + unsafe.compareAndSwapInt(b, byte_offset(i+UNALIGN_OFF), old, d); + } + } + + static int verify(String text, int i, int elem, int val) { + if (elem != val) { + System.err.println(text + "[" + i + "] = " + elem + " != " + val); + return 1; + } + return 0; + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/8004867/TestIntUnsafeOrdered.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/8004867/TestIntUnsafeOrdered.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,990 @@ +/* + * 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 8004867 + * @summary VM crashing with assert "share/vm/opto/node.hpp:357 - assert(i < _max) failed: oob" + * + * @run main/othervm/timeout=300 -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:-OptimizeFill TestIntUnsafeOrdered + * @run main/othervm/timeout=300 -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:+OptimizeFill TestIntUnsafeOrdered + */ + +import sun.misc.Unsafe; +import java.lang.reflect.*; + +public class TestIntUnsafeOrdered { + private static final int ARRLEN = 97; + private static final int ITERS = 11000; + private static final int OFFSET = 3; + private static final int SCALE = 2; + private static final int ALIGN_OFF = 8; + private static final int UNALIGN_OFF = 5; + + private static final Unsafe unsafe; + private static final int BASE; + static { + try { + Class c = TestIntUnsafeOrdered.class.getClassLoader().loadClass("sun.misc.Unsafe"); + Field f = c.getDeclaredField("theUnsafe"); + f.setAccessible(true); + unsafe = (Unsafe)f.get(c); + BASE = unsafe.arrayBaseOffset(int[].class); + } catch (Exception e) { + InternalError err = new InternalError(); + err.initCause(e); + throw err; + } + } + + public static void main(String args[]) { + System.out.println("Testing Integer array unsafe ordered operations"); + int errn = test(false); + if (errn > 0) { + System.err.println("FAILED: " + errn + " errors"); + System.exit(97); + } + System.out.println("PASSED"); + } + + static int test(boolean test_only) { + int[] a1 = new int[ARRLEN]; + int[] a2 = new int[ARRLEN]; + // Initialize + for (int i=0; i 0 || test_only) + return errn; + + // Initialize + for (int i=0; i= 0; i-=1) { + unsafe.putOrderedInt(a, byte_offset(i), -123); + } + } + static void test_vi_neg(int[] a, int b, int old) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + unsafe.putOrderedInt(a, byte_offset(i), b); + } + } + static void test_cp_neg(int[] a, int[] b) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + unsafe.putOrderedInt(a, byte_offset(i), b[i]); + } + } + static void test_2ci_neg(int[] a, int[] b) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + unsafe.putOrderedInt(a, byte_offset(i), -123); + unsafe.putOrderedInt(b, byte_offset(i), -103); + } + } + static void test_2vi_neg(int[] a, int[] b, int c, int d) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + unsafe.putOrderedInt(a, byte_offset(i), c); + unsafe.putOrderedInt(b, byte_offset(i), d); + } + } + static void test_ci_oppos(int[] a, int old) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + unsafe.putOrderedInt(a, byte_offset(limit-i), -123); + } + } + static void test_vi_oppos(int[] a, int b, int old) { + int limit = ARRLEN-1; + for (int i = limit; i >= 0; i-=1) { + unsafe.putOrderedInt(a, byte_offset(limit-i), b); + } + } + static void test_cp_oppos(int[] a, int[] b) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i), b[limit-i]); + } + } + static void test_2ci_oppos(int[] a, int[] b) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + unsafe.putOrderedInt(a, byte_offset(limit-i), -123); + unsafe.putOrderedInt(b, byte_offset(i), -103); + } + } + static void test_2vi_oppos(int[] a, int[] b, int c, int d) { + int limit = ARRLEN-1; + for (int i = limit; i >= 0; i-=1) { + unsafe.putOrderedInt(a, byte_offset(i), c); + unsafe.putOrderedInt(b, byte_offset(limit-i), d); + } + } + static void test_ci_off(int[] a, int old) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i+OFFSET), -123); + } + } + static void test_vi_off(int[] a, int b, int old) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i+OFFSET), b); + } + } + static void test_cp_off(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i+OFFSET), b[i+OFFSET]); + } + } + static void test_2ci_off(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i+OFFSET), -123); + unsafe.putOrderedInt(b, byte_offset(i+OFFSET), -103); + } + } + static void test_2vi_off(int[] a, int[] b, int c, int d) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i+OFFSET), c); + unsafe.putOrderedInt(b, byte_offset(i+OFFSET), d); + } + } + static void test_ci_inv(int[] a, int k, int old) { + for (int i = 0; i < ARRLEN-k; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i+k), -123); + } + } + static void test_vi_inv(int[] a, int b, int k, int old) { + for (int i = 0; i < ARRLEN-k; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i+k), b); + } + } + static void test_cp_inv(int[] a, int[] b, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i+k), b[i+k]); + } + } + static void test_2ci_inv(int[] a, int[] b, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i+k), -123); + unsafe.putOrderedInt(b, byte_offset(i+k), -103); + } + } + static void test_2vi_inv(int[] a, int[] b, int c, int d, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i+k), c); + unsafe.putOrderedInt(b, byte_offset(i+k), d); + } + } + static void test_ci_scl(int[] a, int old) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i*SCALE), -123); + } + } + static void test_vi_scl(int[] a, int b, int old) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i*SCALE), b); + } + } + static void test_cp_scl(int[] a, int[] b) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i*SCALE), b[i*SCALE]); + } + } + static void test_2ci_scl(int[] a, int[] b) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i*SCALE), -123); + unsafe.putOrderedInt(b, byte_offset(i*SCALE), -103); + } + } + static void test_2vi_scl(int[] a, int[] b, int c, int d) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i*SCALE), c); + unsafe.putOrderedInt(b, byte_offset(i*SCALE), d); + } + } + static void test_cp_alndst(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i+ALIGN_OFF), b[i]); + } + } + static void test_cp_alnsrc(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i), b[i+ALIGN_OFF]); + } + } + static void test_2ci_aln(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i+ALIGN_OFF), -123); + unsafe.putOrderedInt(b, byte_offset(i), -103); + } + } + static void test_2vi_aln(int[] a, int[] b, int c, int d) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i), c); + unsafe.putOrderedInt(b, byte_offset(i+ALIGN_OFF), d); + } + } + static void test_cp_unalndst(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i+UNALIGN_OFF), b[i]); + } + } + static void test_cp_unalnsrc(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i), b[i+UNALIGN_OFF]); + } + } + static void test_2ci_unaln(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i+UNALIGN_OFF), -123); + unsafe.putOrderedInt(b, byte_offset(i), -103); + } + } + static void test_2vi_unaln(int[] a, int[] b, int c, int d) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + unsafe.putOrderedInt(a, byte_offset(i), c); + unsafe.putOrderedInt(b, byte_offset(i+UNALIGN_OFF), d); + } + } + + static int verify(String text, int i, int elem, int val) { + if (elem != val) { + System.err.println(text + "[" + i + "] = " + elem + " != " + val); + return 1; + } + return 0; + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/8004867/TestIntUnsafeVolatile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/8004867/TestIntUnsafeVolatile.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,990 @@ +/* + * 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 8004867 + * @summary VM crashing with assert "share/vm/opto/node.hpp:357 - assert(i < _max) failed: oob" + * + * @run main/othervm/timeout=300 -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:-OptimizeFill TestIntUnsafeVolatile + * @run main/othervm/timeout=300 -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:+OptimizeFill TestIntUnsafeVolatile + */ + +import sun.misc.Unsafe; +import java.lang.reflect.*; + +public class TestIntUnsafeVolatile { + private static final int ARRLEN = 97; + private static final int ITERS = 11000; + private static final int OFFSET = 3; + private static final int SCALE = 2; + private static final int ALIGN_OFF = 8; + private static final int UNALIGN_OFF = 5; + + private static final Unsafe unsafe; + private static final int BASE; + static { + try { + Class c = TestIntUnsafeVolatile.class.getClassLoader().loadClass("sun.misc.Unsafe"); + Field f = c.getDeclaredField("theUnsafe"); + f.setAccessible(true); + unsafe = (Unsafe)f.get(c); + BASE = unsafe.arrayBaseOffset(int[].class); + } catch (Exception e) { + InternalError err = new InternalError(); + err.initCause(e); + throw err; + } + } + + public static void main(String args[]) { + System.out.println("Testing Integer array unsafe volatile operations"); + int errn = test(false); + if (errn > 0) { + System.err.println("FAILED: " + errn + " errors"); + System.exit(97); + } + System.out.println("PASSED"); + } + + static int test(boolean test_only) { + int[] a1 = new int[ARRLEN]; + int[] a2 = new int[ARRLEN]; + // Initialize + for (int i=0; i 0 || test_only) + return errn; + + // Initialize + for (int i=0; i= 0; i-=1) { + unsafe.putIntVolatile(a, byte_offset(i), -123); + } + } + static void test_vi_neg(int[] a, int b, int old) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + unsafe.putIntVolatile(a, byte_offset(i), b); + } + } + static void test_cp_neg(int[] a, int[] b) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + unsafe.putIntVolatile(a, byte_offset(i), b[i]); + } + } + static void test_2ci_neg(int[] a, int[] b) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + unsafe.putIntVolatile(a, byte_offset(i), -123); + unsafe.putIntVolatile(b, byte_offset(i), -103); + } + } + static void test_2vi_neg(int[] a, int[] b, int c, int d) { + for (int i = ARRLEN-1; i >= 0; i-=1) { + unsafe.putIntVolatile(a, byte_offset(i), c); + unsafe.putIntVolatile(b, byte_offset(i), d); + } + } + static void test_ci_oppos(int[] a, int old) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + unsafe.putIntVolatile(a, byte_offset(limit-i), -123); + } + } + static void test_vi_oppos(int[] a, int b, int old) { + int limit = ARRLEN-1; + for (int i = limit; i >= 0; i-=1) { + unsafe.putIntVolatile(a, byte_offset(limit-i), b); + } + } + static void test_cp_oppos(int[] a, int[] b) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i), b[limit-i]); + } + } + static void test_2ci_oppos(int[] a, int[] b) { + int limit = ARRLEN-1; + for (int i = 0; i < ARRLEN; i+=1) { + unsafe.putIntVolatile(a, byte_offset(limit-i), -123); + unsafe.putIntVolatile(b, byte_offset(i), -103); + } + } + static void test_2vi_oppos(int[] a, int[] b, int c, int d) { + int limit = ARRLEN-1; + for (int i = limit; i >= 0; i-=1) { + unsafe.putIntVolatile(a, byte_offset(i), c); + unsafe.putIntVolatile(b, byte_offset(limit-i), d); + } + } + static void test_ci_off(int[] a, int old) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i+OFFSET), -123); + } + } + static void test_vi_off(int[] a, int b, int old) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i+OFFSET), b); + } + } + static void test_cp_off(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i+OFFSET), b[i+OFFSET]); + } + } + static void test_2ci_off(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i+OFFSET), -123); + unsafe.putIntVolatile(b, byte_offset(i+OFFSET), -103); + } + } + static void test_2vi_off(int[] a, int[] b, int c, int d) { + for (int i = 0; i < ARRLEN-OFFSET; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i+OFFSET), c); + unsafe.putIntVolatile(b, byte_offset(i+OFFSET), d); + } + } + static void test_ci_inv(int[] a, int k, int old) { + for (int i = 0; i < ARRLEN-k; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i+k), -123); + } + } + static void test_vi_inv(int[] a, int b, int k, int old) { + for (int i = 0; i < ARRLEN-k; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i+k), b); + } + } + static void test_cp_inv(int[] a, int[] b, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i+k), b[i+k]); + } + } + static void test_2ci_inv(int[] a, int[] b, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i+k), -123); + unsafe.putIntVolatile(b, byte_offset(i+k), -103); + } + } + static void test_2vi_inv(int[] a, int[] b, int c, int d, int k) { + for (int i = 0; i < ARRLEN-k; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i+k), c); + unsafe.putIntVolatile(b, byte_offset(i+k), d); + } + } + static void test_ci_scl(int[] a, int old) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i*SCALE), -123); + } + } + static void test_vi_scl(int[] a, int b, int old) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i*SCALE), b); + } + } + static void test_cp_scl(int[] a, int[] b) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i*SCALE), b[i*SCALE]); + } + } + static void test_2ci_scl(int[] a, int[] b) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i*SCALE), -123); + unsafe.putIntVolatile(b, byte_offset(i*SCALE), -103); + } + } + static void test_2vi_scl(int[] a, int[] b, int c, int d) { + for (int i = 0; i*SCALE < ARRLEN; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i*SCALE), c); + unsafe.putIntVolatile(b, byte_offset(i*SCALE), d); + } + } + static void test_cp_alndst(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i+ALIGN_OFF), b[i]); + } + } + static void test_cp_alnsrc(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i), b[i+ALIGN_OFF]); + } + } + static void test_2ci_aln(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i+ALIGN_OFF), -123); + unsafe.putIntVolatile(b, byte_offset(i), -103); + } + } + static void test_2vi_aln(int[] a, int[] b, int c, int d) { + for (int i = 0; i < ARRLEN-ALIGN_OFF; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i), c); + unsafe.putIntVolatile(b, byte_offset(i+ALIGN_OFF), d); + } + } + static void test_cp_unalndst(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i+UNALIGN_OFF), b[i]); + } + } + static void test_cp_unalnsrc(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i), b[i+UNALIGN_OFF]); + } + } + static void test_2ci_unaln(int[] a, int[] b) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i+UNALIGN_OFF), -123); + unsafe.putIntVolatile(b, byte_offset(i), -103); + } + } + static void test_2vi_unaln(int[] a, int[] b, int c, int d) { + for (int i = 0; i < ARRLEN-UNALIGN_OFF; i+=1) { + unsafe.putIntVolatile(a, byte_offset(i), c); + unsafe.putIntVolatile(b, byte_offset(i+UNALIGN_OFF), d); + } + } + + static int verify(String text, int i, int elem, int val) { + if (elem != val) { + System.err.println(text + "[" + i + "] = " + elem + " != " + val); + return 1; + } + return 0; + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/8007294/Test8007294.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/8007294/Test8007294.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,98 @@ +/* + * 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 8007294 + * @summary ReduceFieldZeroing doesn't check for dependent load and can lead to incorrect execution + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline -XX:-UseOnStackReplacement -XX:-BackgroundCompilation Test8007294 + * + */ + +public class Test8007294 { + + int i1; + int i2; + + Test8007294(int i1, int i2) { + this.i1 = i1; + this.i2 = i2; + } + + static int m(int v) { + return v; + } + + static Test8007294 test1() { + Test8007294 obj = new Test8007294(10, 100); + int v1 = obj.i1; + + int v3 = m(v1); + int v2 = obj.i2; + obj.i2 = v3; + obj.i1 = v2; + + return obj; + } + + static int test2(int i) { + int j = 0; + if (i > 0) { + j = 1; + } + + int[] arr = new int[10]; + arr[0] = 1; + arr[1] = 2; + int v1 = arr[j]; + arr[0] = 3; + arr[1] = 4; + + return v1; + } + + static public void main(String[] args) { + boolean failed = false; + for (int i = 0; i < 20000; i++) { + Test8007294 obj = test1(); + if (obj.i1 != 100 || obj.i2 != 10) { + System.out.println("FAILED test1 obj.i1 = " + obj.i1 +", obj.i2 = " + obj.i2); + failed = true; + break; + } + } + for (int i = 0; i < 20000; i++) { + int res = test2(1); + if (res != 2) { + System.out.println("FAILED test2 = " + res); + failed = true; + break; + } + } + if (failed) { + System.exit(97); + } else { + System.out.println("PASSED"); + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/8007722/Test8007722.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/8007722/Test8007722.java Thu Mar 21 14:11:13 2013 +0100 @@ -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. + */ + +/* + * @test + * @bug 8007722 + * @summary GetAndSetP's MachNode should capture bottom type + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation Test8007722 + * + */ + +import java.util.concurrent.atomic.*; + +public class Test8007722 { + + int i; + static AtomicReference ref; + + static int test(Test8007722 new_obj) { + Test8007722 o = ref.getAndSet(new_obj); + int ret = o.i; + o.i = 5; + return ret; + } + + static public void main(String[] args) { + Test8007722 obj = new Test8007722(); + ref = new AtomicReference(obj); + + for (int i = 0; i < 20000; i++) { + test(obj); + } + + System.out.println("PASSED"); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/whitebox/CompilerWhiteBoxTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/whitebox/CompilerWhiteBoxTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,142 @@ +/* + * 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 sun.hotspot.WhiteBox; +import sun.management.ManagementFactoryHelper; +import com.sun.management.HotSpotDiagnosticMXBean; + +import java.lang.reflect.Method; + +/* + * @author igor.ignatyev@oracle.com + */ +public abstract class CompilerWhiteBoxTest { + protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + protected static final Method METHOD = getMethod("method"); + protected static final int COMPILE_THRESHOLD + = Integer.parseInt(getVMOption("CompileThreshold", "10000")); + + protected static Method getMethod(String name) { + try { + return CompilerWhiteBoxTest.class.getDeclaredMethod(name); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException( + "exception on getting method " + name, e); + } + } + + protected static String getVMOption(String name, String defaultValue) { + String result; + HotSpotDiagnosticMXBean diagnostic + = ManagementFactoryHelper.getDiagnosticMXBean(); + result = diagnostic.getVMOption(name).getValue(); + return result == null ? defaultValue : result; + } + + protected final void runTest() throws RuntimeException { + if (ManagementFactoryHelper.getCompilationMXBean() == null) { + System.err.println( + "Warning: test is not applicable in interpreted mode"); + return; + } + System.out.println("at test's start:"); + printInfo(METHOD); + try { + test(); + } catch (Exception e) { + System.out.printf("on exception '%s':", e.getMessage()); + printInfo(METHOD); + throw new RuntimeException(e); + } + System.out.println("at test's end:"); + printInfo(METHOD); + } + + protected static void checkNotCompiled(Method method) { + if (WHITE_BOX.isMethodCompiled(method)) { + throw new RuntimeException(method + " must be not compiled"); + } + if (WHITE_BOX.getMethodCompilationLevel(method) != 0) { + throw new RuntimeException(method + " comp_level must be == 0"); + } + } + + protected static void checkCompiled(Method method) + throws InterruptedException { + final long start = System.currentTimeMillis(); + waitBackgroundCompilation(method); + if (WHITE_BOX.isMethodQueuedForCompilation(method)) { + System.err.printf("Warning: %s is still in queue after %dms%n", + method, System.currentTimeMillis() - start); + return; + } + if (!WHITE_BOX.isMethodCompiled(method)) { + throw new RuntimeException(method + " must be compiled"); + } + if (WHITE_BOX.getMethodCompilationLevel(method) == 0) { + throw new RuntimeException(method + " comp_level must be != 0"); + } + } + + protected static void waitBackgroundCompilation(Method method) + throws InterruptedException { + final Object obj = new Object(); + synchronized (obj) { + for (int i = 0; i < 10; ++i) { + if (!WHITE_BOX.isMethodQueuedForCompilation(method)) { + break; + } + obj.wait(1000); + } + } + } + + protected static void printInfo(Method method) { + System.out.printf("%n%s:%n", method); + System.out.printf("\tcompilable:\t%b%n", + WHITE_BOX.isMethodCompilable(method)); + System.out.printf("\tcompiled:\t%b%n", + WHITE_BOX.isMethodCompiled(method)); + System.out.printf("\tcomp_level:\t%d%n", + WHITE_BOX.getMethodCompilationLevel(method)); + System.out.printf("\tin_queue:\t%b%n", + WHITE_BOX.isMethodQueuedForCompilation(method)); + System.out.printf("compile_queues_size:\t%d%n%n", + WHITE_BOX.getCompileQueuesSize()); + } + + protected abstract void test() throws Exception; + + protected final int compile() { + int result = 0; + for (int i = 0; i < COMPILE_THRESHOLD; ++i) { + result += method(); + } + return result; + } + + + protected int method() { + return 42; + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/whitebox/DeoptimizeAllTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/whitebox/DeoptimizeAllTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,46 @@ +/* + * 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 DeoptimizeAllTest + * @library /testlibrary /testlibrary/whitebox + * @build DeoptimizeAllTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI DeoptimizeAllTest + * @author igor.ignatyev@oracle.com + */ +public class DeoptimizeAllTest extends CompilerWhiteBoxTest { + + public static void main(String[] args) throws Exception { + 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(); + checkNotCompiled(METHOD); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/whitebox/DeoptimizeMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/whitebox/DeoptimizeMethodTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,46 @@ +/* + * 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 DeoptimizeMethodTest + * @library /testlibrary /testlibrary/whitebox + * @build DeoptimizeMethodTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI DeoptimizeMethodTest + * @author igor.ignatyev@oracle.com + */ +public class DeoptimizeMethodTest extends CompilerWhiteBoxTest { + + public static void main(String[] args) throws Exception { + 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); + checkNotCompiled(METHOD); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/whitebox/IsMethodCompilableTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/whitebox/IsMethodCompilableTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -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. + */ + +/* + * @test IsMethodCompilableTest + * @bug 8007270 + * @library /testlibrary /testlibrary/whitebox + * @build IsMethodCompilableTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI IsMethodCompilableTest + * @author igor.ignatyev@oracle.com + */ +public class IsMethodCompilableTest extends CompilerWhiteBoxTest { + protected static final long PER_METHOD_RECOMPILATION_CUTOFF; + + static { + long tmp = Long.parseLong( + getVMOption("PerMethodRecompilationCutoff", "400")); + if (tmp == -1) { + PER_METHOD_RECOMPILATION_CUTOFF = -1 /* Inf */; + } else { + PER_METHOD_RECOMPILATION_CUTOFF = 1 + (0xFFFFFFFFL & tmp); + } + } + + public static void main(String[] args) throws Exception { + new IsMethodCompilableTest().runTest(); + } + + protected void test() throws Exception { + if (!WHITE_BOX.isMethodCompilable(METHOD)) { + throw new RuntimeException(METHOD + " must be compilable"); + } + System.out.println("PerMethodRecompilationCutoff = " + + PER_METHOD_RECOMPILATION_CUTOFF); + if (PER_METHOD_RECOMPILATION_CUTOFF == -1) { + System.err.println( + "Warning: test is not applicable if PerMethodRecompilationCutoff == Inf"); + return; + } + // to prevent inlining #method into #compile() + WHITE_BOX.setDontInlineMethod(METHOD, true); + boolean madeNotCompilable = false; + + for (long i = 0; i < PER_METHOD_RECOMPILATION_CUTOFF; ++i) { + compile(); + waitBackgroundCompilation(METHOD); + WHITE_BOX.deoptimizeMethod(METHOD); + if (!WHITE_BOX.isMethodCompilable(METHOD)) { + madeNotCompilable = true; + break; + } + } + if (!madeNotCompilable) { + 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"); + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/compiler/whitebox/MakeMethodNotCompilableTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/whitebox/MakeMethodNotCompilableTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,55 @@ +/* + * 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 MakeMethodNotCompilableTest + * @library /testlibrary /testlibrary/whitebox + * @build MakeMethodNotCompilableTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI MakeMethodNotCompilableTest + * @author igor.ignatyev@oracle.com + */ +public class MakeMethodNotCompilableTest extends CompilerWhiteBoxTest { + + public static void main(String[] args) throws Exception { + new MakeMethodNotCompilableTest().runTest(); + } + + protected void test() throws Exception { + if (!WHITE_BOX.isMethodCompilable(METHOD)) { + throw new RuntimeException(METHOD + " must be compilable"); + } + WHITE_BOX.makeMethodNotCompilable(METHOD); + if (WHITE_BOX.isMethodCompilable(METHOD)) { + 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 dee7c8b578c7 -r c3657d00e343 test/compiler/whitebox/SetDontInlineMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/whitebox/SetDontInlineMethodTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -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 SetDontInlineMethodTest + * @library /testlibrary /testlibrary/whitebox + * @build SetDontInlineMethodTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SetDontInlineMethodTest + * @author igor.ignatyev@oracle.com + */ +public class SetDontInlineMethodTest extends CompilerWhiteBoxTest { + + public static void main(String[] args) throws Exception { + new SetDontInlineMethodTest().runTest(); + } + + protected void test() throws Exception { + if (WHITE_BOX.setDontInlineMethod(METHOD, true)) { + throw new RuntimeException("on start " + METHOD + + " must be inlineable"); + } + if (!WHITE_BOX.setDontInlineMethod(METHOD, true)) { + throw new RuntimeException("after first change to true " + METHOD + + " must be not inlineable"); + } + if (!WHITE_BOX.setDontInlineMethod(METHOD, false)) { + throw new RuntimeException("after second change to true " + METHOD + + " must be still not inlineable"); + } + if (WHITE_BOX.setDontInlineMethod(METHOD, false)) { + throw new RuntimeException("after first change to false" + METHOD + + " must be inlineable"); + } + if (WHITE_BOX.setDontInlineMethod(METHOD, false)) { + throw new RuntimeException("after second change to false " + METHOD + + " must be inlineable"); + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/gc/8000311/Test8000311.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/8000311/Test8000311.java Thu Mar 21 14:11:13 2013 +0100 @@ -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. + */ + +/** + * @test Test8000311 + * @key gc + * @bug 8000311 + * @summary G1: ParallelGCThreads==0 broken + * @run main/othervm -XX:+UseG1GC -XX:ParallelGCThreads=0 -XX:+ResizePLAB -XX:+ExplicitGCInvokesConcurrent Test8000311 + * @author filipp.zhinkin@oracle.com + */ + +import java.util.*; + +public class Test8000311 { + public static void main(String args[]) { + for(int i = 0; i<100; i++) { + byte[] garbage = new byte[1000]; + System.gc(); + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/gc/TestG1ZeroPGCTJcmdThreadPrint.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/TestG1ZeroPGCTJcmdThreadPrint.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,54 @@ +/* + * 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 TestG1ZeroPGCTJcmdThreadPrint + * @key gc + * @bug 8005875 + * @summary Use jcmd to generate a thread dump of a Java program being run with PGCT=0 to verify 8005875 + * @library /testlibrary + * @run main/othervm -XX:+UseG1GC -XX:ParallelGCThreads=0 -XX:+IgnoreUnrecognizedVMOptions TestG1ZeroPGCTJcmdThreadPrint + */ + +import com.oracle.java.testlibrary.*; + +public class TestG1ZeroPGCTJcmdThreadPrint { + public static void main(String args[]) throws Exception { + + // Grab the pid from the current java process + String pid = Integer.toString(ProcessTools.getProcessId()); + + // Create a ProcessBuilder + ProcessBuilder pb = new ProcessBuilder(); + + // Run jcmd Thread.print + pb.command(JDKToolFinder.getJDKTool("jcmd"), pid, "Thread.print"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + // There shouldn't be a work gang for concurrent marking. + output.shouldNotContain("G1 Parallel Marking Threads"); + + // Make sure we didn't crash + output.shouldHaveExitValue(0); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/gc/metaspace/ClassMetaspaceSizeInJmapHeap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/metaspace/ClassMetaspaceSizeInJmapHeap.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,77 @@ +/* + * 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 ClassMetaspaceSizeInJmapHeap + * @bug 8004924 + * @summary Checks that jmap -heap contains the flag ClassMetaspaceSize + * @library /testlibrary + * @run main/othervm -XX:ClassMetaspaceSize=50m ClassMetaspaceSizeInJmapHeap + */ + +import com.oracle.java.testlibrary.*; +import java.nio.file.*; +import java.io.File; +import java.nio.charset.Charset; +import java.util.List; + +public class ClassMetaspaceSizeInJmapHeap { + 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); + + File out = new File("ClassMetaspaceSizeInJmapHeap.stdout.txt"); + pb.redirectOutput(out); + + File err = new File("ClassMetaspaceSizeInJmapHeap.stderr.txt"); + pb.redirectError(err); + + run(pb); + + OutputAnalyzer output = new OutputAnalyzer(read(out)); + output.shouldContain("ClassMetaspaceSize = 52428800 (50.0MB)"); + out.delete(); + } + + private static void run(ProcessBuilder pb) throws Exception { + Process p = pb.start(); + p.waitFor(); + int exitValue = p.exitValue(); + if (exitValue != 0) { + throw new Exception("jmap -heap exited with error code: " + exitValue); + } + } + + private static String read(File f) throws Exception { + Path p = f.toPath(); + List lines = Files.readAllLines(p, Charset.defaultCharset()); + + StringBuilder sb = new StringBuilder(); + for (String line : lines) { + sb.append(line).append('\n'); + } + return sb.toString(); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/gc/startup_warnings/TestCMS.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/startup_warnings/TestCMS.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,46 @@ +/* +* 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 TestCMS +* @key gc +* @bug 8006398 +* @summary Test that CMS does not print a warning message +* @library /testlibrary +*/ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + + +public class TestCMS { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseConcMarkSweepGC", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("warning"); + output.shouldNotContain("error"); + output.shouldHaveExitValue(0); + } + +} diff -r dee7c8b578c7 -r c3657d00e343 test/gc/startup_warnings/TestCMSIncrementalMode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/startup_warnings/TestCMSIncrementalMode.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,46 @@ + +/* +* 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 TestCMSIncrementalMode +* @key gc +* @bug 8006398 +* @summary Test that the deprecated CMSIncrementalMode print a warning message +* @library /testlibrary +*/ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +public class TestCMSIncrementalMode { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseConcMarkSweepGC", "-XX:+CMSIncrementalMode", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("warning: Using incremental CMS is deprecated and will likely be removed in a future release"); + output.shouldNotContain("error"); + output.shouldHaveExitValue(0); + } + +} diff -r dee7c8b578c7 -r c3657d00e343 test/gc/startup_warnings/TestCMSNoIncrementalMode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/startup_warnings/TestCMSNoIncrementalMode.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,45 @@ +/* +* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +*/ + +/* +* @test TestCMSNoIncrementalMode +* @key gc +* @bug 8006398 +* @summary Test that CMS with incremental mode turned off does not print a warning message +* @library /testlibrary +*/ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +public class TestCMSNoIncrementalMode { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseConcMarkSweepGC", "-XX:-CMSIncrementalMode", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("warning"); + output.shouldNotContain("error"); + output.shouldHaveExitValue(0); + } + +} diff -r dee7c8b578c7 -r c3657d00e343 test/gc/startup_warnings/TestDefNewCMS.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/startup_warnings/TestDefNewCMS.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,45 @@ +/* +* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +*/ + +/* +* @test TestDefNewCMS +* @key gc +* @bug 8006398 +* @summary Test that the deprecated DefNew+CMS combination print a warning message +* @library /testlibrary +*/ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +public class TestDefNewCMS { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:-UseParNewGC", "-XX:+UseConcMarkSweepGC", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("warning: Using the DefNew young collector with the CMS collector is deprecated and will likely be removed in a future release"); + output.shouldNotContain("error"); + output.shouldHaveExitValue(0); + } + +} diff -r dee7c8b578c7 -r c3657d00e343 test/gc/startup_warnings/TestG1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/startup_warnings/TestG1.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,45 @@ +/* +* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +*/ + +/* +* @test TestG1 +* @key gc +* @bug 8006398 +* @summary Test that the G1 collector does not print a warning message +* @library /testlibrary +*/ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +public class TestG1 { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("warning"); + output.shouldNotContain("error"); + output.shouldHaveExitValue(0); + } + +} diff -r dee7c8b578c7 -r c3657d00e343 test/gc/startup_warnings/TestIncGC.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/startup_warnings/TestIncGC.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,46 @@ +/* +* 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 TestIncGC +* @key gc +* @bug 8006398 +* @summary Test that the deprecated -Xincgc print a warning message +* @library /testlibrary +*/ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + + +public class TestIncGC { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xincgc", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("warning: Using incremental CMS is deprecated and will likely be removed in a future release"); + output.shouldNotContain("error"); + output.shouldHaveExitValue(0); + } + +} diff -r dee7c8b578c7 -r c3657d00e343 test/gc/startup_warnings/TestParNewCMS.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/startup_warnings/TestParNewCMS.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,46 @@ +/* +* 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 TestParNewCMS +* @key gc +* @bug 8006398 +* @summary Test that the combination ParNew+CMS does not print a warning message +* @library /testlibrary +*/ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + + +public class TestParNewCMS { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseParNewGC", "-XX:+UseConcMarkSweepGC", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("warning"); + output.shouldNotContain("error"); + output.shouldHaveExitValue(0); + } + +} diff -r dee7c8b578c7 -r c3657d00e343 test/gc/startup_warnings/TestParNewSerialOld.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/startup_warnings/TestParNewSerialOld.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,46 @@ +/* +* 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 TestParNewSerialOld +* @key gc +* @bug 8006398 +* @summary Test that the deprecated ParNew+SerialOld combination print a warning message +* @library /testlibrary +*/ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + + +public class TestParNewSerialOld { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseParNewGC", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("warning: Using the ParNew young collector with the Serial old collector is deprecated and will likely be removed in a future release"); + output.shouldNotContain("error"); + output.shouldHaveExitValue(0); + } + +} diff -r dee7c8b578c7 -r c3657d00e343 test/gc/startup_warnings/TestParallelGC.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/startup_warnings/TestParallelGC.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,46 @@ +/* +* 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 TestParallelGC +* @key gc +* @bug 8006398 +* @summary Test that ParallelGC does not print a warning message +* @library /testlibrary +*/ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + + +public class TestParallelGC { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseParallelGC", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("warning"); + output.shouldNotContain("error"); + output.shouldHaveExitValue(0); + } + +} diff -r dee7c8b578c7 -r c3657d00e343 test/gc/startup_warnings/TestParallelScavengeSerialOld.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/startup_warnings/TestParallelScavengeSerialOld.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,46 @@ +/* +* 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 TestParallelScavengeSerialOld +* @key gc +* @bug 8006398 +* @summary Test that the ParallelScavenge+SerialOld combination does not print a warning message +* @library /testlibrary +*/ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + + +public class TestParallelScavengeSerialOld { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseParallelGC", "-XX:-UseParallelOldGC", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("warning"); + output.shouldNotContain("error"); + output.shouldHaveExitValue(0); + } + +} diff -r dee7c8b578c7 -r c3657d00e343 test/gc/startup_warnings/TestSerialGC.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/startup_warnings/TestSerialGC.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,46 @@ +/* +* 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 TestSerialGC +* @key gc +* @bug 8006398 +* @summary Test that SerialGC does not print a warning message +* @library /testlibrary +*/ + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + + +public class TestSerialGC { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseSerialGC", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("warning"); + output.shouldNotContain("error"); + output.shouldHaveExitValue(0); + } + +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/7158988/FieldMonitor.java --- a/test/runtime/7158988/FieldMonitor.java Thu Mar 21 11:30:38 2013 +0100 +++ b/test/runtime/7158988/FieldMonitor.java Thu Mar 21 14:11:13 2013 +0100 @@ -24,8 +24,10 @@ /* * @test FieldMonitor.java * @bug 7158988 + * @key regression * @summary verify jvm does not crash while debugging - * @run shell TestFieldMonitor.sh + * @run compile TestPostFieldModification.java + * @run main/othervm FieldMonitor * @author axel.siebenborn@sap.com */ import java.io.BufferedReader; diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/7158988/TestFieldMonitor.sh --- a/test/runtime/7158988/TestFieldMonitor.sh Thu Mar 21 11:30:38 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -#!/bin/sh - -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 -fi - -# set platform-dependent variables -OS=`uname -s` -case "$OS" in - SunOS | Linux | Darwin) - NULL=/dev/null - PS=":" - FS="/" - ;; - Windows_95 | Windows_98 | Windows_ME ) - NULL=NUL - PS=";" - FS="\\" - echo "Test skipped, only for WinNT" - exit 0 - ;; - Windows_NT ) - NULL=NUL - PS=";" - FS="\\" - ;; - CYGWIN_NT* ) - NULL=/dev/null - PS=";" - FS="/" - ;; - CYGWIN_* ) - NULL=/dev/null - PS=";" - FS="/" - echo "Test skipped, only for WinNT" - exit 0 - ;; - * ) - echo "Unrecognized system!" - exit 1; - ;; -esac - -#CLASSPATH=.${PS}${TESTCLASSES} ; export CLASSPATH - -cp ${TESTSRC}${FS}*.java . - -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -fullversion - -${TESTJAVA}${FS}bin${FS}javac -classpath .${PS}$TESTJAVA${FS}lib${FS}tools.jar *.java - -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -classpath .${PS}$TESTJAVA${FS}lib${FS}tools.jar FieldMonitor > test.out - -grep "A fatal error has been detected" test.out > ${NULL} -if [ $? = 0 ]; then - cat test.out - STATUS=1 -fi - -exit $STATUS diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/8000968/Test8000968.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/8000968/Test8000968.sh Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,99 @@ +# +# 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 Test8000968.sh +# @bug 8000968 +# @summary NPG: UseCompressedKlassPointers asserts with ObjectAlignmentInBytes=32 +# @run shell Test8000968.sh +# + +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 + + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + Windows_* ) + FS="\\" + NULL=NUL + ;; + * ) + FS="/" + NULL=/dev/null + ;; +esac + +JAVA=${TESTJAVA}${FS}bin${FS}java + +# +# See if platform has 64 bit java. +# +${JAVA} ${TESTVMOPTS} -d64 -version 2>&1 | grep -i "does not support" > ${NULL} +if [ "$?" != "1" ] +then + printf "Platform is 32 bit, does not support -XX:ObjectAlignmentInBytes= option.\n" + printf "Passed.\n" + exit 0 +fi + +# +# Test -XX:ObjectAlignmentInBytes with -XX:+UseCompressedKlassPointers -XX:+UseCompressedOops. +# +${JAVA} ${TESTVMOPTS} -d64 -XX:+UseCompressedKlassPointers -XX:+UseCompressedOops -XX:ObjectAlignmentInBytes=16 -version 2>&1 > ${NULL} +if [ "$?" != "0" ] +then + printf "FAILED: -XX:ObjectAlignmentInBytes=16 option did not work.\n" + exit 1 +fi + +${JAVA} ${TESTVMOPTS} -d64 -XX:+UseCompressedKlassPointers -XX:+UseCompressedOops -XX:ObjectAlignmentInBytes=32 -version 2>&1 > ${NULL} +if [ "$?" != "0" ] +then + printf "FAILED: -XX:ObjectAlignmentInBytes=32 option did not work.\n" + exit 1 +fi + +${JAVA} ${TESTVMOPTS} -d64 -XX:+UseCompressedKlassPointers -XX:+UseCompressedOops -XX:ObjectAlignmentInBytes=64 -version 2>&1 > ${NULL} +if [ "$?" != "0" ] +then + printf "FAILED: -XX:ObjectAlignmentInBytes=64 option did not work.\n" + exit 1 +fi + +${JAVA} ${TESTVMOPTS} -d64 -XX:+UseCompressedKlassPointers -XX:+UseCompressedOops -XX:ObjectAlignmentInBytes=128 -version 2>&1 > ${NULL} +if [ "$?" != "0" ] +then + printf "FAILED: -XX:ObjectAlignmentInBytes=128 option did not work.\n" + exit 1 +fi + + +printf "Passed.\n" +exit 0 diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/8007320/ConstMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/8007320/ConstMethodTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,148 @@ +/* + * 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 8007320 + * @summary Test all optional fields in ConstMethod + * @compile -g -parameters ConstMethodTest.java + * @run main ConstMethodTest + */ + +import java.util.*; +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.io.Serializable; + +@Retention(RetentionPolicy.RUNTIME) +@interface MyAnnotation { + public String name(); + public String value(); + public String date() default "today"; +} + +@Target(ElementType.TYPE_USE) +@Retention(RetentionPolicy.RUNTIME) +@interface TypeAnno { + String value(); +} + +@Target(ElementType.TYPE_USE) +@Retention(RetentionPolicy.RUNTIME) +@interface TypeAnno2 { + String value(); +} + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@interface Named { + String value(); +} + +@Retention(RetentionPolicy.RUNTIME) +@interface ScalarTypesWithDefault { + byte b() default 11; + short s() default 12; + int i() default 13; + long l() default 14; + char c() default 'V'; +} + +// Some exception class +class OkException extends RuntimeException {}; + + +@MyAnnotation(name="someName", value = "Hello World") +public class ConstMethodTest { + + private static void check(boolean b) { + if (!b) + throw new RuntimeException(); + } + private static void fail(String msg) { + System.err.println(msg); + throw new RuntimeException(); + } + private static void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) { + } else { + fail(x + " not equal to " + y); + } + } + private static final String[] parameter_names = { + "parameter", "parameter2", "x" + }; + + // Declare a function with everything in it. + @MyAnnotation(name="someName", value="Hello World") + static void kitchenSinkFunc(@Named(value="aName") String parameter, + @Named("bName") String parameter2, + @ScalarTypesWithDefault T x) + throws @TypeAnno("RE") @TypeAnno2("RE2") RuntimeException, + NullPointerException, + @TypeAnno("AIOOBE") ArrayIndexOutOfBoundsException { + int i, j, k; + try { + System.out.println("calling kitchenSinkFunc " + parameter); + throw new OkException(); // to see stack trace with line numbers + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void test1() throws Throwable { + for (Method m : ConstMethodTest.class.getDeclaredMethods()) { + if (m.getName().equals("kitchenSinkFunc")) { + Annotation[][] ann = m.getParameterAnnotations(); + equal(ann.length, 3); + Annotation foo = ann[0][0]; + Annotation bar = ann[1][0]; + equal(foo.toString(), "@Named(value=aName)"); + equal(bar.toString(), "@Named(value=bName)"); + check(foo.equals(foo)); + check(bar.equals(bar)); + check(! foo.equals(bar)); + // method annotations + Annotation[] ann2 = m.getAnnotations(); + equal(ann2.length, 1); + Annotation mann = ann2[0]; + equal(mann.toString(), "@MyAnnotation(date=today, name=someName, value=Hello World)"); + // Test Method parameter names + Parameter[] parameters = m.getParameters(); + if(parameters == null) + throw new Exception("getParameters should never be null"); + for(int i = 0; i < parameters.length; i++) { + Parameter p = parameters[i]; + equal(parameters[i].getName(), parameter_names[i]); + } + } + } + } + + public static void main(java.lang.String[] unused) throws Throwable { + // pass 5 so kitchenSinkFunc is instantiated with an int + kitchenSinkFunc("parameter", "param2", 5); + test1(); + } +}; + diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/8007475/StackMapFrameTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/8007475/StackMapFrameTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,41 @@ +/* + * 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 8007475 + * @summary Test memory stomp in stack map test + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseMallocOnly StackMapFrameTest + */ +public class StackMapFrameTest { + + public static void foo() { + Object o = new Object(); + } + + public static void main(String args[]) { + for (int i = 0; i < 25000; i++) { + foo(); + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/8007736/TestStaticIF.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/8007736/TestStaticIF.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @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 dee7c8b578c7 -r c3657d00e343 test/runtime/CommandLine/BooleanFlagWithInvalidValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/CommandLine/BooleanFlagWithInvalidValue.java Thu Mar 21 14:11:13 2013 +0100 @@ -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. + */ + +/* + * @test + * @bug 8006298 + * @summary Setting an invalid value for a bool argument should result in a useful error message + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class BooleanFlagWithInvalidValue { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseLargePages=8", "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Improperly specified VM option 'UseLargePages=8'"); + output.shouldHaveExitValue(1); + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:-UseLargePages=8", "-version"); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Improperly specified VM option 'UseLargePages=8'"); + output.shouldHaveExitValue(1); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/CommandLine/FlagWithInvalidValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/CommandLine/FlagWithInvalidValue.java Thu Mar 21 14:11:13 2013 +0100 @@ -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. + */ + +/* + * @test + * @bug 8006298 + * @summary Setting a flag to an invalid value should print a useful error message + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class FlagWithInvalidValue { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:ObjectAlignmentInBytes=v", "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Improperly specified VM option 'ObjectAlignmentInBytes=v'"); + output.shouldHaveExitValue(1); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/CommandLine/NonBooleanFlagWithInvalidBooleanPrefix.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/CommandLine/NonBooleanFlagWithInvalidBooleanPrefix.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,50 @@ +/* + * 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 8006298 + * @summary Using a bool (+/-) prefix on non-bool flag should result in a useful error message + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class NonBooleanFlagWithInvalidBooleanPrefix { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:-ObjectAlignmentInBytes=16", "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Unexpected +/- setting in VM option 'ObjectAlignmentInBytes=16'"); + output.shouldHaveExitValue(1); + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+ObjectAlignmentInBytes=16", "-version"); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Unexpected +/- setting in VM option 'ObjectAlignmentInBytes=16'"); + output.shouldHaveExitValue(1); + + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/CommandLine/UnrecognizedVMOption.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/CommandLine/UnrecognizedVMOption.java Thu Mar 21 14:11:13 2013 +0100 @@ -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. + */ + +/* + * @test + * @bug 8006298 + * @summary Using an unrecognized VM option should print the name of the option + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class UnrecognizedVMOption { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:bogus_option", "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Unrecognized VM option 'bogus_option'"); + output.shouldHaveExitValue(1); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/NMT/AllocTestType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/AllocTestType.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,73 @@ +/* + * 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 dee7c8b578c7 -r c3657d00e343 test/runtime/NMT/BaselineWithParameter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/BaselineWithParameter.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,54 @@ +/* + * 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 8004802 + * @key nmt jcmd regression + * @summary Regression test for invoking a jcmd with baseline=false, result was that the target VM crashed + * @library /testlibrary + * @run main/othervm -XX:NativeMemoryTracking=detail BaselineWithParameter + */ + +import com.oracle.java.testlibrary.*; + +public class BaselineWithParameter { + + public static void main(String args[]) throws Exception { + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + OutputAnalyzer output; + + ProcessBuilder pb = new ProcessBuilder(); + + // Run 'jcmd VM.native_memory baseline=false' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "baseline=false"}); + pb.start(); + + // Run 'jcmd VM.native_memory summary=false' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary=false"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("No command to execute"); + + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/NMT/CommandLineDetail.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/CommandLineDetail.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @key nmt + * @summary Running with NMT detail should not result in an error or warning + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class CommandLineDetail { + + public static void main(String args[]) throws Exception { + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:NativeMemoryTracking=detail", + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("error"); + output.shouldNotContain("warning"); + output.shouldHaveExitValue(0); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/NMT/CommandLineEmptyArgument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/CommandLineEmptyArgument.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,41 @@ +/* + * 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 + * @summary Empty argument to NMT should result in an informative error message + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class CommandLineEmptyArgument { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:NativeMemoryTracking="); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Syntax error, expecting -XX:NativeMemoryTracking=[off|summary|detail]"); + output.shouldHaveExitValue(1); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/NMT/CommandLineInvalidArgument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/CommandLineInvalidArgument.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,41 @@ +/* + * 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 + * @summary Invalid argument to NMT should result in an informative error message + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class CommandLineInvalidArgument { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:NativeMemoryTracking=apa"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Syntax error, expecting -XX:NativeMemoryTracking=[off|summary|detail]"); + output.shouldHaveExitValue(1); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/NMT/CommandLineSummary.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/CommandLineSummary.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @key nmt + * @summary Running with NMT summary should not result in an error or warning + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class CommandLineSummary { + + public static void main(String args[]) throws Exception { + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:NativeMemoryTracking=summary", + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("error"); + output.shouldNotContain("warning"); + output.shouldHaveExitValue(0); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/NMT/CommandLineTurnOffNMT.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/CommandLineTurnOffNMT.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @key nmt + * @summary Turning off NMT should not result in an error or warning + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class CommandLineTurnOffNMT { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:NativeMemoryTracking=off", + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("error"); + output.shouldNotContain("warning"); + output.shouldHaveExitValue(0); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/NMT/JcmdScale.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/JcmdScale.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,67 @@ +/* + * 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 + * @summary Test the NMT scale parameter + * @library /testlibrary + * @run main/othervm -XX:NativeMemoryTracking=summary JcmdScale + */ + +import com.oracle.java.testlibrary.*; + +public class JcmdScale { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = new ProcessBuilder(); + OutputAnalyzer output; + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=KB"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("KB, committed="); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=MB"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("MB, committed="); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=GB"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("GB, committed="); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=apa"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Incorrect scale value: apa"); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary", "scale=GB"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("GB, committed="); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary", "scale=apa"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Incorrect scale value: apa"); + + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/NMT/JcmdWithNMTDisabled.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/JcmdWithNMTDisabled.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,63 @@ +/* + * 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 + * @summary Verify that jcmd correctly reports that NMT is not enabled + * @library /testlibrary + * First run without enabling NMT + * @run main/othervm JcmdWithNMTDisabled + * Then run with explicitly disabling NMT, should not be any difference + * @run main/othervm -XX:NativeMemoryTracking=off JcmdWithNMTDisabled + */ + +import com.oracle.java.testlibrary.*; + +public class JcmdWithNMTDisabled { + static ProcessBuilder pb = new ProcessBuilder(); + static String pid; + + public static void main(String args[]) throws Exception { + // Grab my own PID + pid = Integer.toString(ProcessTools.getProcessId()); + + jcmdCommand("summary"); + jcmdCommand("detail"); + jcmdCommand("baseline"); + jcmdCommand("summary.diff"); + jcmdCommand("detail.diff"); + jcmdCommand("scale=GB"); + jcmdCommand("shutdown"); + } + + // Helper method for invoking different jcmd calls, all should fail with the same message saying NMT is not enabled + public static void jcmdCommand(String command) throws Exception { + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", command}); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + // Verify that jcmd reports that NMT is not enabled + output.shouldContain("Native memory tracking is not enabled"); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/NMT/PrintNMTStatistics.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/PrintNMTStatistics.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,66 @@ +/* + * 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 regression + * @bug 8005936 + * @summary Make sure PrintNMTStatistics works on normal JVM exit + * @library /testlibrary /testlibrary/whitebox + * @run compile PrintNMTStatistics.java + */ + +import com.oracle.java.testlibrary.*; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import sun.hotspot.WhiteBox; + +public class PrintNMTStatistics { + + public static void main(String args[]) throws Exception { + + // We start a new java process running with an argument and use WB API to ensure + // we have data for NMT on VM exit + if (args.length > 0) { + // 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"); + } + return; + } + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:NativeMemoryTracking=summary", + "+XX:+PrintNMTStatistics", + "PrintNMTStatistics", + "test"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Java Heap (reserved="); + output.shouldNotContain("error"); + output.shouldNotContain("warning"); + output.shouldHaveExitValue(0); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/NMT/PrintNMTStatisticsWithNMTDisabled.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/PrintNMTStatisticsWithNMTDisabled.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @key nmt + * @summary Trying to enable PrintNMTStatistics should result in a warning + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class PrintNMTStatisticsWithNMTDisabled { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+PrintNMTStatistics", + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("warning: PrintNMTStatistics is disabled, because native memory tracking is not enabled"); + output.shouldHaveExitValue(0); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/NMT/ShutdownTwice.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/ShutdownTwice.java Thu Mar 21 14:11:13 2013 +0100 @@ -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. + */ + +/* + * @test + * @key nmt jcmd + * @summary Run shutdown twice + * @library /testlibrary + * @run main/othervm -XX:NativeMemoryTracking=detail ShutdownTwice + */ + +import com.oracle.java.testlibrary.*; + +public class ShutdownTwice { + + public static void main(String args[]) throws Exception { + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + OutputAnalyzer output; + + ProcessBuilder pb = new ProcessBuilder(); + + // Run 'jcmd VM.native_memory shutdown' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "shutdown"}); + output = new OutputAnalyzer(pb.start()); + + // Verify that jcmd reports that NMT is shutting down + output.shouldContain("Shutdown is in progress, it will take a few moments to completely shutdown"); + + // Run shutdown again + output = new OutputAnalyzer(pb.start()); + + // Verify that jcmd reports that NMT has been shutdown already + output.shouldContain("Native memory tracking has been shutdown by user"); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/NMT/SummaryAfterShutdown.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/SummaryAfterShutdown.java Thu Mar 21 14:11:13 2013 +0100 @@ -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. + */ + +/* + * @test + * @key nmt jcmd + * @summary Verify that jcmd correctly reports that NMT is not enabled after a shutdown + * @library /testlibrary + * @run main/othervm -XX:NativeMemoryTracking=detail SummaryAfterShutdown + */ + +import com.oracle.java.testlibrary.*; + +public class SummaryAfterShutdown { + + public static void main(String args[]) throws Exception { + OutputAnalyzer output; + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + + // Run 'jcmd VM.native_memory shutdown' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "shutdown"}); + output = new OutputAnalyzer(pb.start()); + + // Verify that jcmd reports that NMT is shutting down + output.shouldContain("Shutdown is in progress, it will take a few moments to completely shutdown"); + + // Run 'jcmd VM.native_memory summary' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary"}); + output = new OutputAnalyzer(pb.start()); + + // Verify that jcmd reports that NMT has been shutdown + output.shouldContain("Native memory tracking has been shutdown by user"); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/runtime/NMT/SummarySanityCheck.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/SummarySanityCheck.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,120 @@ +/* + * 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 + * @summary Sanity check the output of NMT + * @library /testlibrary /testlibrary/whitebox + * @build SummarySanityCheck + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+WhiteBoxAPI SummarySanityCheck + */ + +import com.oracle.java.testlibrary.*; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import sun.hotspot.WhiteBox; + +public class SummarySanityCheck { + + private static String jcmdout; + public static void main(String args[]) throws Exception { + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + + // 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"); + } + + ProcessBuilder pb = new ProcessBuilder(); + + // Run 'jcmd VM.native_memory summary scale=KB' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary", "scale=KB"}); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + jcmdout = output.getOutput(); + // Split by '-' to get the 'groups' + String[] lines = jcmdout.split("\n"); + + if (lines.length == 0) { + throwTestException("Failed to parse jcmd output"); + } + + int totalCommitted = 0, totalReserved = 0; + int totalCommittedSum = 0, totalReservedSum = 0; + + // Match '- (reserved=KB, committed=KB) + Pattern mtTypePattern = Pattern.compile("-\\s+(?[\\w\\s]+)\\(reserved=(?\\d+)KB,\\scommitted=(?\\d+)KB\\)"); + // Match 'Total: reserved=KB, committed=KB' + Pattern totalMemoryPattern = Pattern.compile("Total\\:\\s\\sreserved=(?\\d+)KB,\\s\\scommitted=(?\\d+)KB"); + + for (int i = 0; i < lines.length; i++) { + if (lines[i].startsWith("Total")) { + Matcher totalMemoryMatcher = totalMemoryPattern.matcher(lines[i]); + + if (totalMemoryMatcher.matches() && totalMemoryMatcher.groupCount() == 2) { + totalCommitted = Integer.parseInt(totalMemoryMatcher.group("committed")); + totalReserved = Integer.parseInt(totalMemoryMatcher.group("reserved")); + } else { + throwTestException("Failed to match the expected groups in 'Total' memory part"); + } + } else if (lines[i].startsWith("-")) { + Matcher typeMatcher = mtTypePattern.matcher(lines[i]); + if (typeMatcher.matches()) { + int typeCommitted = Integer.parseInt(typeMatcher.group("committed")); + int typeReserved = Integer.parseInt(typeMatcher.group("reserved")); + + // Make sure reserved is always less or equals + if (typeCommitted > typeReserved) { + throwTestException("Committed (" + typeCommitted + ") was more than Reserved (" + + typeReserved + ") for mtType: " + typeMatcher.group("typename")); + } + + // Add to total and compare them in the end + totalCommittedSum += typeCommitted; + totalReservedSum += typeReserved; + } else { + throwTestException("Failed to match the group on line " + i); + } + } + } + + // See if they add up correctly, rounding is a problem so make sure we're within +/- 8KB + int committedDiff = totalCommitted - totalCommittedSum; + if (committedDiff > 8 || committedDiff < -8) { + throwTestException("Total committed (" + totalCommitted + ") did not match the summarized committed (" + totalCommittedSum + ")" ); + } + + int reservedDiff = totalReserved - totalReservedSum; + if (reservedDiff > 8 || reservedDiff < -8) { + throwTestException("Total reserved (" + totalReserved + ") did not match the summarized reserved (" + totalReservedSum + ")" ); + } + } + + private static void throwTestException(String reason) throws Exception { + throw new Exception(reason + " . Stdout is :\n" + jcmdout); + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/sanity/WBApi.java --- a/test/sanity/WBApi.java Thu Mar 21 11:30:38 2013 +0100 +++ b/test/sanity/WBApi.java Thu Mar 21 14:11:13 2013 +0100 @@ -1,8 +1,33 @@ +/* + * 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 + * 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 WBApi * @summary verify that whitebox functions can be linked and executed - * @run compile -J-XX:+UnlockDiagnosticVMOptions -J-XX:+WhiteBoxAPI WBApi.java - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI WBApi + * @library /testlibrary /testlibrary/whitebox + * @build WBApi + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI WBApi */ import sun.hotspot.WhiteBox; diff -r dee7c8b578c7 -r c3657d00e343 test/serviceability/ParserTest.java --- a/test/serviceability/ParserTest.java Thu Mar 21 11:30:38 2013 +0100 +++ b/test/serviceability/ParserTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -1,8 +1,33 @@ +/* + * 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 + * 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 ParserTest - * @summary verify that whitebox functions can be linked and executed - * @run compile -J-XX:+UnlockDiagnosticVMOptions -J-XX:+WhiteBoxAPI ParserTest.java - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ParserTest + * @summary Test that the diagnostic command arguemnt parser works + * @library /testlibrary /testlibrary/whitebox + * @build ParserTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ParserTest */ import java.math.BigInteger; diff -r dee7c8b578c7 -r c3657d00e343 test/testlibrary/ClassFileInstaller.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary/ClassFileInstaller.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,53 @@ +/* + * 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.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; + +/** + * Dump a class file for a class on the class path in the current directory + */ +public class ClassFileInstaller { + /** + * @param args The names of the classes to dump + * @throws Exception + */ + public static void main(String... args) throws Exception { + for (String arg : args) { + ClassLoader cl = ClassFileInstaller.class.getClassLoader(); + + // Convert dotted class name to a path to a class file + String pathName = arg.replace('.', '/').concat(".class"); + InputStream is = cl.getResourceAsStream(pathName); + + // Create the class file's package directory + Path p = Paths.get(pathName); + Files.createDirectories(p.getParent()); + // Create the class file + Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING); + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/testlibrary/OutputAnalyzerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary/OutputAnalyzerTest.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,108 @@ +/* + * 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 the OutputAnalyzer utility class + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.OutputAnalyzer; + +public class OutputAnalyzerTest { + + public static void main(String args[]) throws Exception { + + String stdout = "aaaaaa"; + String stderr = "bbbbbb"; + + OutputAnalyzer output = new OutputAnalyzer(stdout, stderr); + + if (!stdout.equals(output.getStdout())) { + throw new Exception("getStdout() returned '" + output.getStdout() + "', expected '" + stdout + "'"); + } + + if (!stderr.equals(output.getStderr())) { + throw new Exception("getStderr() returned '" + output.getStderr() + "', expected '" + stderr + "'"); + } + + try { + output.shouldContain(stdout); + output.stdoutShouldContain(stdout); + output.shouldContain(stderr); + output.stderrShouldContain(stderr); + } catch (RuntimeException e) { + throw new Exception("shouldContain() failed", e); + } + + try { + output.shouldContain("cccc"); + throw new Exception("shouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stdoutShouldContain(stderr); + throw new Exception("stdoutShouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stderrShouldContain(stdout); + throw new Exception("stdoutShouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.shouldNotContain("cccc"); + output.stdoutShouldNotContain("cccc"); + output.stderrShouldNotContain("cccc"); + } catch (RuntimeException e) { + throw new Exception("shouldNotContain() failed", e); + } + + try { + output.shouldNotContain(stdout); + throw new Exception("shouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stdoutShouldNotContain(stdout); + throw new Exception("shouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stderrShouldNotContain(stderr); + throw new Exception("shouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/testlibrary/com/oracle/java/testlibrary/JDKToolFinder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary/com/oracle/java/testlibrary/JDKToolFinder.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,50 @@ +/* + * 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.io.File; + +public final class JDKToolFinder { + + private JDKToolFinder() { + } + + /** + * Returns the full path to an executable in jdk/bin based on System property + * test.jdk (set by jtreg test suite) + * + * @return Full path to an executable in jdk/bin + */ + public static String getJDKTool(String tool) { + String binPath = System.getProperty("test.jdk"); + if (binPath == null) { + throw new RuntimeException("System property 'test.jdk' not set. This property is normally set by jtreg. " + + "When running test separately, set this property using '-Dtest.jdk=/path/to/jdk'."); + } + + binPath += File.separatorChar + "bin" + File.separatorChar + tool; + + return binPath; + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,191 @@ +/* + * 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.io.IOException; + +public final class OutputAnalyzer { + + private final String stdout; + private final String stderr; + private final int exitValue; + + /** + * Create an OutputAnalyzer, a utility class for verifying output and exit + * value from a Process + * + * @param process Process to analyze + * @throws IOException If an I/O error occurs. + */ + public OutputAnalyzer(Process process) throws IOException { + OutputBuffer output = ProcessTools.getOutput(process); + exitValue = process.exitValue(); + this.stdout = output.getStdout(); + this.stderr = output.getStderr(); + } + + /** + * Create an OutputAnalyzer, a utility class for verifying output + * + * @param buf String buffer to analyze + */ + public OutputAnalyzer(String buf) { + this(buf, buf); + } + + /** + * Create an OutputAnalyzer, a utility class for verifying output + * + * @param stdout stdout buffer to analyze + * @param stderr stderr buffer to analyze + */ + public OutputAnalyzer(String stdout, String stderr) { + this.stdout = stdout; + this.stderr = stderr; + exitValue = -1; + } + + /** + * Verify that the stdout and stderr contents of output buffer contains the string + * + * @param expectedString String that buffer should contain + * @throws RuntimeException If the string was not found + */ + public void shouldContain(String expectedString) { + if (!stdout.contains(expectedString) && !stderr.contains(expectedString)) { + throw new RuntimeException("'" + expectedString + "' missing from stdout/stderr: [" + stdout + stderr + "]\n"); + } + } + + /** + * Verify that the stdout contents of output buffer contains the string + * + * @param expectedString String that buffer should contain + * @throws RuntimeException If the string was not found + */ + public void stdoutShouldContain(String expectedString) { + if (!stdout.contains(expectedString)) { + throw new RuntimeException("'" + expectedString + "' missing from stdout: [" + stdout + "]\n"); + } + } + + /** + * Verify that the stderr contents of output buffer contains the string + * + * @param expectedString String that buffer should contain + * @throws RuntimeException If the string was not found + */ + public void stderrShouldContain(String expectedString) { + if (!stderr.contains(expectedString)) { + throw new RuntimeException("'" + expectedString + "' missing from stderr: [" + stderr + "]\n"); + } + } + + /** + * Verify that the stdout and stderr contents of output buffer does not contain the string + * + * @param expectedString String that the buffer should not contain + * @throws RuntimeException If the string was found + */ + public void shouldNotContain(String notExpectedString) { + if (stdout.contains(notExpectedString)) { + throw new RuntimeException("'" + notExpectedString + "' found in stdout: [" + stdout + "]\n"); + } + if (stderr.contains(notExpectedString)) { + throw new RuntimeException("'" + notExpectedString + "' found in stderr: [" + stderr + "]\n"); + } + } + + /** + * Verify that the stdout contents of output buffer does not contain the string + * + * @param expectedString String that the buffer should not contain + * @throws RuntimeException If the string was found + */ + public void stdoutShouldNotContain(String notExpectedString) { + if (stdout.contains(notExpectedString)) { + throw new RuntimeException("'" + notExpectedString + "' found in stdout: [" + stdout + "]\n"); + } + } + + /** + * Verify that the stderr contents of output buffer does not contain the string + * + * @param expectedString String that the buffer should not contain + * @throws RuntimeException If the string was found + */ + public void stderrShouldNotContain(String notExpectedString) { + if (stderr.contains(notExpectedString)) { + throw new RuntimeException("'" + notExpectedString + "' 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); + } + } + + /** + * Get the contents of the output buffer (stdout and stderr) + * + * @return Content of the output buffer + */ + public String getOutput() { + return stdout + stderr; + } + + /** + * Get the contents of the stdout buffer + * + * @return Content of the stdout buffer + */ + public String getStdout() { + return stdout; + } + + /** + * Get the contents of the stderr buffer + * + * @return Content of the stderr buffer + */ + public String getStderr() { + return stderr; + } + + /** + * Get the process exit value + * + * @return Process exit value + */ + public int getExitValue() { + return exitValue; + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/testlibrary/com/oracle/java/testlibrary/OutputBuffer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary/com/oracle/java/testlibrary/OutputBuffer.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.java.testlibrary; + +public class OutputBuffer { + private final String stdout; + private final String stderr; + + /** + * Create an OutputBuffer, a class for storing and managing stdout and stderr + * results separately + * + * @param stdout stdout result + * @param stderr stderr result + */ + public OutputBuffer(String stdout, String stderr) { + this.stdout = stdout; + this.stderr = stderr; + } + + /** + * Returns the stdout result + * + * @return stdout result + */ + public String getStdout() { + return stdout; + } + + /** + * Returns the stderr result + * + * @return stderr result + */ + public String getStderr() { + return stderr; + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,141 @@ +/* + * 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.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; + +import sun.management.VMManagement; + +public final class ProcessTools { + + private ProcessTools() { + } + + /** + * Pumps stdout and stderr from running the process into a String. + * + * @param processHandler ProcessHandler to run. + * @return Output from process. + * @throws IOException If an I/O error occurs. + */ + public static OutputBuffer getOutput(ProcessBuilder processBuilder) throws IOException { + return getOutput(processBuilder.start()); + } + + /** + * Pumps stdout and stderr the running process into a String. + * + * @param process Process to pump. + * @return Output from process. + * @throws IOException If an I/O error occurs. + */ + public static OutputBuffer getOutput(Process process) throws IOException { + ByteArrayOutputStream stderrBuffer = new ByteArrayOutputStream(); + ByteArrayOutputStream stdoutBuffer = new ByteArrayOutputStream(); + StreamPumper outPumper = new StreamPumper(process.getInputStream(), stdoutBuffer); + StreamPumper errPumper = new StreamPumper(process.getErrorStream(), stderrBuffer); + Thread outPumperThread = new Thread(outPumper); + Thread errPumperThread = new Thread(errPumper); + + outPumperThread.setDaemon(true); + errPumperThread.setDaemon(true); + + outPumperThread.start(); + errPumperThread.start(); + + try { + process.waitFor(); + outPumperThread.join(); + errPumperThread.join(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return null; + } + + return new OutputBuffer(stdoutBuffer.toString(), stderrBuffer.toString()); + } + + /** + * Get the process id of the current running Java process + * + * @return Process id + */ + public static int getProcessId() throws Exception { + + // Get the current process id using a reflection hack + RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); + Field jvm = runtime.getClass().getDeclaredField("jvm"); + + jvm.setAccessible(true); + VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime); + + Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId"); + + pid_method.setAccessible(true); + + int pid = (Integer) pid_method.invoke(mgmt); + + return pid; + } + + /** + * Get platform specific VM arguments (e.g. -d64 on 64bit Solaris) + * + * @return String[] with platform specific arguments, empty if there are none + */ + public static String[] getPlatformSpecificVMArgs() { + String osName = System.getProperty("os.name"); + String dataModel = System.getProperty("sun.arch.data.model"); + + if (osName.equals("SunOS") && dataModel.equals("64")) { + return new String[] { "-d64" }; + } + + return new String[] {}; + } + + /** + * Create ProcessBuilder using the java launcher from the jdk to be tested and + * with any platform specific arguments prepended + */ + public static ProcessBuilder createJavaProcessBuilder(String... command) throws Exception { + String javapath = JDKToolFinder.getJDKTool("java"); + + ArrayList args = new ArrayList<>(); + args.add(javapath); + Collections.addAll(args, getPlatformSpecificVMArgs()); + Collections.addAll(args, command); + + return new ProcessBuilder(args.toArray(new String[args.size()])); + + } + +} diff -r dee7c8b578c7 -r c3657d00e343 test/testlibrary/com/oracle/java/testlibrary/StreamPumper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary/com/oracle/java/testlibrary/StreamPumper.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,76 @@ +/* + * 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.io.OutputStream; +import java.io.InputStream; +import java.io.IOException; + +public final class StreamPumper implements Runnable { + + private static final int BUF_SIZE = 256; + + private final OutputStream out; + private final InputStream in; + + /** + * Create a StreamPumper that reads from in and writes to out. + * + * @param in The stream to read from. + * @param out The stream to write to. + */ + public StreamPumper(InputStream in, OutputStream out) { + this.in = in; + this.out = out; + } + + /** + * Implements Thread.run(). Continuously read from in and write + * to out until in has reached end of stream. Abort + * on interruption. Abort on IOExceptions. + */ + @Override + public void run() { + int length; + InputStream localIn = in; + OutputStream localOut = out; + byte[] buffer = new byte[BUF_SIZE]; + + try { + while (!Thread.interrupted() && (length = localIn.read(buffer)) > 0) { + localOut.write(buffer, 0, length); + } + } catch (IOException e) { + // Just abort if something like this happens. + e.printStackTrace(); + } finally { + try { + localOut.flush(); + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} diff -r dee7c8b578c7 -r c3657d00e343 test/testlibrary/whitebox/sun/hotspot/WhiteBox.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,97 @@ +/* + * 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 + * 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 sun.hotspot; + +import java.lang.reflect.Method; +import java.security.BasicPermission; +import sun.hotspot.parser.DiagnosticCommand; + +public class WhiteBox { + + @SuppressWarnings("serial") + public static class WhiteBoxPermission extends BasicPermission { + public WhiteBoxPermission(String s) { + super(s); + } + } + + private WhiteBox() {} + private static final WhiteBox instance = new WhiteBox(); + private static native void registerNatives(); + + /** + * Returns the singleton WhiteBox instance. + * + * The returned WhiteBox object should be carefully guarded + * by the caller, since it can be used to read and write data + * at arbitrary memory addresses. It must never be passed to + * untrusted code. + */ + public synchronized static WhiteBox getWhiteBox() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new WhiteBoxPermission("getInstance")); + } + return instance; + } + + static { + registerNatives(); + } + + // Memory + public native long getObjectAddress(Object o); + public native int getHeapOopSize(); + + // Runtime + // Make sure class name is in the correct format + public boolean isClassAlive(String name) { + return isClassAlive0(name.replace('.', '/')); + } + private native boolean isClassAlive0(String name); + + // G1 + public native boolean g1InConcurrentMark(); + public native boolean g1IsHumongous(Object o); + public native long g1NumFreeRegions(); + public native int g1RegionSize(); + public native Object[] parseCommandLine(String commandline, DiagnosticCommand[] args); + + // NMT + public native boolean NMTAllocTest(); + public native boolean NMTFreeTestMemory(); + public native boolean NMTWaitForDataMerge(); + + // Compiler + public native void deoptimizeAll(); + public native boolean isMethodCompiled(Method method); + public native boolean isMethodCompilable(Method method); + 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 int getCompileQueuesSize(); +} diff -r dee7c8b578c7 -r c3657d00e343 test/testlibrary/whitebox/sun/hotspot/parser/DiagnosticCommand.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testlibrary/whitebox/sun/hotspot/parser/DiagnosticCommand.java Thu Mar 21 14:11:13 2013 +0100 @@ -0,0 +1,66 @@ +/* + * 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 + * 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 sun.hotspot.parser; + +public class DiagnosticCommand { + + public enum DiagnosticArgumentType { + JLONG, BOOLEAN, STRING, NANOTIME, STRINGARRAY, MEMORYSIZE + } + + private String name; + private String desc; + private DiagnosticArgumentType type; + private boolean mandatory; + private String defaultValue; + + public DiagnosticCommand(String name, String desc, DiagnosticArgumentType type, + boolean mandatory, String defaultValue) { + this.name = name; + this.desc = desc; + this.type = type; + this.mandatory = mandatory; + this.defaultValue = defaultValue; + } + + public String getName() { + return name; + } + + public String getDesc() { + return desc; + } + + public DiagnosticArgumentType getType() { + return type; + } + + public boolean isMandatory() { + return mandatory; + } + + public String getDefaultValue() { + return defaultValue; + } +}