# HG changeset patch # User iveresov # Date 1227133251 28800 # Node ID b5e603f2e02480180ace404141897cf8f6266e93 # Parent 491a904952f2af6aeb750f9d18ed07a9d514c72c# Parent 8fa025608ec6fc5a2bce99ece1d648873741bc6b Merge diff -r 8fa025608ec6 -r b5e603f2e024 .hgtags --- a/.hgtags Tue Nov 18 14:52:33 2008 -0800 +++ b/.hgtags Wed Nov 19 14:20:51 2008 -0800 @@ -13,3 +13,4 @@ e91159f921a58af3698e6479ea1fc5818da66d09 jdk7-b36 9ee9cf798b59e7d51f8c0a686959f313867a55d6 jdk7-b37 d9bc824aa078573829bb66572af847e26e1bd12e jdk7-b38 +49ca90d77f34571b0757ebfcb8a7848ef2696b88 jdk7-b39 diff -r 8fa025608ec6 -r b5e603f2e024 make/hotspot_version --- a/make/hotspot_version Tue Nov 18 14:52:33 2008 -0800 +++ b/make/hotspot_version Wed Nov 19 14:20:51 2008 -0800 @@ -35,7 +35,7 @@ HS_MAJOR_VER=14 HS_MINOR_VER=0 -HS_BUILD_NUMBER=06 +HS_BUILD_NUMBER=07 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff -r 8fa025608ec6 -r b5e603f2e024 make/linux/makefiles/top.make --- a/make/linux/makefiles/top.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/linux/makefiles/top.make Wed Nov 19 14:20:51 2008 -0800 @@ -85,9 +85,9 @@ AD_Dir = $(GENERATED)/adfiles ADLC = $(AD_Dir)/adlc -AD_Spec = $(GAMMADIR)/src/cpu/$(Platform_arch)/vm/$(Platform_arch).ad +AD_Spec = $(GAMMADIR)/src/cpu/$(Platform_arch)/vm/$(Platform_arch_model).ad AD_Src = $(GAMMADIR)/src/share/vm/adlc -AD_Names = ad_$(Platform_arch).hpp ad_$(Platform_arch).cpp +AD_Names = ad_$(Platform_arch_model).hpp ad_$(Platform_arch_model).cpp AD_Files = $(AD_Names:%=$(AD_Dir)/%) # AD_Files_If_Required/COMPILER1 = ad_stuff diff -r 8fa025608ec6 -r b5e603f2e024 make/solaris/makefiles/amd64.make --- a/make/solaris/makefiles/amd64.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/solaris/makefiles/amd64.make Wed Nov 19 14:20:51 2008 -0800 @@ -26,7 +26,6 @@ CFLAGS += -DVM_LITTLE_ENDIAN # Not included in includeDB because it has no dependencies -# Obj_Files += solaris_amd64.o Obj_Files += solaris_x86_64.o # @@ -38,8 +37,6 @@ # _lwp_create_interpose must have a frame OPT_CFLAGS/os_solaris_x86_64.o = -xO1 -# force C++ interpreter to be full optimization -#OPT_CFLAGS/interpret.o = -fast -O4 # Temporary until SS10 C++ compiler is fixed OPT_CFLAGS/generateOptoStub.o = -xO2 @@ -51,8 +48,6 @@ # gcc # The serviceability agent relies on frame pointer (%rbp) to walk thread stack CFLAGS += -fno-omit-frame-pointer -# force C++ interpreter to be full optimization -#OPT_CFLAGS/interpret.o = -O3 else # error diff -r 8fa025608ec6 -r b5e603f2e024 make/solaris/makefiles/debug.make --- a/make/solaris/makefiles/debug.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/solaris/makefiles/debug.make Wed Nov 19 14:20:51 2008 -0800 @@ -30,7 +30,7 @@ ifeq ("${Platform_compiler}", "sparcWorks") -ifeq ($(COMPILER_REV),5.8) +ifeq ($(COMPILER_REV_NUMERIC),508) # SS11 SEGV when compiling with -g and -xarch=v8, using different backend DEBUG_CFLAGS/compileBroker.o = $(DEBUG_CFLAGS) -xO0 DEBUG_CFLAGS/jvmtiTagMap.o = $(DEBUG_CFLAGS) -xO0 diff -r 8fa025608ec6 -r b5e603f2e024 make/solaris/makefiles/dtrace.make --- a/make/solaris/makefiles/dtrace.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/solaris/makefiles/dtrace.make Wed Nov 19 14:20:51 2008 -0800 @@ -87,17 +87,16 @@ XLIBJVM_DB = 64/$(LIBJVM_DB) XLIBJVM_DTRACE = 64/$(LIBJVM_DTRACE) -XARCH = $(subst sparcv9,v9,$(shell echo $(ISA))) $(XLIBJVM_DB): $(DTRACE_SRCDIR)/$(JVM_DB).c $(JVMOFFS).h $(LIBJVM_DB_MAPFILE) @echo Making $@ $(QUIETLY) mkdir -p 64/ ; \ - $(CC) $(SYMFLAG) $(ARCHFLAG/$(XARCH)) -D$(TYPE) -I. -I$(GENERATED) \ + $(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. -I$(GENERATED) \ $(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c -lc $(XLIBJVM_DTRACE): $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE) @echo Making $@ $(QUIETLY) mkdir -p 64/ ; \ - $(CC) $(SYMFLAG) $(ARCHFLAG/$(XARCH)) -D$(TYPE) -I. \ + $(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. \ $(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c -lc -lthread -ldoor endif # ifneq ("${ISA}","${BUILDARCH}") diff -r 8fa025608ec6 -r b5e603f2e024 make/solaris/makefiles/fastdebug.make --- a/make/solaris/makefiles/fastdebug.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/solaris/makefiles/fastdebug.make Wed Nov 19 14:20:51 2008 -0800 @@ -37,7 +37,7 @@ OPT_CFLAGS/SLOWER = -xO2 # Problem with SS12 compiler, dtrace doesn't like the .o files (bug 6693876) -ifeq ($(COMPILER_REV), 5.9) +ifeq ($(COMPILER_REV_NUMERIC), 509) # To avoid jvm98 crash OPT_CFLAGS/instanceKlass.o = $(OPT_CFLAGS/SLOWER) # Not clear this workaround could be skipped in some cases. @@ -46,47 +46,41 @@ OPT_CFLAGS/jni.o = $(OPT_CFLAGS/SLOWER) endif -ifeq ($(COMPILER_REV), 5.5) +ifeq ($(COMPILER_REV_NUMERIC), 505) # CC 5.5 has bug 4908364 with -xO4 (Fixed in 5.6) OPT_CFLAGS/library_call.o = $(OPT_CFLAGS/SLOWER) -endif # COMPILER_REV == 5.5 +endif # COMPILER_REV_NUMERIC == 505 -ifeq ($(shell expr $(COMPILER_REV) \<= 5.4), 1) +ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \<= 504), 1) # Compilation of *_.cpp can take an hour or more at O3. Use O2 # See comments at top of sparc.make. -OPT_CFLAGS/ad_$(Platform_arch).o = $(OPT_CFLAGS/SLOWER) -OPT_CFLAGS/dfa_$(Platform_arch).o = $(OPT_CFLAGS/SLOWER) -endif # COMPILER_REV <= 5.4 +OPT_CFLAGS/ad_$(Platform_arch_model).o = $(OPT_CFLAGS/SLOWER) +OPT_CFLAGS/dfa_$(Platform_arch_model).o = $(OPT_CFLAGS/SLOWER) +endif # COMPILER_REV_NUMERIC <= 504 -ifeq (${COMPILER_REV}, 5.0) -# Avoid a compiler bug caused by using -xO -g -# Since the bug also occurs with -xO0, use an innocuous value (must not be null) -OPT_CFLAGS/c1_LIROptimizer_i486.o = -c -endif - -ifeq ($(shell expr $(COMPILER_REV) \< 5.5), 1) -# Same problem with Solaris/x86 compiler (both 5.0 and 5.2) on ad_i486.cpp. -# CC build time is also too long for ad_i486_{gen,misc}.o -OPT_CFLAGS/ad_i486.o = -c -OPT_CFLAGS/ad_i486_gen.o = -c -OPT_CFLAGS/ad_i486_misc.o = -c -ifeq ($(Platform_arch), i486) +ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \< 505), 1) +# Same problem with Solaris/x86 compiler (both 5.0 and 5.2) on ad_x86_{32,64}.cpp. +# CC build time is also too long for ad_$(Platform_arch_model)_{gen,misc}.o +OPT_CFLAGS/ad_$(Platform_arch_model).o = -c +OPT_CFLAGS/ad_$(Platform_arch_model)_gen.o = -c +OPT_CFLAGS/ad_$(Platform_arch_model)_misc.o = -c +ifeq ($(Platform_arch), x86) # Same problem for the wrapper roosts: jni.o jvm.o OPT_CFLAGS/jni.o = -c OPT_CFLAGS/jvm.o = -c # Same problem in parse2.o (probably the Big Switch over bytecodes) OPT_CFLAGS/parse2.o = -c -endif # Platform_arch == i486 +endif # Platform_arch == x86 endif # Frame size > 100k if we allow inlining via -g0! DEBUG_CFLAGS/bytecodeInterpreter.o = -g DEBUG_CFLAGS/bytecodeInterpreterWithChecks.o = -g -ifeq ($(Platform_arch), i486) +ifeq ($(Platform_arch), x86) # ube explodes on x86 OPT_CFLAGS/bytecodeInterpreter.o = -xO1 OPT_CFLAGS/bytecodeInterpreterWithChecks.o = -xO1 -endif # Platform_arch == i486 +endif # Platform_arch == x86 endif # Platform_compiler == sparcWorks diff -r 8fa025608ec6 -r b5e603f2e024 make/solaris/makefiles/i486.make --- a/make/solaris/makefiles/i486.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/solaris/makefiles/i486.make Wed Nov 19 14:20:51 2008 -0800 @@ -35,17 +35,13 @@ ifeq ("${Platform_compiler}", "sparcWorks") # _lwp_create_interpose must have a frame -OPT_CFLAGS/os_solaris_i486.o = -xO1 -# force C++ interpreter to be full optimization -OPT_CFLAGS/interpret.o = -fast -O4 +OPT_CFLAGS/os_solaris_x86.o = -xO1 else ifeq ("${Platform_compiler}", "gcc") # gcc # _lwp_create_interpose must have a frame -OPT_CFLAGS/os_solaris_i486.o = -fno-omit-frame-pointer -# force C++ interpreter to be full optimization -OPT_CFLAGS/interpret.o = -O3 +OPT_CFLAGS/os_solaris_x86.o = -fno-omit-frame-pointer # else # error @@ -57,7 +53,7 @@ ifeq ("${Platform_compiler}", "sparcWorks") # ILD is gone as of SS11 (5.8), not supported in SS10 (5.7) -ifeq ($(shell expr $(COMPILER_REV) \< 5.7), 1) +ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \< 507), 1) # # Bug in ild causes it to fail randomly. Until we get a fix we can't # use ild. diff -r 8fa025608ec6 -r b5e603f2e024 make/solaris/makefiles/jvmg.make --- a/make/solaris/makefiles/jvmg.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/solaris/makefiles/jvmg.make Wed Nov 19 14:20:51 2008 -0800 @@ -30,7 +30,7 @@ ifeq ("${Platform_compiler}", "sparcWorks") -ifeq ($(COMPILER_REV),5.8) +ifeq ($(COMPILER_REV_NUMERIC),508) # SS11 SEGV when compiling with -g and -xarch=v8, using different backend DEBUG_CFLAGS/compileBroker.o = $(DEBUG_CFLAGS) -xO0 DEBUG_CFLAGS/jvmtiTagMap.o = $(DEBUG_CFLAGS) -xO0 diff -r 8fa025608ec6 -r b5e603f2e024 make/solaris/makefiles/optimized.make --- a/make/solaris/makefiles/optimized.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/solaris/makefiles/optimized.make Wed Nov 19 14:20:51 2008 -0800 @@ -33,7 +33,7 @@ ifeq ("${Platform_compiler}", "sparcWorks") # Problem with SS12 compiler, dtrace doesn't like the .o files (bug 6693876) -ifeq ($(COMPILER_REV),5.9) +ifeq ($(COMPILER_REV_NUMERIC),509) # Not clear this workaround could be skipped in some cases. OPT_CFLAGS/vmGCOperations.o = $(OPT_CFLAGS/SLOWER) -g OPT_CFLAGS/java.o = $(OPT_CFLAGS/SLOWER) -g @@ -41,9 +41,9 @@ endif # Workaround SS11 bug 6345274 (all platforms) (Fixed in SS11 patch and SS12) -ifeq ($(COMPILER_REV),5.8)) +ifeq ($(COMPILER_REV_NUMERIC),508)) OPT_CFLAGS/ciTypeFlow.o = $(OPT_CFLAGS/O2) -endif # COMPILER_REV == 5.8 +endif # COMPILER_REV_NUMERIC == 508 endif # Platform_compiler == sparcWorks diff -r 8fa025608ec6 -r b5e603f2e024 make/solaris/makefiles/product.make --- a/make/solaris/makefiles/product.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/solaris/makefiles/product.make Wed Nov 19 14:20:51 2008 -0800 @@ -41,7 +41,7 @@ ifeq ("${Platform_compiler}", "sparcWorks") # Problem with SS12 compiler, dtrace doesn't like the .o files (bug 6693876) -ifeq ($(COMPILER_REV),5.9) +ifeq ($(COMPILER_REV_NUMERIC),509) # Not clear this workaround could be skipped in some cases. OPT_CFLAGS/vmGCOperations.o = $(OPT_CFLAGS/SLOWER) -g OPT_CFLAGS/java.o = $(OPT_CFLAGS/SLOWER) -g @@ -49,9 +49,9 @@ endif # Workaround SS11 bug 6345274 (all platforms) (Fixed in SS11 patch and SS12) -ifeq ($(COMPILER_REV),5.8) +ifeq ($(COMPILER_REV_NUMERIC),508) OPT_CFLAGS/ciTypeFlow.o = $(OPT_CFLAGS/O2) -endif # COMPILER_REV == 5.8 +endif # COMPILER_REV_NUMERIC == 508 endif # Platform_compiler == sparcWorks diff -r 8fa025608ec6 -r b5e603f2e024 make/solaris/makefiles/sparc.make --- a/make/solaris/makefiles/sparc.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/solaris/makefiles/sparc.make Wed Nov 19 14:20:51 2008 -0800 @@ -26,7 +26,7 @@ ASFLAGS += $(AS_ARCHFLAG) ifeq ("${Platform_compiler}", "sparcWorks") -ifeq ($(shell expr $(COMPILER_REV) \< 5.5), 1) +ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \< 505), 1) # For 5.2 ad_sparc file is compiled with -O2 %%%% remove when adlc is fixed OPT_CFLAGS/ad_sparc.o = $(OPT_CFLAGS/SLOWER) OPT_CFLAGS/dfa_sparc.o = $(OPT_CFLAGS/SLOWER) @@ -39,7 +39,7 @@ OPT_CFLAGS/jniHandles.o = $(OPT_CFLAGS/O2) # CC brings an US-II to its knees compiling the vmStructs asserts under -xO4 OPT_CFLAGS/vmStructs.o = $(OPT_CFLAGS/O2) -endif +endif # COMPILER_REV_NUMERIC < 505 else # Options for gcc OPT_CFLAGS/ad_sparc.o = $(OPT_CFLAGS/SLOWER) diff -r 8fa025608ec6 -r b5e603f2e024 make/solaris/makefiles/sparcWorks.make --- a/make/solaris/makefiles/sparcWorks.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/solaris/makefiles/sparcWorks.make Wed Nov 19 14:20:51 2008 -0800 @@ -41,9 +41,9 @@ # Get the last thing on the line that looks like x.x+ (x is a digit). COMPILER_REV := \ -$(shell $(CPP) -V 2>&1 | sed -e 's/^.*\([1-9]\.[0-9][0-9]*\).*/\1/') +$(shell $(CPP) -V 2>&1 | sed -n 's/^.*[ ,\t]C++[ ,\t]\([1-9]\.[0-9][0-9]*\).*/\1/p') C_COMPILER_REV := \ -$(shell $(CC) -V 2>&1 | grep -i "cc:" | sed -e 's/^.*\([1-9]\.[0-9][0-9]*\).*/\1/') +$(shell $(CC) -V 2>&1 | sed -n 's/^.*[ ,\t]C[ ,\t]\([1-9]\.[0-9][0-9]*\).*/\1/p') # Pick which compiler is validated ifeq ($(JDK_MINOR_VERSION),6) @@ -60,17 +60,19 @@ ENFORCE_COMPILER_REV${ENFORCE_COMPILER_REV} := ${VALIDATED_COMPILER_REV} ifneq (${COMPILER_REV},${ENFORCE_COMPILER_REV}) dummy_target_to_enforce_compiler_rev:=\ -$(info WARNING: You are using CC version ${COMPILER_REV} \ -and should be using version ${ENFORCE_COMPILER_REV}) +$(shell echo >&2 WARNING: You are using CC version ${COMPILER_REV} \ +and should be using version ${ENFORCE_COMPILER_REV}. Set ENFORCE_COMPILER_REV=${COMPILER_REV} to avoid this warning.) endif ENFORCE_C_COMPILER_REV${ENFORCE_C_COMPILER_REV} := ${VALIDATED_C_COMPILER_REV} ifneq (${C_COMPILER_REV},${ENFORCE_C_COMPILER_REV}) dummy_target_to_enforce_c_compiler_rev:=\ -$(info WARNING: You are using cc version ${C_COMPILER_REV} \ -and should be using version ${ENFORCE_C_COMPILER_REV}) +$(shell echo >&2 WARNING: You are using cc version ${C_COMPILER_REV} \ +and should be using version ${ENFORCE_C_COMPILER_REV}. Set ENFORCE_C_COMPILER_REV=${C_COMPILER_REV} to avoid this warning.) endif +COMPILER_REV_NUMERIC := $(shell echo $(COMPILER_REV) | awk -F. '{ print $$1 * 100 + $$2 }') + # Fail the build if __fabsf is used. __fabsf exists only in Solaris 8 2/04 # and newer; objects with a dependency on this symbol will not run on older # Solaris 8. @@ -120,7 +122,7 @@ ARCHFLAG_NEW/amd64 = -m64 # Select the ARCHFLAGs and other SS12 (5.9) options -ifeq ($(shell expr $(COMPILER_REV) \>= 5.9), 1) +ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \>= 509), 1) ARCHFLAG/sparc = $(ARCHFLAG_NEW/sparc) ARCHFLAG/sparcv9 = $(ARCHFLAG_NEW/sparcv9) ARCHFLAG/i486 = $(ARCHFLAG_NEW/i486) @@ -150,7 +152,7 @@ # Begin current (>=5.6) Forte compiler options # ################################################# -ifeq ($(shell expr $(COMPILER_REV) \>= 5.6), 1) +ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \>= 506), 1) ifeq ("${Platform_arch}", "sparc") @@ -167,7 +169,7 @@ # Begin current (>=5.5) Forte compiler options # ################################################# -ifeq ($(shell expr $(COMPILER_REV) \>= 5.5), 1) +ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \>= 505), 1) CFLAGS += $(ARCHFLAG) AOUT_FLAGS += $(ARCHFLAG) @@ -255,7 +257,7 @@ LFLAGS += -mt -endif # COMPILER_REV >= 5.5 +endif # COMPILER_REV_NUMERIC >= 505 ###################################### # End 5.5 Forte compiler options # @@ -265,7 +267,7 @@ # Begin 5.2 Forte compiler options # ###################################### -ifeq ($(COMPILER_REV), 5.2) +ifeq ($(COMPILER_REV_NUMERIC), 502) CFLAGS += $(ARCHFLAG) AOUT_FLAGS += $(ARCHFLAG) @@ -324,7 +326,7 @@ LFLAGS += -library=Crun LIBS += -library=Crun -lCrun -endif # COMPILER_REV == 5.2 +endif # COMPILER_REV_NUMERIC == 502 ################################## # End 5.2 Forte compiler options # @@ -333,7 +335,7 @@ ################################## # Begin old 5.1 compiler options # ################################## -ifeq ($(COMPILER_REV), 5.1) +ifeq ($(COMPILER_REV_NUMERIC), 501) _JUNK_ := $(shell echo >&2 \ "*** ERROR: sparkWorks.make incomplete for 5.1 compiler") @@ -347,7 +349,7 @@ # Begin old 5.0 compiler options # ################################## -ifeq (${COMPILER_REV}, 5.0) +ifeq (${COMPILER_REV_NUMERIC}, 500) # Had to hoist this higher apparently because of other changes. Must # come before -xarch specification. @@ -379,7 +381,7 @@ ifeq ("${Platform_arch_model}", "x86_32") OPT_CFLAGS=-xtarget=pentium $(EXTRA_OPT_CFLAGS) -ifeq ("${COMPILER_REV}", "5.0") +ifeq ("${COMPILER_REV_NUMERIC}", "500") # SC5.0 tools on x86 are flakey at -xO4 OPT_CFLAGS+=-xO3 else @@ -405,13 +407,13 @@ PICFLAG/BETTER = $(PICFLAG/DEFAULT) PICFLAG/BYFILE = $(PICFLAG/$@)$(PICFLAG/DEFAULT$(PICFLAG/$@)) -endif # COMPILER_REV = 5.0 +endif # COMPILER_REV_NUMERIC = 500 ################################ # End old 5.0 compiler options # ################################ -ifeq ("${COMPILER_REV}", "4.2") +ifeq ("${COMPILER_REV_NUMERIC}", "402") # 4.2 COMPILERS SHOULD NO LONGER BE USED _JUNK_ := $(shell echo >&2 \ "*** ERROR: SC4.2 compilers are not supported by this code base!") @@ -443,7 +445,7 @@ LINK_MODE/optimized = -Bsymbolic -znodefs # Have thread local errnos -ifeq ($(shell expr $(COMPILER_REV) \>= 5.5), 1) +ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \>= 505), 1) CFLAGS += -mt else CFLAGS += -D_REENTRANT @@ -460,7 +462,7 @@ # The -g0 setting allows the C++ frontend to inline, which is a big win. # Special global options for SS12 -ifeq ($(COMPILER_REV),5.9) +ifeq ($(COMPILER_REV_NUMERIC),509) # There appears to be multiple issues with the new Dwarf2 debug format, so # we tell the compiler to use the older 'stabs' debug format all the time. # Note that this needs to be used in optimized compiles too to be 100%. @@ -479,8 +481,8 @@ #DEBUG_CFLAGS += -Qoption ccfe -xglobalstatic #FASTDEBUG_CFLAGS += -Qoption ccfe -xglobalstatic -ifeq (${COMPILER_REV}, 5.2) -COMPILER_DATE := $(shell $(CPP) -V 2>&1 | awk '{ print $$NF; }') +ifeq (${COMPILER_REV_NUMERIC}, 502) +COMPILER_DATE := $(shell $(CPP) -V 2>&1 | sed -n '/^.*[ ]C++[ ]\([1-9]\.[0-9][0-9]*\)/p' | awk '{ print $$NF; }') ifeq (${COMPILER_DATE}, 2001/01/31) # disable -g0 in fastdebug since SC6.1 dated 2001/01/31 seems to be buggy # use an innocuous value because it will get -g if it's empty @@ -493,7 +495,7 @@ CFLAGS += $(CFLAGS_BROWSE) # ILD is gone as of SS11 (5.8), not supportted in SS10 (5.7) -ifeq ($(shell expr $(COMPILER_REV) \< 5.7), 1) +ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \< 507), 1) # use ild when debugging (but when optimizing we want reproducible results) ILDFLAG = $(ILDFLAG/$(VERSION)) ILDFLAG/debug = -xildon diff -r 8fa025608ec6 -r b5e603f2e024 make/solaris/makefiles/sparcv9.make --- a/make/solaris/makefiles/sparcv9.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/solaris/makefiles/sparcv9.make Wed Nov 19 14:20:51 2008 -0800 @@ -26,7 +26,7 @@ ASFLAGS += $(AS_ARCHFLAG) ifeq ("${Platform_compiler}", "sparcWorks") -ifeq ($(shell expr $(COMPILER_REV) \< 5.5), 1) +ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \< 505), 1) # When optimized fully, stubGenerator_sparc.cpp # has bogus code for the routine # StubGenerator::generate_flush_callers_register_windows() diff -r 8fa025608ec6 -r b5e603f2e024 make/solaris/makefiles/top.make --- a/make/solaris/makefiles/top.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/solaris/makefiles/top.make Wed Nov 19 14:20:51 2008 -0800 @@ -83,9 +83,9 @@ AD_Dir = $(GENERATED)/adfiles ADLC = $(AD_Dir)/adlc -AD_Spec = $(GAMMADIR)/src/cpu/$(Platform_arch)/vm/$(Platform_arch).ad +AD_Spec = $(GAMMADIR)/src/cpu/$(Platform_arch)/vm/$(Platform_arch_model).ad AD_Src = $(GAMMADIR)/src/share/vm/adlc -AD_Names = ad_$(Platform_arch).hpp ad_$(Platform_arch).cpp +AD_Names = ad_$(Platform_arch_model).hpp ad_$(Platform_arch_model).cpp AD_Files = $(AD_Names:%=$(AD_Dir)/%) # AD_Files_If_Required/COMPILER1 = ad_stuff diff -r 8fa025608ec6 -r b5e603f2e024 make/solaris/makefiles/vm.make --- a/make/solaris/makefiles/vm.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/solaris/makefiles/vm.make Wed Nov 19 14:20:51 2008 -0800 @@ -101,7 +101,7 @@ ifeq ("${Platform_compiler}", "sparcWorks") # The whole megilla: -ifeq ($(shell expr $(COMPILER_REV) \>= 5.5), 1) +ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \>= 505), 1) # Old Comment: List the libraries in the order the compiler was designed for # Not sure what the 'designed for' comment is referring too above. # The order may not be too significant anymore, but I have placed this diff -r 8fa025608ec6 -r b5e603f2e024 make/windows/makefiles/adlc.make --- a/make/windows/makefiles/adlc.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/windows/makefiles/adlc.make Wed Nov 19 14:20:51 2008 -0800 @@ -102,6 +102,12 @@ adlc.exe: main.obj adlparse.obj archDesc.obj arena.obj dfa.obj dict2.obj filebuff.obj \ forms.obj formsopt.obj formssel.obj opcodes.obj output_c.obj output_h.obj $(LINK) $(LINK_FLAGS) /subsystem:console /out:$@ $** +!if "$(MT)" != "" +# The previous link command created a .manifest file that we want to +# insert into the linked artifact so we do not need to track it +# separately. Use ";#2" for .dll and ";#1" for .exe: + $(MT) /manifest $@.manifest /outputresource:$@;#1 +!endif $(GENERATED_NAMES_IN_INCL): $(Platform_arch_model).ad adlc.exe includeDB.current rm -f $(GENERATED_NAMES) diff -r 8fa025608ec6 -r b5e603f2e024 make/windows/makefiles/compile.make --- a/make/windows/makefiles/compile.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/windows/makefiles/compile.make Wed Nov 19 14:20:51 2008 -0800 @@ -30,7 +30,7 @@ # /W3 Warning level 3 # /Zi Include debugging information # /WX Treat any warning error as a fatal error -# /MD Use dynamic multi-threaded runtime (msvcrt.dll or msvc*71.dll) +# /MD Use dynamic multi-threaded runtime (msvcrt.dll or msvc*NN.dll) # /MTd Use static multi-threaded runtime debug versions # /O1 Optimize for size (/Os), skips /Oi # /O2 Optimize for speed (/Ot), adds /Oi to /O1 @@ -80,8 +80,10 @@ CPP=ARCH_ERROR !endif -# MSC_VER is a 4 digit number that tells us what compiler is being used, it is -# generated when the local.make file is created by the script gen_msc_ver.sh. +# MSC_VER is a 4 digit number that tells us what compiler is being used +# and is generated when the local.make file is created by build.make +# via the script get_msc_ver.sh +# # If MSC_VER is set, it overrides the above default setting. # But it should be set. # Possible values: @@ -89,13 +91,14 @@ # 1300 and 1310 is VS2003 or VC7 # 1399 is our fake number for the VS2005 compiler that really isn't 1400 # 1400 is for VS2005 +# 1500 is for VS2008 # Do not confuse this MSC_VER with the predefined macro _MSC_VER that the # compiler provides, when MSC_VER==1399, _MSC_VER will be 1400. # Normally they are the same, but a pre-release of the VS2005 compilers # in the Windows 64bit Platform SDK said it was 1400 when it was really # closer to VS2003 in terms of option spellings, so we use 1399 for that # 1400 version that really isn't 1400. -# See the file gen_msc_ver.sh for more info. +# See the file get_msc_ver.sh for more info. !if "x$(MSC_VER)" == "x" COMPILER_NAME=$(DEFAULT_COMPILER_NAME) !else @@ -115,6 +118,9 @@ !if "$(MSC_VER)" == "1400" COMPILER_NAME=VS2005 !endif +!if "$(MSC_VER)" == "1500" +COMPILER_NAME=VS2008 +!endif !endif # Add what version of the compiler we think this is to the compile line @@ -160,7 +166,25 @@ # externals at link time. Even with /GS-, you need bufferoverflowU.lib. # NOTE: Currently we decided to not use /GS- BUFFEROVERFLOWLIB = bufferoverflowU.lib -LINK_FLAGS = $(LINK_FLAGS) $(BUFFEROVERFLOWLIB) +LINK_FLAGS = /manifest $(LINK_FLAGS) $(BUFFEROVERFLOWLIB) +# Manifest Tool - used in VS2005 and later to adjust manifests stored +# as resources inside build artifacts. +MT=mt.exe +!if "$(BUILDARCH)" == "i486" +# VS2005 on x86 restricts the use of certain libc functions without this +CPP_FLAGS=$(CPP_FLAGS) /D _CRT_SECURE_NO_DEPRECATE +!endif +!endif + +!if "$(COMPILER_NAME)" == "VS2008" +PRODUCT_OPT_OPTION = /O2 /Oy- +FASTDEBUG_OPT_OPTION = /O2 /Oy- +DEBUG_OPT_OPTION = /Od +GX_OPTION = /EHsc +LINK_FLAGS = /manifest $(LINK_FLAGS) +# Manifest Tool - used in VS2005 and later to adjust manifests stored +# as resources inside build artifacts. +MT=mt.exe !if "$(BUILDARCH)" == "i486" # VS2005 on x86 restricts the use of certain libc functions without this CPP_FLAGS=$(CPP_FLAGS) /D _CRT_SECURE_NO_DEPRECATE diff -r 8fa025608ec6 -r b5e603f2e024 make/windows/makefiles/debug.make --- a/make/windows/makefiles/debug.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/windows/makefiles/debug.make Wed Nov 19 14:20:51 2008 -0800 @@ -50,6 +50,12 @@ $(LINK) @<< $(LINK_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) << +!if "$(MT)" != "" +# The previous link command created a .manifest file that we want to +# insert into the linked artifact so we do not need to track it +# separately. Use ";#2" for .dll and ";#1" for .exe: + $(MT) /manifest $@.manifest /outputresource:$@;#2 +!endif !include $(WorkSpace)/make/windows/makefiles/shared.make !include $(WorkSpace)/make/windows/makefiles/sa.make diff -r 8fa025608ec6 -r b5e603f2e024 make/windows/makefiles/defs.make --- a/make/windows/makefiles/defs.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/windows/makefiles/defs.make Wed Nov 19 14:20:51 2008 -0800 @@ -25,7 +25,7 @@ # The common definitions for hotspot windows builds. # Include the top level defs.make under make directory instead of this one. # This file is included into make/defs.make. -# On windows it is only used to construct parameters for +# On windows it is only used to construct parameters for # make/windows/build.make when make/Makefile is used to build VM. SLASH_JAVA ?= J: @@ -69,7 +69,7 @@ JDK_INCLUDE_SUBDIR=win32 -# HOTSPOT_RELEASE_VERSION and HOTSPOT_BUILD_VERSION are defined +# HOTSPOT_RELEASE_VERSION and HOTSPOT_BUILD_VERSION are defined # and added to MAKE_ARGS list in $(GAMMADIR)/make/defs.make. # next parameters are defined in $(GAMMADIR)/make/defs.make. @@ -125,7 +125,7 @@ endif ifeq ($(BUILD_WIN_SA), 1) - ifeq ($(ARCH),ia64) + ifeq ($(ARCH),ia64) BUILD_WIN_SA = 0 endif endif @@ -154,7 +154,7 @@ EXPORT_LIST += $(EXPORT_JRE_BIN_DIR)/sawindbg.dll EXPORT_LIST += $(EXPORT_JRE_BIN_DIR)/sawindbg.pdb EXPORT_LIST += $(EXPORT_JRE_BIN_DIR)/sawindbg.map - EXPORT_LIST += $(EXPORT_LIB_DIR)/sa-jdi.jar + EXPORT_LIST += $(EXPORT_LIB_DIR)/sa-jdi.jar # Must pass this down to nmake. MAKE_ARGS += BUILD_WIN_SA=1 endif diff -r 8fa025608ec6 -r b5e603f2e024 make/windows/makefiles/fastdebug.make --- a/make/windows/makefiles/fastdebug.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/windows/makefiles/fastdebug.make Wed Nov 19 14:20:51 2008 -0800 @@ -50,6 +50,13 @@ $(LINK) @<< $(LINK_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) << +!if "$(MT)" != "" +# The previous link command created a .manifest file that we want to +# insert into the linked artifact so we do not need to track it +# separately. Use ";#2" for .dll and ";#1" for .exe: + $(MT) /manifest $@.manifest /outputresource:$@;#2 +!endif + !include $(WorkSpace)/make/windows/makefiles/shared.make !include $(WorkSpace)/make/windows/makefiles/sa.make diff -r 8fa025608ec6 -r b5e603f2e024 make/windows/makefiles/product.make --- a/make/windows/makefiles/product.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/windows/makefiles/product.make Wed Nov 19 14:20:51 2008 -0800 @@ -61,6 +61,12 @@ $(LINK_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) << !endif +!if "$(MT)" != "" +# The previous link command created a .manifest file that we want to +# insert into the linked artifact so we do not need to track it +# separately. Use ";#2" for .dll and ";#1" for .exe: + $(MT) /manifest $@.manifest /outputresource:$@;#2 +!endif !include $(WorkSpace)/make/windows/makefiles/shared.make !include $(WorkSpace)/make/windows/makefiles/sa.make diff -r 8fa025608ec6 -r b5e603f2e024 make/windows/makefiles/sa.make --- a/make/windows/makefiles/sa.make Tue Nov 18 14:52:33 2008 -0800 +++ b/make/windows/makefiles/sa.make Wed Nov 19 14:20:51 2008 -0800 @@ -92,13 +92,18 @@ !else SA_CFLAGS = /nologo $(MS_RUNTIME_OPTION) /W3 /Gm $(GX_OPTION) /ZI /Od /D "WIN32" /D "_WINDOWS" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c !endif - +!if "$(MT)" != "" + SA_LINK_FLAGS = /manifest $(SA_LINK_FLAGS) +!endif SASRCFILE = $(AGENT_DIR)/src/os/win32/windbg/sawindbg.cpp SA_LFLAGS = $(SA_LINK_FLAGS) /nologo /subsystem:console /map /debug /machine:$(MACHINE) # Note that we do not keep sawindbj.obj around as it would then # get included in the dumpbin command in build_vm_def.sh +# In VS2005 or VS2008 the link command creates a .manifest file that we want +# to insert into the linked artifact so we do not need to track it separately. +# Use ";#2" for .dll and ";#1" for .exe in the MT command below: $(SAWINDBG): $(SASRCFILE) set INCLUDE=$(SA_INCLUDE)$(INCLUDE) $(CPP) @<< @@ -109,6 +114,9 @@ << set LIB=$(SA_LIB)$(LIB) $(LINK) /out:$@ /DLL sawindbg.obj dbgeng.lib $(SA_LFLAGS) +!if "$(MT)" != "" + $(MT) /manifest $(@F).manifest /outputresource:$(@F);#2 +!endif -@rm -f sawindbg.obj cleanall : diff -r 8fa025608ec6 -r b5e603f2e024 src/cpu/sparc/vm/assembler_sparc.cpp --- a/src/cpu/sparc/vm/assembler_sparc.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/cpu/sparc/vm/assembler_sparc.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -2615,7 +2615,8 @@ } } -void MacroAssembler::biased_locking_enter(Register obj_reg, Register mark_reg, Register temp_reg, +void MacroAssembler::biased_locking_enter(Register obj_reg, Register mark_reg, + Register temp_reg, Label& done, Label* slow_case, BiasedLockingCounters* counters) { assert(UseBiasedLocking, "why call this otherwise?"); @@ -2691,8 +2692,7 @@ markOopDesc::biased_lock_mask_in_place | markOopDesc::age_mask_in_place | markOopDesc::epoch_mask_in_place, mark_reg); or3(G2_thread, mark_reg, temp_reg); - casx_under_lock(mark_addr.base(), mark_reg, temp_reg, - (address)StubRoutines::Sparc::atomic_memory_operation_lock_addr()); + casn(mark_addr.base(), mark_reg, temp_reg); // If the biasing toward our thread failed, this means that // another thread succeeded in biasing it toward itself and we // need to revoke that bias. The revocation will occur in the @@ -2721,8 +2721,7 @@ load_klass(obj_reg, temp_reg); ld_ptr(Address(temp_reg, 0, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes()), temp_reg); or3(G2_thread, temp_reg, temp_reg); - casx_under_lock(mark_addr.base(), mark_reg, temp_reg, - (address)StubRoutines::Sparc::atomic_memory_operation_lock_addr()); + casn(mark_addr.base(), mark_reg, temp_reg); // If the biasing toward our thread failed, this means that // another thread succeeded in biasing it toward itself and we // need to revoke that bias. The revocation will occur in the @@ -2752,8 +2751,7 @@ // bits in this situation. Should attempt to preserve them. load_klass(obj_reg, temp_reg); ld_ptr(Address(temp_reg, 0, Klass::prototype_header_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes()), temp_reg); - casx_under_lock(mark_addr.base(), mark_reg, temp_reg, - (address)StubRoutines::Sparc::atomic_memory_operation_lock_addr()); + casn(mark_addr.base(), mark_reg, temp_reg); // Fall through to the normal CAS-based lock, because no matter what // the result of the above CAS, some thread must have succeeded in // removing the bias bit from the object's header. @@ -2815,8 +2813,10 @@ // effect). -void MacroAssembler::compiler_lock_object(Register Roop, Register Rmark, Register Rbox, Register Rscratch, - BiasedLockingCounters* counters) { +void MacroAssembler::compiler_lock_object(Register Roop, Register Rmark, + Register Rbox, Register Rscratch, + BiasedLockingCounters* counters, + bool try_bias) { Address mark_addr(Roop, 0, oopDesc::mark_offset_in_bytes()); verify_oop(Roop); @@ -2838,7 +2838,7 @@ // Fetch object's markword ld_ptr(mark_addr, Rmark); - if (UseBiasedLocking) { + if (try_bias) { biased_locking_enter(Roop, Rmark, Rscratch, done, NULL, counters); } @@ -2881,7 +2881,7 @@ ld_ptr (mark_addr, Rmark); // fetch obj->mark // Triage: biased, stack-locked, neutral, inflated - if (UseBiasedLocking) { + if (try_bias) { biased_locking_enter(Roop, Rmark, Rscratch, done, NULL, counters); // Invariant: if control reaches this point in the emitted stream // then Rmark has not been modified. @@ -2945,7 +2945,7 @@ ld_ptr (mark_addr, Rmark); // fetch obj->mark // Triage: biased, stack-locked, neutral, inflated - if (UseBiasedLocking) { + if (try_bias) { biased_locking_enter(Roop, Rmark, Rscratch, done, NULL, counters); // Invariant: if control reaches this point in the emitted stream // then Rmark has not been modified. @@ -3039,7 +3039,9 @@ bind (done) ; } -void MacroAssembler::compiler_unlock_object(Register Roop, Register Rmark, Register Rbox, Register Rscratch) { +void MacroAssembler::compiler_unlock_object(Register Roop, Register Rmark, + Register Rbox, Register Rscratch, + bool try_bias) { Address mark_addr(Roop, 0, oopDesc::mark_offset_in_bytes()); Label done ; @@ -3050,7 +3052,7 @@ } if (EmitSync & 8) { - if (UseBiasedLocking) { + if (try_bias) { biased_locking_exit(mark_addr, Rscratch, done); } @@ -3077,7 +3079,7 @@ // I$ effects. Label LStacked ; - if (UseBiasedLocking) { + if (try_bias) { // TODO: eliminate redundant LDs of obj->mark biased_locking_exit(mark_addr, Rscratch, done); } diff -r 8fa025608ec6 -r b5e603f2e024 src/cpu/sparc/vm/assembler_sparc.hpp --- a/src/cpu/sparc/vm/assembler_sparc.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/cpu/sparc/vm/assembler_sparc.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -2220,9 +2220,13 @@ // These set the icc condition code to equal if the lock succeeded // and notEqual if it failed and requires a slow case - void compiler_lock_object(Register Roop, Register Rmark, Register Rbox, Register Rscratch, - BiasedLockingCounters* counters = NULL); - void compiler_unlock_object(Register Roop, Register Rmark, Register Rbox, Register Rscratch); + void compiler_lock_object(Register Roop, Register Rmark, Register Rbox, + Register Rscratch, + BiasedLockingCounters* counters = NULL, + bool try_bias = UseBiasedLocking); + void compiler_unlock_object(Register Roop, Register Rmark, Register Rbox, + Register Rscratch, + bool try_bias = UseBiasedLocking); // Biased locking support // Upon entry, lock_reg must point to the lock record on the stack, diff -r 8fa025608ec6 -r b5e603f2e024 src/cpu/sparc/vm/interp_masm_sparc.cpp --- a/src/cpu/sparc/vm/interp_masm_sparc.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/cpu/sparc/vm/interp_masm_sparc.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -906,7 +906,7 @@ // load next super to check if (UseCompressedOops) { - ld( Rtmp2, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Rtmp3); + lduw( Rtmp2, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Rtmp3); // Bump array pointer forward one oop add( Rtmp2, 4, Rtmp2 ); } else { diff -r 8fa025608ec6 -r b5e603f2e024 src/cpu/sparc/vm/sparc.ad --- a/src/cpu/sparc/vm/sparc.ad Tue Nov 18 14:52:33 2008 -0800 +++ b/src/cpu/sparc/vm/sparc.ad Wed Nov 19 14:20:51 2008 -0800 @@ -395,6 +395,7 @@ ); reg_class g1_regL(R_G1H,R_G1); +reg_class g3_regL(R_G3H,R_G3); reg_class o2_regL(R_O2H,R_O2); reg_class o7_regL(R_O7H,R_O7); @@ -1743,7 +1744,7 @@ // // NOTE: If the platform does not provide any short branch variants, then // this method should return false for offset 0. -bool Matcher::is_short_branch_offset(int offset) { +bool Matcher::is_short_branch_offset(int rule, int offset) { return false; } @@ -1926,18 +1927,23 @@ $mem$$base, $mem$$disp, $mem$$index, $dst$$reg); %} + enc_class simple_form3_mem_reg( memory mem, iRegI dst ) %{ + emit_form3_mem_reg(cbuf, this, $primary, -1, + $mem$$base, $mem$$disp, $mem$$index, $dst$$reg); + %} + enc_class form3_mem_reg_little( memory mem, iRegI dst) %{ - emit_form3_mem_reg_asi(cbuf, this, $primary, $tertiary, + emit_form3_mem_reg_asi(cbuf, this, $primary, -1, $mem$$base, $mem$$disp, $mem$$index, $dst$$reg, Assembler::ASI_PRIMARY_LITTLE); %} enc_class form3_mem_prefetch_read( memory mem ) %{ - emit_form3_mem_reg(cbuf, this, $primary, $tertiary, + emit_form3_mem_reg(cbuf, this, $primary, -1, $mem$$base, $mem$$disp, $mem$$index, 0/*prefetch function many-reads*/); %} enc_class form3_mem_prefetch_write( memory mem ) %{ - emit_form3_mem_reg(cbuf, this, $primary, $tertiary, + emit_form3_mem_reg(cbuf, this, $primary, -1, $mem$$base, $mem$$disp, $mem$$index, 2/*prefetch function many-writes*/); %} @@ -1945,8 +1951,8 @@ assert( Assembler::is_simm13($mem$$disp ), "need disp and disp+4" ); assert( Assembler::is_simm13($mem$$disp+4), "need disp and disp+4" ); guarantee($mem$$index == R_G0_enc, "double index?"); - emit_form3_mem_reg(cbuf, this, $primary, $tertiary, $mem$$base, $mem$$disp+4, R_G0_enc, R_O7_enc ); - emit_form3_mem_reg(cbuf, this, $primary, $tertiary, $mem$$base, $mem$$disp, R_G0_enc, $reg$$reg ); + emit_form3_mem_reg(cbuf, this, $primary, -1, $mem$$base, $mem$$disp+4, R_G0_enc, R_O7_enc ); + emit_form3_mem_reg(cbuf, this, $primary, -1, $mem$$base, $mem$$disp, R_G0_enc, $reg$$reg ); emit3_simm13( cbuf, Assembler::arith_op, $reg$$reg, Assembler::sllx_op3, $reg$$reg, 0x1020 ); emit3( cbuf, Assembler::arith_op, $reg$$reg, Assembler::or_op3, $reg$$reg, 0, R_O7_enc ); %} @@ -1956,14 +1962,14 @@ assert( Assembler::is_simm13($mem$$disp+4), "need disp and disp+4" ); guarantee($mem$$index == R_G0_enc, "double index?"); // Load long with 2 instructions - emit_form3_mem_reg(cbuf, this, $primary, $tertiary, $mem$$base, $mem$$disp, R_G0_enc, $reg$$reg+0 ); - emit_form3_mem_reg(cbuf, this, $primary, $tertiary, $mem$$base, $mem$$disp+4, R_G0_enc, $reg$$reg+1 ); + emit_form3_mem_reg(cbuf, this, $primary, -1, $mem$$base, $mem$$disp, R_G0_enc, $reg$$reg+0 ); + emit_form3_mem_reg(cbuf, this, $primary, -1, $mem$$base, $mem$$disp+4, R_G0_enc, $reg$$reg+1 ); %} //%%% form3_mem_plus_4_reg is a hack--get rid of it enc_class form3_mem_plus_4_reg( memory mem, iRegI dst ) %{ guarantee($mem$$disp, "cannot offset a reg-reg operand by 4"); - emit_form3_mem_reg(cbuf, this, $primary, $tertiary, $mem$$base, $mem$$disp + 4, $mem$$index, $dst$$reg); + emit_form3_mem_reg(cbuf, this, $primary, -1, $mem$$base, $mem$$disp + 4, $mem$$index, $dst$$reg); %} enc_class form3_g0_rs2_rd_move( iRegI rs2, iRegI rd ) %{ @@ -2683,7 +2689,7 @@ assert(Rbox != Rscratch, ""); assert(Rbox != Rmark, ""); - __ compiler_lock_object(Roop, Rmark, Rbox, Rscratch, _counters); + __ compiler_lock_object(Roop, Rmark, Rbox, Rscratch, _counters, UseBiasedLocking && !UseOptoBiasInlining); %} enc_class Fast_Unlock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{ @@ -2699,7 +2705,7 @@ assert(Rbox != Rscratch, ""); assert(Rbox != Rmark, ""); - __ compiler_unlock_object(Roop, Rmark, Rbox, Rscratch); + __ compiler_unlock_object(Roop, Rmark, Rbox, Rscratch, UseBiasedLocking && !UseOptoBiasInlining); %} enc_class enc_cas( iRegP mem, iRegP old, iRegP new ) %{ @@ -2711,8 +2717,7 @@ // casx_under_lock picks 1 of 3 encodings: // For 32-bit pointers you get a 32-bit CAS // For 64-bit pointers you get a 64-bit CASX - __ casx_under_lock(Rmem, Rold, Rnew, // Swap(*Rmem,Rnew) if *Rmem == Rold - (address) StubRoutines::Sparc::atomic_memory_operation_lock_addr()); + __ casn(Rmem, Rold, Rnew); // Swap(*Rmem,Rnew) if *Rmem == Rold __ cmp( Rold, Rnew ); %} @@ -3761,6 +3766,14 @@ interface(REG_INTER); %} +operand g3RegL() %{ + constraint(ALLOC_IN_RC(g3_regL)); + match(iRegL); + + format %{ %} + interface(REG_INTER); +%} + // Int Register safe // This is 64bit safe operand iRegIsafe() %{ @@ -5062,7 +5075,7 @@ size(4); format %{ "LDF $src,$dst\t! stkI to regF" %} opcode(Assembler::ldf_op3); - ins_encode(form3_mem_reg(src, dst)); + ins_encode(simple_form3_mem_reg(src, dst)); ins_pipe(floadF_stk); %} @@ -5073,7 +5086,7 @@ size(4); format %{ "LDDF $src,$dst\t! stkL to regD" %} opcode(Assembler::lddf_op3); - ins_encode(form3_mem_reg(src, dst)); + ins_encode(simple_form3_mem_reg(src, dst)); ins_pipe(floadD_stk); %} @@ -5084,7 +5097,7 @@ size(4); format %{ "STF $src,$dst\t! regF to stkI" %} opcode(Assembler::stf_op3); - ins_encode(form3_mem_reg(dst, src)); + ins_encode(simple_form3_mem_reg(dst, src)); ins_pipe(fstoreF_stk_reg); %} @@ -5095,7 +5108,7 @@ size(4); format %{ "STDF $src,$dst\t! regD to stkL" %} opcode(Assembler::stdf_op3); - ins_encode(form3_mem_reg(dst, src)); + ins_encode(simple_form3_mem_reg(dst, src)); ins_pipe(fstoreD_stk_reg); %} @@ -5106,7 +5119,7 @@ format %{ "STW $src,$dst.hi\t! long\n\t" "STW R_G0,$dst.lo" %} opcode(Assembler::stw_op3); - ins_encode(form3_mem_reg(dst, src), form3_mem_plus_4_reg(dst, R_G0)); + ins_encode(simple_form3_mem_reg(dst, src), form3_mem_plus_4_reg(dst, R_G0)); ins_pipe(lstoreI_stk_reg); %} @@ -5117,7 +5130,7 @@ size(4); format %{ "STX $src,$dst\t! regL to stkD" %} opcode(Assembler::stx_op3); - ins_encode( form3_mem_reg( dst, src ) ); + ins_encode(simple_form3_mem_reg( dst, src ) ); ins_pipe(istore_stk_reg); %} @@ -5131,7 +5144,7 @@ size(4); format %{ "LDUW $src,$dst\t!stk" %} opcode(Assembler::lduw_op3); - ins_encode( form3_mem_reg( src, dst ) ); + ins_encode(simple_form3_mem_reg( src, dst ) ); ins_pipe(iload_mem); %} @@ -5143,7 +5156,7 @@ size(4); format %{ "STW $src,$dst\t!stk" %} opcode(Assembler::stw_op3); - ins_encode( form3_mem_reg( dst, src ) ); + ins_encode(simple_form3_mem_reg( dst, src ) ); ins_pipe(istore_mem_reg); %} @@ -5155,7 +5168,7 @@ size(4); format %{ "LDX $src,$dst\t! long" %} opcode(Assembler::ldx_op3); - ins_encode( form3_mem_reg( src, dst ) ); + ins_encode(simple_form3_mem_reg( src, dst ) ); ins_pipe(iload_mem); %} @@ -5167,7 +5180,7 @@ size(4); format %{ "STX $src,$dst\t! long" %} opcode(Assembler::stx_op3); - ins_encode( form3_mem_reg( dst, src ) ); + ins_encode(simple_form3_mem_reg( dst, src ) ); ins_pipe(istore_mem_reg); %} @@ -5179,7 +5192,7 @@ size(4); format %{ "LDX $src,$dst\t!ptr" %} opcode(Assembler::ldx_op3); - ins_encode( form3_mem_reg( src, dst ) ); + ins_encode(simple_form3_mem_reg( src, dst ) ); ins_pipe(iload_mem); %} @@ -5190,7 +5203,7 @@ size(4); format %{ "STX $src,$dst\t!ptr" %} opcode(Assembler::stx_op3); - ins_encode( form3_mem_reg( dst, src ) ); + ins_encode(simple_form3_mem_reg( dst, src ) ); ins_pipe(istore_mem_reg); %} #else // _LP64 @@ -5200,7 +5213,7 @@ ins_cost(MEMORY_REF_COST); format %{ "LDUW $src,$dst\t!ptr" %} opcode(Assembler::lduw_op3, Assembler::ldst_op); - ins_encode( form3_mem_reg( src, dst ) ); + ins_encode(simple_form3_mem_reg( src, dst ) ); ins_pipe(iload_mem); %} @@ -5210,7 +5223,7 @@ ins_cost(MEMORY_REF_COST); format %{ "STW $src,$dst\t!ptr" %} opcode(Assembler::stw_op3, Assembler::ldst_op); - ins_encode( form3_mem_reg( dst, src ) ); + ins_encode(simple_form3_mem_reg( dst, src ) ); ins_pipe(istore_mem_reg); %} #endif // _LP64 @@ -5273,7 +5286,7 @@ size(4); format %{ "LDSB $mem,$dst" %} opcode(Assembler::ldsb_op3); - ins_encode( form3_mem_reg( mem, dst ) ); + ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(iload_mask_mem); %} @@ -5285,7 +5298,7 @@ size(4); format %{ "LDUB $mem,$dst" %} opcode(Assembler::ldub_op3); - ins_encode( form3_mem_reg( mem, dst ) ); + ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(iload_mask_mem); %} @@ -5297,7 +5310,7 @@ size(4); format %{ "LDUB $mem,$dst" %} opcode(Assembler::ldub_op3); - ins_encode( form3_mem_reg( mem, dst ) ); + ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(iload_mask_mem); %} @@ -5309,7 +5322,7 @@ size(4); format %{ "LDUH $mem,$dst" %} opcode(Assembler::lduh_op3); - ins_encode( form3_mem_reg( mem, dst ) ); + ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(iload_mask_mem); %} @@ -5321,7 +5334,7 @@ size(4); format %{ "LDUH $mem,$dst" %} opcode(Assembler::lduh_op3); - ins_encode( form3_mem_reg( mem, dst ) ); + ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(iload_mask_mem); %} @@ -5333,7 +5346,7 @@ format %{ "LDUW $mem,$dst" %} opcode(Assembler::lduw_op3); - ins_encode( form3_mem_reg( mem, dst ) ); + ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(iload_mem); %} @@ -5344,7 +5357,7 @@ size(4); format %{ "LDX $mem,$dst\t! long" %} opcode(Assembler::ldx_op3); - ins_encode( form3_mem_reg( mem, dst ) ); + ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(iload_mem); %} @@ -5359,7 +5372,7 @@ "\tSLLX #32, $dst, $dst\n" "\tOR $dst, R_O7, $dst" %} opcode(Assembler::lduw_op3); - ins_encode( form3_mem_reg_long_unaligned_marshal( mem, dst )); + ins_encode(form3_mem_reg_long_unaligned_marshal( mem, dst )); ins_pipe(iload_mem); %} @@ -5370,7 +5383,7 @@ size(4); format %{ "LDDF $mem,$dst\t! packed8B" %} opcode(Assembler::lddf_op3); - ins_encode( form3_mem_reg( mem, dst ) ); + ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(floadD_mem); %} @@ -5381,7 +5394,7 @@ size(4); format %{ "LDDF $mem,$dst\t! packed4C" %} opcode(Assembler::lddf_op3); - ins_encode( form3_mem_reg( mem, dst ) ); + ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(floadD_mem); %} @@ -5392,7 +5405,7 @@ size(4); format %{ "LDDF $mem,$dst\t! packed4S" %} opcode(Assembler::lddf_op3); - ins_encode( form3_mem_reg( mem, dst ) ); + ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(floadD_mem); %} @@ -5403,7 +5416,7 @@ size(4); format %{ "LDDF $mem,$dst\t! packed2I" %} opcode(Assembler::lddf_op3); - ins_encode( form3_mem_reg( mem, dst ) ); + ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(floadD_mem); %} @@ -5415,7 +5428,7 @@ size(4); format %{ "LDUW $mem,$dst\t! range" %} opcode(Assembler::lduw_op3); - ins_encode( form3_mem_reg( mem, dst ) ); + ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(iload_mem); %} @@ -5427,7 +5440,7 @@ format %{ "LDF $mem,$dst\t! for fitos/fitod" %} opcode(Assembler::ldf_op3); - ins_encode( form3_mem_reg( mem, dst ) ); + ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(floadF_mem); %} @@ -5514,7 +5527,7 @@ size(4); format %{ "LDSH $mem,$dst" %} opcode(Assembler::ldsh_op3); - ins_encode( form3_mem_reg( mem, dst ) ); + ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(iload_mask_mem); %} @@ -5526,7 +5539,7 @@ size(4); format %{ "LDDF $mem,$dst" %} opcode(Assembler::lddf_op3); - ins_encode( form3_mem_reg( mem, dst ) ); + ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(floadD_mem); %} @@ -5550,7 +5563,7 @@ size(4); format %{ "LDF $mem,$dst" %} opcode(Assembler::ldf_op3); - ins_encode( form3_mem_reg( mem, dst ) ); + ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(floadF_mem); %} @@ -5719,7 +5732,7 @@ size(4); format %{ "STB $src,$mem\t! byte" %} opcode(Assembler::stb_op3); - ins_encode( form3_mem_reg( mem, src ) ); + ins_encode(simple_form3_mem_reg( mem, src ) ); ins_pipe(istore_mem_reg); %} @@ -5730,7 +5743,7 @@ size(4); format %{ "STB $src,$mem\t! byte" %} opcode(Assembler::stb_op3); - ins_encode( form3_mem_reg( mem, R_G0 ) ); + ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); ins_pipe(istore_mem_zero); %} @@ -5741,7 +5754,7 @@ size(4); format %{ "STB $src,$mem\t! CMS card-mark byte 0" %} opcode(Assembler::stb_op3); - ins_encode( form3_mem_reg( mem, R_G0 ) ); + ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); ins_pipe(istore_mem_zero); %} @@ -5753,7 +5766,7 @@ size(4); format %{ "STH $src,$mem\t! short" %} opcode(Assembler::sth_op3); - ins_encode( form3_mem_reg( mem, src ) ); + ins_encode(simple_form3_mem_reg( mem, src ) ); ins_pipe(istore_mem_reg); %} @@ -5764,7 +5777,7 @@ size(4); format %{ "STH $src,$mem\t! short" %} opcode(Assembler::sth_op3); - ins_encode( form3_mem_reg( mem, R_G0 ) ); + ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); ins_pipe(istore_mem_zero); %} @@ -5776,7 +5789,7 @@ size(4); format %{ "STW $src,$mem" %} opcode(Assembler::stw_op3); - ins_encode( form3_mem_reg( mem, src ) ); + ins_encode(simple_form3_mem_reg( mem, src ) ); ins_pipe(istore_mem_reg); %} @@ -5787,7 +5800,7 @@ size(4); format %{ "STX $src,$mem\t! long" %} opcode(Assembler::stx_op3); - ins_encode( form3_mem_reg( mem, src ) ); + ins_encode(simple_form3_mem_reg( mem, src ) ); ins_pipe(istore_mem_reg); %} @@ -5798,7 +5811,7 @@ size(4); format %{ "STW $src,$mem" %} opcode(Assembler::stw_op3); - ins_encode( form3_mem_reg( mem, R_G0 ) ); + ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); ins_pipe(istore_mem_zero); %} @@ -5809,7 +5822,7 @@ size(4); format %{ "STX $src,$mem" %} opcode(Assembler::stx_op3); - ins_encode( form3_mem_reg( mem, R_G0 ) ); + ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); ins_pipe(istore_mem_zero); %} @@ -5821,7 +5834,7 @@ size(4); format %{ "STF $src,$mem\t! after fstoi/fdtoi" %} opcode(Assembler::stf_op3); - ins_encode( form3_mem_reg( mem, src ) ); + ins_encode(simple_form3_mem_reg( mem, src ) ); ins_pipe(fstoreF_mem_reg); %} @@ -5904,7 +5917,7 @@ size(4); format %{ "STDF $src,$mem" %} opcode(Assembler::stdf_op3); - ins_encode( form3_mem_reg( mem, src ) ); + ins_encode(simple_form3_mem_reg( mem, src ) ); ins_pipe(fstoreD_mem_reg); %} @@ -5915,7 +5928,7 @@ size(4); format %{ "STX $src,$mem" %} opcode(Assembler::stx_op3); - ins_encode( form3_mem_reg( mem, R_G0 ) ); + ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); ins_pipe(fstoreD_mem_zero); %} @@ -5927,7 +5940,7 @@ size(4); format %{ "STF $src,$mem" %} opcode(Assembler::stf_op3); - ins_encode( form3_mem_reg( mem, src ) ); + ins_encode(simple_form3_mem_reg( mem, src ) ); ins_pipe(fstoreF_mem_reg); %} @@ -5938,7 +5951,7 @@ size(4); format %{ "STW $src,$mem\t! storeF0" %} opcode(Assembler::stw_op3); - ins_encode( form3_mem_reg( mem, R_G0 ) ); + ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); ins_pipe(fstoreF_mem_zero); %} @@ -5949,7 +5962,7 @@ size(4); format %{ "STDF $src,$mem\t! packed8B" %} opcode(Assembler::stdf_op3); - ins_encode( form3_mem_reg( mem, src ) ); + ins_encode(simple_form3_mem_reg( mem, src ) ); ins_pipe(fstoreD_mem_reg); %} @@ -6004,7 +6017,7 @@ size(4); format %{ "STX $zero,$mem\t! packed8B" %} opcode(Assembler::stx_op3); - ins_encode( form3_mem_reg( mem, R_G0 ) ); + ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); ins_pipe(fstoreD_mem_zero); %} @@ -6015,7 +6028,7 @@ size(4); format %{ "STDF $src,$mem\t! packed4C" %} opcode(Assembler::stdf_op3); - ins_encode( form3_mem_reg( mem, src ) ); + ins_encode(simple_form3_mem_reg( mem, src ) ); ins_pipe(fstoreD_mem_reg); %} @@ -6026,7 +6039,7 @@ size(4); format %{ "STX $zero,$mem\t! packed4C" %} opcode(Assembler::stx_op3); - ins_encode( form3_mem_reg( mem, R_G0 ) ); + ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); ins_pipe(fstoreD_mem_zero); %} @@ -6037,7 +6050,7 @@ size(4); format %{ "STDF $src,$mem\t! packed2I" %} opcode(Assembler::stdf_op3); - ins_encode( form3_mem_reg( mem, src ) ); + ins_encode(simple_form3_mem_reg( mem, src ) ); ins_pipe(fstoreD_mem_reg); %} @@ -6048,7 +6061,7 @@ size(4); format %{ "STX $zero,$mem\t! packed2I" %} opcode(Assembler::stx_op3); - ins_encode( form3_mem_reg( mem, R_G0 ) ); + ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); ins_pipe(fstoreD_mem_zero); %} @@ -6162,7 +6175,7 @@ ins_cost(MEMORY_REF_COST); format %{ "STDF $src,$stkSlot\t!stk" %} opcode(Assembler::stdf_op3); - ins_encode(form3_mem_reg(stkSlot, src)); + ins_encode(simple_form3_mem_reg(stkSlot, src)); ins_pipe(fstoreD_stk_reg); %} @@ -6172,7 +6185,7 @@ ins_cost(MEMORY_REF_COST); format %{ "LDDF $stkSlot,$dst\t!stk" %} opcode(Assembler::lddf_op3); - ins_encode(form3_mem_reg(stkSlot, dst)); + ins_encode(simple_form3_mem_reg(stkSlot, dst)); ins_pipe(floadD_stk); %} @@ -6182,7 +6195,7 @@ ins_cost(MEMORY_REF_COST); format %{ "STF $src,$stkSlot\t!stk" %} opcode(Assembler::stf_op3); - ins_encode(form3_mem_reg(stkSlot, src)); + ins_encode(simple_form3_mem_reg(stkSlot, src)); ins_pipe(fstoreF_stk_reg); %} @@ -6584,7 +6597,7 @@ size(4); format %{ "LDX $mem,$dst\t! long" %} opcode(Assembler::ldx_op3); - ins_encode( form3_mem_reg( mem, dst ) ); + ins_encode(simple_form3_mem_reg( mem, dst ) ); ins_pipe(iload_mem); %} @@ -6597,32 +6610,23 @@ ins_pipe( long_memory_op ); %} -instruct storeLConditional_bool(iRegP mem_ptr, iRegL oldval, iRegL newval, iRegI res, o7RegI tmp1, flagsReg ccr ) %{ - match(Set res (StoreLConditional mem_ptr (Binary oldval newval))); - effect( USE mem_ptr, KILL ccr, KILL tmp1); - // Marshal the register pairs into V9 64-bit registers, then do the compare-and-swap - format %{ - "MOV $newval,R_O7\n\t" - "CASXA [$mem_ptr],$oldval,R_O7\t! If $oldval==[$mem_ptr] Then store R_O7 into [$mem_ptr], set R_O7=[$mem_ptr] in any case\n\t" - "CMP $oldval,R_O7\t\t! See if we made progress\n\t" - "MOV 1,$res\n\t" - "MOVne xcc,R_G0,$res" - %} - ins_encode( enc_casx(mem_ptr, oldval, newval), - enc_lflags_ne_to_boolean(res) ); +// Conditional-store of an int value. +instruct storeIConditional( iRegP mem_ptr, iRegI oldval, g3RegI newval, flagsReg icc ) %{ + match(Set icc (StoreIConditional mem_ptr (Binary oldval newval))); + effect( KILL newval ); + format %{ "CASA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr], set $newval=[$mem_ptr] in any case\n\t" + "CMP $oldval,$newval\t\t! See if we made progress" %} + ins_encode( enc_cas(mem_ptr,oldval,newval) ); ins_pipe( long_memory_op ); %} -instruct storeLConditional_flags(iRegP mem_ptr, iRegL oldval, iRegL newval, flagsRegL xcc, o7RegI tmp1, immI0 zero) %{ - match(Set xcc (CmpI (StoreLConditional mem_ptr (Binary oldval newval)) zero)); - effect( USE mem_ptr, KILL tmp1); - // Marshal the register pairs into V9 64-bit registers, then do the compare-and-swap - format %{ - "MOV $newval,R_O7\n\t" - "CASXA [$mem_ptr],$oldval,R_O7\t! If $oldval==[$mem_ptr] Then store R_O7 into [$mem_ptr], set R_O7=[$mem_ptr] in any case\n\t" - "CMP $oldval,R_O7\t\t! See if we made progress" - %} - ins_encode( enc_casx(mem_ptr, oldval, newval)); +// Conditional-store of a long value. +instruct storeLConditional( iRegP mem_ptr, iRegL oldval, g3RegL newval, flagsRegL xcc ) %{ + match(Set xcc (StoreLConditional mem_ptr (Binary oldval newval))); + effect( KILL newval ); + format %{ "CASXA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr], set $newval=[$mem_ptr] in any case\n\t" + "CMP $oldval,$newval\t\t! See if we made progress" %} + ins_encode( enc_cas(mem_ptr,oldval,newval) ); ins_pipe( long_memory_op ); %} @@ -7405,6 +7409,34 @@ ins_pipe(ialu_reg_imm); %} +#ifndef _LP64 + +// Use sp_ptr_RegP to match G2 (TLS register) without spilling. +instruct orI_reg_castP2X(iRegI dst, iRegI src1, sp_ptr_RegP src2) %{ + match(Set dst (OrI src1 (CastP2X src2))); + + size(4); + format %{ "OR $src1,$src2,$dst" %} + opcode(Assembler::or_op3, Assembler::arith_op); + ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); + ins_pipe(ialu_reg_reg); +%} + +#else + +instruct orL_reg_castP2X(iRegL dst, iRegL src1, sp_ptr_RegP src2) %{ + match(Set dst (OrL src1 (CastP2X src2))); + + ins_cost(DEFAULT_COST); + size(4); + format %{ "OR $src1,$src2,$dst\t! long" %} + opcode(Assembler::or_op3, Assembler::arith_op); + ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); + ins_pipe(ialu_reg_reg); +%} + +#endif + // Xor Instructions // Register Xor instruct xorI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ @@ -7666,7 +7698,7 @@ format %{ "LDF $mem,$dst\n\t" "FITOD $dst,$dst" %} opcode(Assembler::ldf_op3, Assembler::fitod_opf); - ins_encode( form3_mem_reg( mem, dst ), form3_convI2F(dst, dst)); + ins_encode(simple_form3_mem_reg( mem, dst ), form3_convI2F(dst, dst)); ins_pipe(floadF_mem); %} @@ -7696,7 +7728,7 @@ format %{ "LDF $mem,$dst\n\t" "FITOS $dst,$dst" %} opcode(Assembler::ldf_op3, Assembler::fitos_opf); - ins_encode( form3_mem_reg( mem, dst ), form3_convI2F(dst, dst)); + ins_encode(simple_form3_mem_reg( mem, dst ), form3_convI2F(dst, dst)); ins_pipe(floadF_mem); %} @@ -7738,7 +7770,7 @@ size(4); format %{ "LDUW $src,$dst\t! MoveF2I" %} opcode(Assembler::lduw_op3); - ins_encode( form3_mem_reg( src, dst ) ); + ins_encode(simple_form3_mem_reg( src, dst ) ); ins_pipe(iload_mem); %} @@ -7750,7 +7782,7 @@ size(4); format %{ "LDF $src,$dst\t! MoveI2F" %} opcode(Assembler::ldf_op3); - ins_encode(form3_mem_reg(src, dst)); + ins_encode(simple_form3_mem_reg(src, dst)); ins_pipe(floadF_stk); %} @@ -7762,7 +7794,7 @@ size(4); format %{ "LDX $src,$dst\t! MoveD2L" %} opcode(Assembler::ldx_op3); - ins_encode( form3_mem_reg( src, dst ) ); + ins_encode(simple_form3_mem_reg( src, dst ) ); ins_pipe(iload_mem); %} @@ -7774,7 +7806,7 @@ size(4); format %{ "LDDF $src,$dst\t! MoveL2D" %} opcode(Assembler::lddf_op3); - ins_encode(form3_mem_reg(src, dst)); + ins_encode(simple_form3_mem_reg(src, dst)); ins_pipe(floadD_stk); %} @@ -7786,7 +7818,7 @@ size(4); format %{ "STF $src,$dst\t!MoveF2I" %} opcode(Assembler::stf_op3); - ins_encode(form3_mem_reg(dst, src)); + ins_encode(simple_form3_mem_reg(dst, src)); ins_pipe(fstoreF_stk_reg); %} @@ -7798,7 +7830,7 @@ size(4); format %{ "STW $src,$dst\t!MoveI2F" %} opcode(Assembler::stw_op3); - ins_encode( form3_mem_reg( dst, src ) ); + ins_encode(simple_form3_mem_reg( dst, src ) ); ins_pipe(istore_mem_reg); %} @@ -7810,7 +7842,7 @@ size(4); format %{ "STDF $src,$dst\t!MoveD2L" %} opcode(Assembler::stdf_op3); - ins_encode(form3_mem_reg(dst, src)); + ins_encode(simple_form3_mem_reg(dst, src)); ins_pipe(fstoreD_stk_reg); %} @@ -7822,7 +7854,7 @@ size(4); format %{ "STX $src,$dst\t!MoveL2D" %} opcode(Assembler::stx_op3); - ins_encode( form3_mem_reg( dst, src ) ); + ins_encode(simple_form3_mem_reg( dst, src ) ); ins_pipe(istore_mem_reg); %} diff -r 8fa025608ec6 -r b5e603f2e024 src/cpu/sparc/vm/stubGenerator_sparc.cpp --- a/src/cpu/sparc/vm/stubGenerator_sparc.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/cpu/sparc/vm/stubGenerator_sparc.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -956,7 +956,7 @@ // Load a little early; will load 1 off the end of the array. // Ok for now; revisit if we have other uses of this routine. if (UseCompressedOops) { - __ ld(L1_ary_ptr,0,L2_super);// Will load a little early + __ lduw(L1_ary_ptr,0,L2_super);// Will load a little early } else { __ ld_ptr(L1_ary_ptr,0,L2_super);// Will load a little early } @@ -973,7 +973,7 @@ #ifdef _LP64 __ subcc(L2_super,L4_ooptmp,Rret); // Check for match; zero in Rret for a hit __ br( Assembler::notEqual, false, Assembler::pt, loop ); - __ delayed()->ld(L1_ary_ptr,0,L2_super);// Will load a little early + __ delayed()->lduw(L1_ary_ptr,0,L2_super);// Will load a little early #else ShouldNotReachHere(); #endif diff -r 8fa025608ec6 -r b5e603f2e024 src/cpu/x86/vm/assembler_x86.cpp --- a/src/cpu/x86/vm/assembler_x86.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/cpu/x86/vm/assembler_x86.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -621,6 +621,10 @@ debug_only(has_disp32 = true); break; + case 0xF0: // Lock + assert(os::is_MP(), "only on MP"); + goto again_after_prefix; + case 0xF3: // For SSE case 0xF2: // For SSE2 switch (0xFF & *ip++) { diff -r 8fa025608ec6 -r b5e603f2e024 src/cpu/x86/vm/assembler_x86.hpp --- a/src/cpu/x86/vm/assembler_x86.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/cpu/x86/vm/assembler_x86.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -1780,7 +1780,8 @@ // check info (currently consumed only by C1). If // swap_reg_contains_mark is true then returns -1 as it is assumed // the calling code has already passed any potential faults. - int biased_locking_enter(Register lock_reg, Register obj_reg, Register swap_reg, Register tmp_reg, + int biased_locking_enter(Register lock_reg, Register obj_reg, + Register swap_reg, Register tmp_reg, bool swap_reg_contains_mark, Label& done, Label* slow_case = NULL, BiasedLockingCounters* counters = NULL); diff -r 8fa025608ec6 -r b5e603f2e024 src/cpu/x86/vm/register_definitions_x86.cpp --- a/src/cpu/x86/vm/register_definitions_x86.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/cpu/x86/vm/register_definitions_x86.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -22,9 +22,6 @@ * */ -// make sure the defines don't screw up the declarations later on in this file -#define DONT_USE_REGISTER_DEFINES - #include "incls/_precompiled.incl" #include "incls/_register_definitions_x86.cpp.incl" diff -r 8fa025608ec6 -r b5e603f2e024 src/cpu/x86/vm/x86_32.ad --- a/src/cpu/x86/vm/x86_32.ad Tue Nov 18 14:52:33 2008 -0800 +++ b/src/cpu/x86/vm/x86_32.ad Wed Nov 19 14:20:51 2008 -0800 @@ -495,8 +495,8 @@ void MachPrologNode::format( PhaseRegAlloc *ra_, outputStream* st ) const { Compile* C = ra_->C; if( C->in_24_bit_fp_mode() ) { - tty->print("FLDCW 24 bit fpu control word"); - tty->print_cr(""); tty->print("\t"); + st->print("FLDCW 24 bit fpu control word"); + st->print_cr(""); st->print("\t"); } int framesize = C->frame_slots() << LogBytesPerInt; @@ -510,22 +510,22 @@ // stack. But the stack safety zone should account for that. // See bugs 4446381, 4468289, 4497237. if (C->need_stack_bang(framesize)) { - tty->print_cr("# stack bang"); tty->print("\t"); + st->print_cr("# stack bang"); st->print("\t"); } - tty->print_cr("PUSHL EBP"); tty->print("\t"); + st->print_cr("PUSHL EBP"); st->print("\t"); if( VerifyStackAtCalls ) { // Majik cookie to verify stack depth - tty->print("PUSH 0xBADB100D\t# Majik cookie for stack depth check"); - tty->print_cr(""); tty->print("\t"); + st->print("PUSH 0xBADB100D\t# Majik cookie for stack depth check"); + st->print_cr(""); st->print("\t"); framesize -= wordSize; } if ((C->in_24_bit_fp_mode() || VerifyStackAtCalls ) && framesize < 128 ) { if (framesize) { - tty->print("SUB ESP,%d\t# Create frame",framesize); + st->print("SUB ESP,%d\t# Create frame",framesize); } } else { - tty->print("SUB ESP,%d\t# Create frame",framesize); + st->print("SUB ESP,%d\t# Create frame",framesize); } } #endif @@ -725,18 +725,19 @@ return rc_xmm; } -static int impl_helper( CodeBuffer *cbuf, bool do_size, bool is_load, int offset, int reg, int opcode, const char *op_str, int size ) { +static int impl_helper( CodeBuffer *cbuf, bool do_size, bool is_load, int offset, int reg, + int opcode, const char *op_str, int size, outputStream* st ) { if( cbuf ) { emit_opcode (*cbuf, opcode ); encode_RegMem(*cbuf, Matcher::_regEncode[reg], ESP_enc, 0x4, 0, offset, false); #ifndef PRODUCT } else if( !do_size ) { - if( size != 0 ) tty->print("\n\t"); + if( size != 0 ) st->print("\n\t"); if( opcode == 0x8B || opcode == 0x89 ) { // MOV - if( is_load ) tty->print("%s %s,[ESP + #%d]",op_str,Matcher::regName[reg],offset); - else tty->print("%s [ESP + #%d],%s",op_str,offset,Matcher::regName[reg]); + if( is_load ) st->print("%s %s,[ESP + #%d]",op_str,Matcher::regName[reg],offset); + else st->print("%s [ESP + #%d],%s",op_str,offset,Matcher::regName[reg]); } else { // FLD, FST, PUSH, POP - tty->print("%s [ESP + #%d]",op_str,offset); + st->print("%s [ESP + #%d]",op_str,offset); } #endif } @@ -746,7 +747,7 @@ // Helper for XMM registers. Extra opcode bits, limited syntax. static int impl_x_helper( CodeBuffer *cbuf, bool do_size, bool is_load, - int offset, int reg_lo, int reg_hi, int size ) { + int offset, int reg_lo, int reg_hi, int size, outputStream* st ) { if( cbuf ) { if( reg_lo+1 == reg_hi ) { // double move? if( is_load && !UseXmmLoadAndClearUpper ) @@ -764,17 +765,17 @@ encode_RegMem(*cbuf, Matcher::_regEncode[reg_lo], ESP_enc, 0x4, 0, offset, false); #ifndef PRODUCT } else if( !do_size ) { - if( size != 0 ) tty->print("\n\t"); + if( size != 0 ) st->print("\n\t"); if( reg_lo+1 == reg_hi ) { // double move? - if( is_load ) tty->print("%s %s,[ESP + #%d]", + if( is_load ) st->print("%s %s,[ESP + #%d]", UseXmmLoadAndClearUpper ? "MOVSD " : "MOVLPD", Matcher::regName[reg_lo], offset); - else tty->print("MOVSD [ESP + #%d],%s", + else st->print("MOVSD [ESP + #%d],%s", offset, Matcher::regName[reg_lo]); } else { - if( is_load ) tty->print("MOVSS %s,[ESP + #%d]", + if( is_load ) st->print("MOVSS %s,[ESP + #%d]", Matcher::regName[reg_lo], offset); - else tty->print("MOVSS [ESP + #%d],%s", + else st->print("MOVSS [ESP + #%d],%s", offset, Matcher::regName[reg_lo]); } #endif @@ -785,7 +786,7 @@ static int impl_movx_helper( CodeBuffer *cbuf, bool do_size, int src_lo, int dst_lo, - int src_hi, int dst_hi, int size ) { + int src_hi, int dst_hi, int size, outputStream* st ) { if( UseXmmRegToRegMoveAll ) {//Use movaps,movapd to move between xmm registers if( cbuf ) { if( (src_lo+1 == src_hi && dst_lo+1 == dst_hi) ) { @@ -796,11 +797,11 @@ emit_rm (*cbuf, 0x3, Matcher::_regEncode[dst_lo], Matcher::_regEncode[src_lo] ); #ifndef PRODUCT } else if( !do_size ) { - if( size != 0 ) tty->print("\n\t"); + if( size != 0 ) st->print("\n\t"); if( src_lo+1 == src_hi && dst_lo+1 == dst_hi ) { // double move? - tty->print("MOVAPD %s,%s",Matcher::regName[dst_lo],Matcher::regName[src_lo]); + st->print("MOVAPD %s,%s",Matcher::regName[dst_lo],Matcher::regName[src_lo]); } else { - tty->print("MOVAPS %s,%s",Matcher::regName[dst_lo],Matcher::regName[src_lo]); + st->print("MOVAPS %s,%s",Matcher::regName[dst_lo],Matcher::regName[src_lo]); } #endif } @@ -813,11 +814,11 @@ emit_rm (*cbuf, 0x3, Matcher::_regEncode[dst_lo], Matcher::_regEncode[src_lo] ); #ifndef PRODUCT } else if( !do_size ) { - if( size != 0 ) tty->print("\n\t"); + if( size != 0 ) st->print("\n\t"); if( src_lo+1 == src_hi && dst_lo+1 == dst_hi ) { // double move? - tty->print("MOVSD %s,%s",Matcher::regName[dst_lo],Matcher::regName[src_lo]); + st->print("MOVSD %s,%s",Matcher::regName[dst_lo],Matcher::regName[src_lo]); } else { - tty->print("MOVSS %s,%s",Matcher::regName[dst_lo],Matcher::regName[src_lo]); + st->print("MOVSS %s,%s",Matcher::regName[dst_lo],Matcher::regName[src_lo]); } #endif } @@ -825,28 +826,29 @@ } } -static int impl_mov_helper( CodeBuffer *cbuf, bool do_size, int src, int dst, int size ) { +static int impl_mov_helper( CodeBuffer *cbuf, bool do_size, int src, int dst, int size, outputStream* st ) { if( cbuf ) { emit_opcode(*cbuf, 0x8B ); emit_rm (*cbuf, 0x3, Matcher::_regEncode[dst], Matcher::_regEncode[src] ); #ifndef PRODUCT } else if( !do_size ) { - if( size != 0 ) tty->print("\n\t"); - tty->print("MOV %s,%s",Matcher::regName[dst],Matcher::regName[src]); + if( size != 0 ) st->print("\n\t"); + st->print("MOV %s,%s",Matcher::regName[dst],Matcher::regName[src]); #endif } return size+2; } -static int impl_fp_store_helper( CodeBuffer *cbuf, bool do_size, int src_lo, int src_hi, int dst_lo, int dst_hi, int offset, int size ) { +static int impl_fp_store_helper( CodeBuffer *cbuf, bool do_size, int src_lo, int src_hi, int dst_lo, int dst_hi, + int offset, int size, outputStream* st ) { if( src_lo != FPR1L_num ) { // Move value to top of FP stack, if not already there if( cbuf ) { emit_opcode( *cbuf, 0xD9 ); // FLD (i.e., push it) emit_d8( *cbuf, 0xC0-1+Matcher::_regEncode[src_lo] ); #ifndef PRODUCT } else if( !do_size ) { - if( size != 0 ) tty->print("\n\t"); - tty->print("FLD %s",Matcher::regName[src_lo]); + if( size != 0 ) st->print("\n\t"); + st->print("FLD %s",Matcher::regName[src_lo]); #endif } size += 2; @@ -864,7 +866,7 @@ assert( !OptoReg::is_valid(src_hi) && !OptoReg::is_valid(dst_hi), "no non-adjacent float-stores" ); } - return impl_helper(cbuf,do_size,false,offset,st_op,op,op_str,size); + return impl_helper(cbuf,do_size,false,offset,st_op,op,op_str,size, st); } uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, PhaseRegAlloc *ra_, bool do_size, outputStream* st ) const { @@ -892,16 +894,16 @@ if( src_first_rc == rc_stack && dst_first_rc == rc_stack ) { if( src_second == dst_first ) { // overlapping stack copy ranges assert( src_second_rc == rc_stack && dst_second_rc == rc_stack, "we only expect a stk-stk copy here" ); - size = impl_helper(cbuf,do_size,true ,ra_->reg2offset(src_second),ESI_num,0xFF,"PUSH ",size); - size = impl_helper(cbuf,do_size,false,ra_->reg2offset(dst_second),EAX_num,0x8F,"POP ",size); + size = impl_helper(cbuf,do_size,true ,ra_->reg2offset(src_second),ESI_num,0xFF,"PUSH ",size, st); + size = impl_helper(cbuf,do_size,false,ra_->reg2offset(dst_second),EAX_num,0x8F,"POP ",size, st); src_second_rc = dst_second_rc = rc_bad; // flag as already moved the second bits } // move low bits - size = impl_helper(cbuf,do_size,true ,ra_->reg2offset(src_first),ESI_num,0xFF,"PUSH ",size); - size = impl_helper(cbuf,do_size,false,ra_->reg2offset(dst_first),EAX_num,0x8F,"POP ",size); + size = impl_helper(cbuf,do_size,true ,ra_->reg2offset(src_first),ESI_num,0xFF,"PUSH ",size, st); + size = impl_helper(cbuf,do_size,false,ra_->reg2offset(dst_first),EAX_num,0x8F,"POP ",size, st); if( src_second_rc == rc_stack && dst_second_rc == rc_stack ) { // mov second bits - size = impl_helper(cbuf,do_size,true ,ra_->reg2offset(src_second),ESI_num,0xFF,"PUSH ",size); - size = impl_helper(cbuf,do_size,false,ra_->reg2offset(dst_second),EAX_num,0x8F,"POP ",size); + size = impl_helper(cbuf,do_size,true ,ra_->reg2offset(src_second),ESI_num,0xFF,"PUSH ",size, st); + size = impl_helper(cbuf,do_size,false,ra_->reg2offset(dst_second),EAX_num,0x8F,"POP ",size, st); } return size; } @@ -909,15 +911,15 @@ // -------------------------------------- // Check for integer reg-reg copy if( src_first_rc == rc_int && dst_first_rc == rc_int ) - size = impl_mov_helper(cbuf,do_size,src_first,dst_first,size); + size = impl_mov_helper(cbuf,do_size,src_first,dst_first,size, st); // Check for integer store if( src_first_rc == rc_int && dst_first_rc == rc_stack ) - size = impl_helper(cbuf,do_size,false,ra_->reg2offset(dst_first),src_first,0x89,"MOV ",size); + size = impl_helper(cbuf,do_size,false,ra_->reg2offset(dst_first),src_first,0x89,"MOV ",size, st); // Check for integer load if( dst_first_rc == rc_int && src_first_rc == rc_stack ) - size = impl_helper(cbuf,do_size,true ,ra_->reg2offset(src_first),dst_first,0x8B,"MOV ",size); + size = impl_helper(cbuf,do_size,true ,ra_->reg2offset(src_first),dst_first,0x8B,"MOV ",size, st); // -------------------------------------- // Check for float reg-reg copy @@ -951,7 +953,7 @@ // Check for float store if( src_first_rc == rc_float && dst_first_rc == rc_stack ) { - return impl_fp_store_helper(cbuf,do_size,src_first,src_second,dst_first,dst_second,ra_->reg2offset(dst_first),size); + return impl_fp_store_helper(cbuf,do_size,src_first,src_second,dst_first,dst_second,ra_->reg2offset(dst_first),size, st); } // Check for float load @@ -987,17 +989,17 @@ assert( (src_second_rc == rc_bad && dst_second_rc == rc_bad) || (src_first+1 == src_second && dst_first+1 == dst_second), "no non-adjacent float-moves" ); - return impl_movx_helper(cbuf,do_size,src_first,dst_first,src_second, dst_second, size); + return impl_movx_helper(cbuf,do_size,src_first,dst_first,src_second, dst_second, size, st); } // Check for xmm store if( src_first_rc == rc_xmm && dst_first_rc == rc_stack ) { - return impl_x_helper(cbuf,do_size,false,ra_->reg2offset(dst_first),src_first, src_second, size); + return impl_x_helper(cbuf,do_size,false,ra_->reg2offset(dst_first),src_first, src_second, size, st); } // Check for float xmm load if( dst_first_rc == rc_xmm && src_first_rc == rc_stack ) { - return impl_x_helper(cbuf,do_size,true ,ra_->reg2offset(src_first),dst_first, dst_second, size); + return impl_x_helper(cbuf,do_size,true ,ra_->reg2offset(src_first),dst_first, dst_second, size, st); } // Copy from float reg to xmm reg @@ -1017,10 +1019,10 @@ } size += 4; - size = impl_fp_store_helper(cbuf,do_size,src_first,src_second,dst_first,dst_second,0,size); + size = impl_fp_store_helper(cbuf,do_size,src_first,src_second,dst_first,dst_second,0,size, st); // Copy from the temp memory to the xmm reg. - size = impl_x_helper(cbuf,do_size,true ,0,dst_first, dst_second, size); + size = impl_x_helper(cbuf,do_size,true ,0,dst_first, dst_second, size, st); if( cbuf ) { emit_opcode(*cbuf,0x8D); // LEA ESP,[ESP+8] @@ -1047,15 +1049,15 @@ // Check for second word int-int move if( src_second_rc == rc_int && dst_second_rc == rc_int ) - return impl_mov_helper(cbuf,do_size,src_second,dst_second,size); + return impl_mov_helper(cbuf,do_size,src_second,dst_second,size, st); // Check for second word integer store if( src_second_rc == rc_int && dst_second_rc == rc_stack ) - return impl_helper(cbuf,do_size,false,ra_->reg2offset(dst_second),src_second,0x89,"MOV ",size); + return impl_helper(cbuf,do_size,false,ra_->reg2offset(dst_second),src_second,0x89,"MOV ",size, st); // Check for second word integer load if( dst_second_rc == rc_int && src_second_rc == rc_stack ) - return impl_helper(cbuf,do_size,true ,ra_->reg2offset(src_second),dst_second,0x8B,"MOV ",size); + return impl_helper(cbuf,do_size,true ,ra_->reg2offset(src_second),dst_second,0x8B,"MOV ",size, st); Unimplemented(); @@ -1318,7 +1320,11 @@ // // NOTE: If the platform does not provide any short branch variants, then // this method should return false for offset 0. -bool Matcher::is_short_branch_offset(int offset) { +bool Matcher::is_short_branch_offset(int rule, int offset) { + // the short version of jmpConUCF2 contains multiple branches, + // making the reach slightly less + if (rule == jmpConUCF2_rule) + return (-126 <= offset && offset <= 125); return (-128 <= offset && offset <= 127); } @@ -3307,7 +3313,7 @@ // Beware -- there's a subtle invariant that fetch of the markword // at [FETCH], below, will never observe a biased encoding (*101b). // If this invariant is not held we risk exclusion (safety) failure. - if (UseBiasedLocking) { + if (UseBiasedLocking && !UseOptoBiasInlining) { masm.biased_locking_enter(boxReg, objReg, tmpReg, scrReg, false, DONE_LABEL, NULL, _counters); } @@ -3528,7 +3534,7 @@ // Critically, the biased locking test must have precedence over // and appear before the (box->dhw == 0) recursive stack-lock test. - if (UseBiasedLocking) { + if (UseBiasedLocking && !UseOptoBiasInlining) { masm.biased_locking_exit(objReg, tmpReg, DONE_LABEL); } @@ -5272,6 +5278,15 @@ interface(REG_INTER); %} +operand eFlagsRegUCF() %{ + constraint(ALLOC_IN_RC(int_flags)); + match(RegFlags); + predicate(false); + + format %{ "EFLAGS_U_CF" %} + interface(REG_INTER); +%} + // Condition Code Register used by long compare operand flagsReg_long_LTGE() %{ constraint(ALLOC_IN_RC(int_flags)); @@ -5749,12 +5764,12 @@ format %{ "" %} interface(COND_INTER) %{ - equal(0x4); - not_equal(0x5); - less(0xC); - greater_equal(0xD); - less_equal(0xE); - greater(0xF); + equal(0x4, "e"); + not_equal(0x5, "ne"); + less(0xC, "l"); + greater_equal(0xD, "ge"); + less_equal(0xE, "le"); + greater(0xF, "g"); %} %} @@ -5766,12 +5781,47 @@ format %{ "" %} interface(COND_INTER) %{ - equal(0x4); - not_equal(0x5); - less(0x2); - greater_equal(0x3); - less_equal(0x6); - greater(0x7); + equal(0x4, "e"); + not_equal(0x5, "ne"); + less(0x2, "b"); + greater_equal(0x3, "nb"); + less_equal(0x6, "be"); + greater(0x7, "nbe"); + %} +%} + +// Floating comparisons that don't require any fixup for the unordered case +operand cmpOpUCF() %{ + match(Bool); + predicate(n->as_Bool()->_test._test == BoolTest::lt || + n->as_Bool()->_test._test == BoolTest::ge || + n->as_Bool()->_test._test == BoolTest::le || + n->as_Bool()->_test._test == BoolTest::gt); + format %{ "" %} + interface(COND_INTER) %{ + equal(0x4, "e"); + not_equal(0x5, "ne"); + less(0x2, "b"); + greater_equal(0x3, "nb"); + less_equal(0x6, "be"); + greater(0x7, "nbe"); + %} +%} + + +// Floating comparisons that can be fixed up with extra conditional jumps +operand cmpOpUCF2() %{ + match(Bool); + predicate(n->as_Bool()->_test._test == BoolTest::ne || + n->as_Bool()->_test._test == BoolTest::eq); + format %{ "" %} + interface(COND_INTER) %{ + equal(0x4, "e"); + not_equal(0x5, "ne"); + less(0x2, "b"); + greater_equal(0x3, "nb"); + less_equal(0x6, "be"); + greater(0x7, "nbe"); %} %} @@ -5796,12 +5846,12 @@ format %{ "" %} interface(COND_INTER) %{ - equal(0x4); - not_equal(0x5); - less(0xF); - greater_equal(0xE); - less_equal(0xD); - greater(0xC); + equal(0x4, "e"); + not_equal(0x5, "ne"); + less(0xF, "g"); + greater_equal(0xE, "le"); + less_equal(0xD, "ge"); + greater(0xC, "l"); %} %} @@ -7357,7 +7407,7 @@ ins_pipe( pipe_cmov_reg ); %} -instruct cmovI_regU( eRegI dst, eRegI src, eFlagsRegU cr, cmpOpU cop ) %{ +instruct cmovI_regU( cmpOpU cop, eFlagsRegU cr, eRegI dst, eRegI src ) %{ predicate(VM_Version::supports_cmov() ); match(Set dst (CMoveI (Binary cop cr) (Binary dst src))); ins_cost(200); @@ -7367,6 +7417,15 @@ ins_pipe( pipe_cmov_reg ); %} +instruct cmovI_regUCF( cmpOpUCF cop, eFlagsRegUCF cr, eRegI dst, eRegI src ) %{ + predicate(VM_Version::supports_cmov() ); + match(Set dst (CMoveI (Binary cop cr) (Binary dst src))); + ins_cost(200); + expand %{ + cmovI_regU(cop, cr, dst, src); + %} +%} + // Conditional move instruct cmovI_mem(cmpOp cop, eFlagsReg cr, eRegI dst, memory src) %{ predicate(VM_Version::supports_cmov() ); @@ -7379,7 +7438,7 @@ %} // Conditional move -instruct cmovI_memu(cmpOpU cop, eFlagsRegU cr, eRegI dst, memory src) %{ +instruct cmovI_memU(cmpOpU cop, eFlagsRegU cr, eRegI dst, memory src) %{ predicate(VM_Version::supports_cmov() ); match(Set dst (CMoveI (Binary cop cr) (Binary dst (LoadI src)))); ins_cost(250); @@ -7389,6 +7448,15 @@ ins_pipe( pipe_cmov_mem ); %} +instruct cmovI_memUCF(cmpOpUCF cop, eFlagsRegUCF cr, eRegI dst, memory src) %{ + predicate(VM_Version::supports_cmov() ); + match(Set dst (CMoveI (Binary cop cr) (Binary dst (LoadI src)))); + ins_cost(250); + expand %{ + cmovI_memU(cop, cr, dst, src); + %} +%} + // Conditional move instruct cmovP_reg(eRegP dst, eRegP src, eFlagsReg cr, cmpOp cop ) %{ predicate(VM_Version::supports_cmov() ); @@ -7416,7 +7484,7 @@ %} // Conditional move -instruct cmovP_regU(eRegP dst, eRegP src, eFlagsRegU cr, cmpOpU cop ) %{ +instruct cmovP_regU(cmpOpU cop, eFlagsRegU cr, eRegP dst, eRegP src ) %{ predicate(VM_Version::supports_cmov() ); match(Set dst (CMoveP (Binary cop cr) (Binary dst src))); ins_cost(200); @@ -7426,6 +7494,15 @@ ins_pipe( pipe_cmov_reg ); %} +instruct cmovP_regUCF(cmpOpUCF cop, eFlagsRegUCF cr, eRegP dst, eRegP src ) %{ + predicate(VM_Version::supports_cmov() ); + match(Set dst (CMoveP (Binary cop cr) (Binary dst src))); + ins_cost(200); + expand %{ + cmovP_regU(cop, cr, dst, src); + %} +%} + // DISABLED: Requires the ADLC to emit a bottom_type call that // correctly meets the two pointer arguments; one is an incoming // register but the other is a memory operand. ALSO appears to @@ -7555,6 +7632,15 @@ ins_pipe( pipe_slow ); %} +instruct fcmovX_regUCF(cmpOpUCF cop, eFlagsRegUCF cr, regX dst, regX src) %{ + predicate (UseSSE>=1); + match(Set dst (CMoveF (Binary cop cr) (Binary dst src))); + ins_cost(200); + expand %{ + fcmovX_regU(cop, cr, dst, src); + %} +%} + // unsigned version instruct fcmovXD_regU(cmpOpU cop, eFlagsRegU cr, regXD dst, regXD src) %{ predicate (UseSSE>=2); @@ -7573,6 +7659,15 @@ ins_pipe( pipe_slow ); %} +instruct fcmovXD_regUCF(cmpOpUCF cop, eFlagsRegUCF cr, regXD dst, regXD src) %{ + predicate (UseSSE>=2); + match(Set dst (CMoveD (Binary cop cr) (Binary dst src))); + ins_cost(200); + expand %{ + fcmovXD_regU(cop, cr, dst, src); + %} +%} + instruct cmovL_reg(cmpOp cop, eFlagsReg cr, eRegL dst, eRegL src) %{ predicate(VM_Version::supports_cmov() ); match(Set dst (CMoveL (Binary cop cr) (Binary dst src))); @@ -7595,6 +7690,15 @@ ins_pipe( pipe_cmov_reg_long ); %} +instruct cmovL_regUCF(cmpOpUCF cop, eFlagsRegUCF cr, eRegL dst, eRegL src) %{ + predicate(VM_Version::supports_cmov() ); + match(Set dst (CMoveL (Binary cop cr) (Binary dst src))); + ins_cost(200); + expand %{ + cmovL_regU(cop, cr, dst, src); + %} +%} + //----------Arithmetic Instructions-------------------------------------------- //----------Addition Instructions---------------------------------------------- // Integer Addition Instructions @@ -7826,33 +7930,36 @@ ins_pipe( pipe_cmpxchg ); %} -// Conditional-store of a long value -// Returns a boolean value (0/1) on success. Implemented with a CMPXCHG8 on Intel. -// mem_ptr can actually be in either ESI or EDI -instruct storeLConditional( eRegI res, eSIRegP mem_ptr, eADXRegL oldval, eBCXRegL newval, eFlagsReg cr ) %{ - match(Set res (StoreLConditional mem_ptr (Binary oldval newval))); - effect(KILL cr); - // EDX:EAX is killed if there is contention, but then it's also unused. - // In the common case of no contention, EDX:EAX holds the new oop address. - format %{ "CMPXCHG8 [$mem_ptr],$newval\t# If EDX:EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" - "MOV $res,0\n\t" - "JNE,s fail\n\t" - "MOV $res,1\n" - "fail:" %} - ins_encode( enc_cmpxchg8(mem_ptr), - enc_flags_ne_to_boolean(res) ); +// Conditional-store of an int value. +// ZF flag is set on success, reset otherwise. Implemented with a CMPXCHG on Intel. +instruct storeIConditional( memory mem, eAXRegI oldval, eRegI newval, eFlagsReg cr ) %{ + match(Set cr (StoreIConditional mem (Binary oldval newval))); + effect(KILL oldval); + format %{ "CMPXCHG $mem,$newval\t# If EAX==$mem Then store $newval into $mem" %} + ins_encode( lock_prefix, Opcode(0x0F), Opcode(0xB1), RegMem(newval, mem) ); ins_pipe( pipe_cmpxchg ); %} -// Conditional-store of a long value -// ZF flag is set on success, reset otherwise. Implemented with a CMPXCHG8 on Intel. -// mem_ptr can actually be in either ESI or EDI -instruct storeLConditional_flags( eSIRegP mem_ptr, eADXRegL oldval, eBCXRegL newval, eFlagsReg cr, immI0 zero ) %{ - match(Set cr (CmpI (StoreLConditional mem_ptr (Binary oldval newval)) zero)); - // EDX:EAX is killed if there is contention, but then it's also unused. - // In the common case of no contention, EDX:EAX holds the new oop address. - format %{ "CMPXCHG8 [$mem_ptr],$newval\t# If EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" %} - ins_encode( enc_cmpxchg8(mem_ptr) ); +// Conditional-store of a long value. +// ZF flag is set on success, reset otherwise. Implemented with a CMPXCHG8 on Intel. +instruct storeLConditional( memory mem, eADXRegL oldval, eBCXRegL newval, eFlagsReg cr ) %{ + match(Set cr (StoreLConditional mem (Binary oldval newval))); + effect(KILL oldval); + format %{ "XCHG EBX,ECX\t# correct order for CMPXCHG8 instruction\n\t" + "CMPXCHG8 $mem,ECX:EBX\t# If EDX:EAX==$mem Then store ECX:EBX into $mem\n\t" + "XCHG EBX,ECX" + %} + ins_encode %{ + // Note: we need to swap rbx, and rcx before and after the + // cmpxchg8 instruction because the instruction uses + // rcx as the high order word of the new value to store but + // our register encoding uses rbx. + __ xchgl(as_Register(EBX_enc), as_Register(ECX_enc)); + if( os::is_MP() ) + __ lock(); + __ cmpxchg8(Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp)); + __ xchgl(as_Register(EBX_enc), as_Register(ECX_enc)); + %} ins_pipe( pipe_cmpxchg ); %} @@ -8319,6 +8426,7 @@ ins_pipe( ialu_reg ); %} + // Logical Shift Right by 24, followed by Arithmetic Shift Left by 24. // This idiom is used by the compiler for the i2b bytecode. instruct i2b(eRegI dst, xRegI src, immI_24 twentyfour, eFlagsReg cr) %{ @@ -8436,6 +8544,18 @@ ins_pipe( ialu_reg_reg ); %} +instruct orI_eReg_castP2X(eRegI dst, eRegP src, eFlagsReg cr) %{ + match(Set dst (OrI dst (CastP2X src))); + effect(KILL cr); + + size(2); + format %{ "OR $dst,$src" %} + opcode(0x0B); + ins_encode( OpcP, RegReg( dst, src) ); + ins_pipe( ialu_reg_reg ); +%} + + // Or Register with Immediate instruct orI_eReg_imm(eRegI dst, immI src, eFlagsReg cr) %{ match(Set dst (OrI dst src)); @@ -9200,6 +9320,18 @@ ins_pipe( pipe_slow ); %} +instruct cmpD_cc_P6CF(eFlagsRegUCF cr, regD src1, regD src2) %{ + predicate(VM_Version::supports_cmov() && UseSSE <=1); + match(Set cr (CmpD src1 src2)); + ins_cost(150); + format %{ "FLD $src1\n\t" + "FUCOMIP ST,$src2 // P6 instruction" %} + opcode(0xDF, 0x05); /* DF E8+i or DF /5 */ + ins_encode( Push_Reg_D(src1), + OpcP, RegOpc(src2)); + ins_pipe( pipe_slow ); +%} + // Compare & branch instruct cmpD_cc(eFlagsRegU cr, regD src1, regD src2, eAXRegI rax) %{ predicate(UseSSE<=1); @@ -9264,6 +9396,16 @@ ins_pipe( pipe_slow ); %} +instruct cmpXD_ccCF(eFlagsRegUCF cr, regXD dst, regXD src) %{ + predicate(UseSSE>=2); + match(Set cr (CmpD dst src)); + ins_cost(100); + format %{ "COMISD $dst,$src" %} + opcode(0x66, 0x0F, 0x2F); + ins_encode(OpcP, OpcS, Opcode(tertiary), RegReg(dst, src)); + ins_pipe( pipe_slow ); +%} + // float compare and set condition codes in EFLAGS by XMM regs instruct cmpXD_ccmem(eFlagsRegU cr, regXD dst, memory src, eAXRegI rax) %{ predicate(UseSSE>=2); @@ -9280,6 +9422,16 @@ ins_pipe( pipe_slow ); %} +instruct cmpXD_ccmemCF(eFlagsRegUCF cr, regXD dst, memory src) %{ + predicate(UseSSE>=2); + match(Set cr (CmpD dst (LoadD src))); + ins_cost(100); + format %{ "COMISD $dst,$src" %} + opcode(0x66, 0x0F, 0x2F); + ins_encode(OpcP, OpcS, Opcode(tertiary), RegMem(dst, src)); + ins_pipe( pipe_slow ); +%} + // Compare into -1,0,1 in XMM instruct cmpXD_reg(eRegI dst, regXD src1, regXD src2, eFlagsReg cr) %{ predicate(UseSSE>=2); @@ -10167,6 +10319,18 @@ ins_pipe( pipe_slow ); %} +instruct cmpF_cc_P6CF(eFlagsRegUCF cr, regF src1, regF src2) %{ + predicate(VM_Version::supports_cmov() && UseSSE == 0); + match(Set cr (CmpF src1 src2)); + ins_cost(100); + format %{ "FLD $src1\n\t" + "FUCOMIP ST,$src2 // P6 instruction" %} + opcode(0xDF, 0x05); /* DF E8+i or DF /5 */ + ins_encode( Push_Reg_D(src1), + OpcP, RegOpc(src2)); + ins_pipe( pipe_slow ); +%} + // Compare & branch instruct cmpF_cc(eFlagsRegU cr, regF src1, regF src2, eAXRegI rax) %{ @@ -10232,6 +10396,16 @@ ins_pipe( pipe_slow ); %} +instruct cmpX_ccCF(eFlagsRegUCF cr, regX dst, regX src) %{ + predicate(UseSSE>=1); + match(Set cr (CmpF dst src)); + ins_cost(100); + format %{ "COMISS $dst,$src" %} + opcode(0x0F, 0x2F); + ins_encode(OpcP, OpcS, RegReg(dst, src)); + ins_pipe( pipe_slow ); +%} + // float compare and set condition codes in EFLAGS by XMM regs instruct cmpX_ccmem(eFlagsRegU cr, regX dst, memory src, eAXRegI rax) %{ predicate(UseSSE>=1); @@ -10248,6 +10422,16 @@ ins_pipe( pipe_slow ); %} +instruct cmpX_ccmemCF(eFlagsRegUCF cr, regX dst, memory src) %{ + predicate(UseSSE>=1); + match(Set cr (CmpF dst (LoadF src))); + ins_cost(100); + format %{ "COMISS $dst,$src" %} + opcode(0x0F, 0x2F); + ins_encode(OpcP, OpcS, RegMem(dst, src)); + ins_pipe( pipe_slow ); +%} + // Compare into -1,0,1 in XMM instruct cmpX_reg(eRegI dst, regX src1, regX src2, eFlagsReg cr) %{ predicate(UseSSE>=1); @@ -12099,6 +12283,19 @@ ins_pc_relative(1); %} +instruct jmpLoopEndUCF(cmpOpUCF cop, eFlagsRegUCF cmp, label labl) %{ + match(CountedLoopEnd cop cmp); + effect(USE labl); + + ins_cost(200); + format %{ "J$cop,u $labl\t# Loop end" %} + size(6); + opcode(0x0F, 0x80); + ins_encode( Jcc( cop, labl) ); + ins_pipe( pipe_jcc ); + ins_pc_relative(1); +%} + // Jump Direct Conditional - using unsigned comparison instruct jmpConU(cmpOpU cop, eFlagsRegU cmp, label labl) %{ match(If cop cmp); @@ -12108,8 +12305,63 @@ format %{ "J$cop,u $labl" %} size(6); opcode(0x0F, 0x80); - ins_encode( Jcc( cop, labl) ); - ins_pipe( pipe_jcc ); + ins_encode(Jcc(cop, labl)); + ins_pipe(pipe_jcc); + ins_pc_relative(1); +%} + +instruct jmpConUCF(cmpOpUCF cop, eFlagsRegUCF cmp, label labl) %{ + match(If cop cmp); + effect(USE labl); + + ins_cost(200); + format %{ "J$cop,u $labl" %} + size(6); + opcode(0x0F, 0x80); + ins_encode(Jcc(cop, labl)); + ins_pipe(pipe_jcc); + ins_pc_relative(1); +%} + +instruct jmpConUCF2(cmpOpUCF2 cop, eFlagsRegUCF cmp, label labl) %{ + match(If cop cmp); + effect(USE labl); + + ins_cost(200); + format %{ $$template + if ($cop$$cmpcode == Assembler::notEqual) { + $$emit$$"JP,u $labl\n\t" + $$emit$$"J$cop,u $labl" + } else { + $$emit$$"JP,u done\n\t" + $$emit$$"J$cop,u $labl\n\t" + $$emit$$"done:" + } + %} + size(12); + opcode(0x0F, 0x80); + ins_encode %{ + Label* l = $labl$$label; + $$$emit8$primary; + emit_cc(cbuf, $secondary, Assembler::parity); + int parity_disp = -1; + bool ok = false; + if ($cop$$cmpcode == Assembler::notEqual) { + // the two jumps 6 bytes apart so the jump distances are too + parity_disp = l ? (l->loc_pos() - (cbuf.code_size() + 4)) : 0; + } else if ($cop$$cmpcode == Assembler::equal) { + parity_disp = 6; + ok = true; + } else { + ShouldNotReachHere(); + } + emit_d32(cbuf, parity_disp); + $$$emit8$primary; + emit_cc(cbuf, $secondary, $cop$$cmpcode); + int disp = l ? (l->loc_pos() - (cbuf.code_size() + 4)) : 0; + emit_d32(cbuf, disp); + %} + ins_pipe(pipe_jcc); ins_pc_relative(1); %} @@ -12208,7 +12460,7 @@ effect(USE labl); ins_cost(300); - format %{ "J$cop,s $labl" %} + format %{ "J$cop,s $labl\t# Loop end" %} size(2); opcode(0x70); ins_encode( JccShort( cop, labl) ); @@ -12223,7 +12475,21 @@ effect(USE labl); ins_cost(300); - format %{ "J$cop,us $labl" %} + format %{ "J$cop,us $labl\t# Loop end" %} + size(2); + opcode(0x70); + ins_encode( JccShort( cop, labl) ); + ins_pipe( pipe_jcc ); + ins_pc_relative(1); + ins_short_branch(1); +%} + +instruct jmpLoopEndUCF_short(cmpOpUCF cop, eFlagsRegUCF cmp, label labl) %{ + match(CountedLoopEnd cop cmp); + effect(USE labl); + + ins_cost(300); + format %{ "J$cop,us $labl\t# Loop end" %} size(2); opcode(0x70); ins_encode( JccShort( cop, labl) ); @@ -12247,6 +12513,60 @@ ins_short_branch(1); %} +instruct jmpConUCF_short(cmpOpUCF cop, eFlagsRegUCF cmp, label labl) %{ + match(If cop cmp); + effect(USE labl); + + ins_cost(300); + format %{ "J$cop,us $labl" %} + size(2); + opcode(0x70); + ins_encode( JccShort( cop, labl) ); + ins_pipe( pipe_jcc ); + ins_pc_relative(1); + ins_short_branch(1); +%} + +instruct jmpConUCF2_short(cmpOpUCF2 cop, eFlagsRegUCF cmp, label labl) %{ + match(If cop cmp); + effect(USE labl); + + ins_cost(300); + format %{ $$template + if ($cop$$cmpcode == Assembler::notEqual) { + $$emit$$"JP,u,s $labl\n\t" + $$emit$$"J$cop,u,s $labl" + } else { + $$emit$$"JP,u,s done\n\t" + $$emit$$"J$cop,u,s $labl\n\t" + $$emit$$"done:" + } + %} + size(4); + opcode(0x70); + ins_encode %{ + Label* l = $labl$$label; + emit_cc(cbuf, $primary, Assembler::parity); + int parity_disp = -1; + if ($cop$$cmpcode == Assembler::notEqual) { + parity_disp = l ? (l->loc_pos() - (cbuf.code_size() + 1)) : 0; + } else if ($cop$$cmpcode == Assembler::equal) { + parity_disp = 2; + } else { + ShouldNotReachHere(); + } + emit_d8(cbuf, parity_disp); + emit_cc(cbuf, $primary, $cop$$cmpcode); + int disp = l ? (l->loc_pos() - (cbuf.code_size() + 1)) : 0; + emit_d8(cbuf, disp); + assert(-128 <= disp && disp <= 127, "Displacement too large for short jmp"); + assert(-128 <= parity_disp && parity_disp <= 127, "Displacement too large for short jmp"); + %} + ins_pipe(pipe_jcc); + ins_pc_relative(1); + ins_short_branch(1); +%} + // ============================================================================ // Long Compare // diff -r 8fa025608ec6 -r b5e603f2e024 src/cpu/x86/vm/x86_64.ad --- a/src/cpu/x86/vm/x86_64.ad Tue Nov 18 14:52:33 2008 -0800 +++ b/src/cpu/x86/vm/x86_64.ad Wed Nov 19 14:20:51 2008 -0800 @@ -2004,9 +2004,12 @@ // // NOTE: If the platform does not provide any short branch variants, then // this method should return false for offset 0. -bool Matcher::is_short_branch_offset(int offset) -{ - return -0x80 <= offset && offset < 0x80; +bool Matcher::is_short_branch_offset(int rule, int offset) { + // the short version of jmpConUCF2 contains multiple branches, + // making the reach slightly less + if (rule == jmpConUCF2_rule) + return (-126 <= offset && offset <= 125); + return (-128 <= offset && offset <= 127); } const bool Matcher::isSimpleConstant64(jlong value) { @@ -3569,7 +3572,7 @@ // at [FETCH], below, will never observe a biased encoding (*101b). // If this invariant is not held we'll suffer exclusion (safety) failure. - if (UseBiasedLocking) { + if (UseBiasedLocking && !UseOptoBiasInlining) { masm.biased_locking_enter(boxReg, objReg, tmpReg, scrReg, true, DONE_LABEL, NULL, _counters); masm.movptr(tmpReg, Address(objReg, 0)) ; // [FETCH] } @@ -3657,7 +3660,7 @@ } else { Label DONE_LABEL, Stacked, CheckSucc ; - if (UseBiasedLocking) { + if (UseBiasedLocking && !UseOptoBiasInlining) { masm.biased_locking_exit(objReg, tmpReg, DONE_LABEL); } @@ -5134,6 +5137,15 @@ interface(REG_INTER); %} +operand rFlagsRegUCF() %{ + constraint(ALLOC_IN_RC(int_flags)); + match(RegFlags); + predicate(false); + + format %{ "RFLAGS_U_CF" %} + interface(REG_INTER); +%} + // Float register operands operand regF() %{ @@ -5405,12 +5417,12 @@ format %{ "" %} interface(COND_INTER) %{ - equal(0x4); - not_equal(0x5); - less(0xC); - greater_equal(0xD); - less_equal(0xE); - greater(0xF); + equal(0x4, "e"); + not_equal(0x5, "ne"); + less(0xC, "l"); + greater_equal(0xD, "ge"); + less_equal(0xE, "le"); + greater(0xF, "g"); %} %} @@ -5423,12 +5435,48 @@ format %{ "" %} interface(COND_INTER) %{ - equal(0x4); - not_equal(0x5); - less(0x2); - greater_equal(0x3); - less_equal(0x6); - greater(0x7); + equal(0x4, "e"); + not_equal(0x5, "ne"); + less(0x2, "b"); + greater_equal(0x3, "nb"); + less_equal(0x6, "be"); + greater(0x7, "nbe"); + %} +%} + + +// Floating comparisons that don't require any fixup for the unordered case +operand cmpOpUCF() %{ + match(Bool); + predicate(n->as_Bool()->_test._test == BoolTest::lt || + n->as_Bool()->_test._test == BoolTest::ge || + n->as_Bool()->_test._test == BoolTest::le || + n->as_Bool()->_test._test == BoolTest::gt); + format %{ "" %} + interface(COND_INTER) %{ + equal(0x4, "e"); + not_equal(0x5, "ne"); + less(0x2, "b"); + greater_equal(0x3, "nb"); + less_equal(0x6, "be"); + greater(0x7, "nbe"); + %} +%} + + +// Floating comparisons that can be fixed up with extra conditional jumps +operand cmpOpUCF2() %{ + match(Bool); + predicate(n->as_Bool()->_test._test == BoolTest::ne || + n->as_Bool()->_test._test == BoolTest::eq); + format %{ "" %} + interface(COND_INTER) %{ + equal(0x4, "e"); + not_equal(0x5, "ne"); + less(0x2, "b"); + greater_equal(0x3, "nb"); + less_equal(0x6, "be"); + greater(0x7, "nbe"); %} %} @@ -7176,8 +7224,7 @@ ins_pipe(pipe_cmov_reg); %} -instruct cmovI_regU(rRegI dst, rRegI src, rFlagsRegU cr, cmpOpU cop) -%{ +instruct cmovI_regU(cmpOpU cop, rFlagsRegU cr, rRegI dst, rRegI src) %{ match(Set dst (CMoveI (Binary cop cr) (Binary dst src))); ins_cost(200); // XXX @@ -7187,9 +7234,16 @@ ins_pipe(pipe_cmov_reg); %} +instruct cmovI_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegI dst, rRegI src) %{ + match(Set dst (CMoveI (Binary cop cr) (Binary dst src))); + ins_cost(200); + expand %{ + cmovI_regU(cop, cr, dst, src); + %} +%} + // Conditional move -instruct cmovI_mem(cmpOp cop, rFlagsReg cr, rRegI dst, memory src) -%{ +instruct cmovI_mem(cmpOp cop, rFlagsReg cr, rRegI dst, memory src) %{ match(Set dst (CMoveI (Binary cop cr) (Binary dst (LoadI src)))); ins_cost(250); // XXX @@ -7211,6 +7265,14 @@ ins_pipe(pipe_cmov_mem); %} +instruct cmovI_memUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegI dst, memory src) %{ + match(Set dst (CMoveI (Binary cop cr) (Binary dst (LoadI src)))); + ins_cost(250); + expand %{ + cmovI_memU(cop, cr, dst, src); + %} +%} + // Conditional move instruct cmovN_reg(rRegN dst, rRegN src, rFlagsReg cr, cmpOp cop) %{ @@ -7224,7 +7286,7 @@ %} // Conditional move -instruct cmovN_regU(rRegN dst, rRegN src, rFlagsRegU cr, cmpOpU cop) +instruct cmovN_regU(cmpOpU cop, rFlagsRegU cr, rRegN dst, rRegN src) %{ match(Set dst (CMoveN (Binary cop cr) (Binary dst src))); @@ -7235,6 +7297,14 @@ ins_pipe(pipe_cmov_reg); %} +instruct cmovN_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegN dst, rRegN src) %{ + match(Set dst (CMoveN (Binary cop cr) (Binary dst src))); + ins_cost(200); + expand %{ + cmovN_regU(cop, cr, dst, src); + %} +%} + // Conditional move instruct cmovP_reg(rRegP dst, rRegP src, rFlagsReg cr, cmpOp cop) %{ @@ -7248,7 +7318,7 @@ %} // Conditional move -instruct cmovP_regU(rRegP dst, rRegP src, rFlagsRegU cr, cmpOpU cop) +instruct cmovP_regU(cmpOpU cop, rFlagsRegU cr, rRegP dst, rRegP src) %{ match(Set dst (CMoveP (Binary cop cr) (Binary dst src))); @@ -7259,6 +7329,14 @@ ins_pipe(pipe_cmov_reg); // XXX %} +instruct cmovP_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegP dst, rRegP src) %{ + match(Set dst (CMoveP (Binary cop cr) (Binary dst src))); + ins_cost(200); + expand %{ + cmovP_regU(cop, cr, dst, src); + %} +%} + // DISABLED: Requires the ADLC to emit a bottom_type call that // correctly meets the two pointer arguments; one is an incoming // register but the other is a memory operand. ALSO appears to @@ -7319,6 +7397,14 @@ ins_pipe(pipe_cmov_reg); // XXX %} +instruct cmovL_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegL dst, rRegL src) %{ + match(Set dst (CMoveL (Binary cop cr) (Binary dst src))); + ins_cost(200); + expand %{ + cmovL_regU(cop, cr, dst, src); + %} +%} + instruct cmovL_memU(cmpOpU cop, rFlagsRegU cr, rRegL dst, memory src) %{ match(Set dst (CMoveL (Binary cop cr) (Binary dst (LoadL src)))); @@ -7330,6 +7416,14 @@ ins_pipe(pipe_cmov_mem); // XXX %} +instruct cmovL_memUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegL dst, memory src) %{ + match(Set dst (CMoveL (Binary cop cr) (Binary dst (LoadL src)))); + ins_cost(200); + expand %{ + cmovL_memU(cop, cr, dst, src); + %} +%} + instruct cmovF_reg(cmpOp cop, rFlagsReg cr, regF dst, regF src) %{ match(Set dst (CMoveF (Binary cop cr) (Binary dst src))); @@ -7366,6 +7460,14 @@ ins_pipe(pipe_slow); %} +instruct cmovF_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, regF dst, regF src) %{ + match(Set dst (CMoveF (Binary cop cr) (Binary dst src))); + ins_cost(200); + expand %{ + cmovF_regU(cop, cr, dst, src); + %} +%} + instruct cmovD_reg(cmpOp cop, rFlagsReg cr, regD dst, regD src) %{ match(Set dst (CMoveD (Binary cop cr) (Binary dst src))); @@ -7390,6 +7492,14 @@ ins_pipe(pipe_slow); %} +instruct cmovD_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, regD dst, regD src) %{ + match(Set dst (CMoveD (Binary cop cr) (Binary dst src))); + ins_cost(200); + expand %{ + cmovD_regU(cop, cr, dst, src); + %} +%} + //----------Arithmetic Instructions-------------------------------------------- //----------Addition Instructions---------------------------------------------- @@ -7735,7 +7845,7 @@ rFlagsReg cr) %{ match(Set cr (StorePConditional heap_top_ptr (Binary oldval newval))); - + format %{ "cmpxchgq $heap_top_ptr, $newval\t# (ptr) " "If rax == $heap_top_ptr then store $newval into $heap_top_ptr" %} opcode(0x0F, 0xB1); @@ -7746,53 +7856,40 @@ ins_pipe(pipe_cmpxchg); %} -// Conditional-store of a long value -// Returns a boolean value (0/1) on success. Implemented with a -// CMPXCHG8 on Intel. mem_ptr can actually be in either RSI or RDI - -instruct storeLConditional(rRegI res, - memory mem_ptr, - rax_RegL oldval, rRegL newval, - rFlagsReg cr) -%{ - match(Set res (StoreLConditional mem_ptr (Binary oldval newval))); - effect(KILL cr); - - format %{ "cmpxchgq $mem_ptr, $newval\t# (long) " - "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" - "sete $res\n\t" - "movzbl $res, $res" %} +// Conditional-store of an int value. +// ZF flag is set on success, reset otherwise. Implemented with a CMPXCHG. +instruct storeIConditional(memory mem, rax_RegI oldval, rRegI newval, rFlagsReg cr) +%{ + match(Set cr (StoreIConditional mem (Binary oldval newval))); + effect(KILL oldval); + + format %{ "cmpxchgl $mem, $newval\t# If rax == $mem then store $newval into $mem" %} opcode(0x0F, 0xB1); ins_encode(lock_prefix, - REX_reg_mem_wide(newval, mem_ptr), + REX_reg_mem(newval, mem), OpcP, OpcS, - reg_mem(newval, mem_ptr), - REX_breg(res), Opcode(0x0F), Opcode(0x94), reg(res), // sete - REX_reg_breg(res, res), // movzbl - Opcode(0xF), Opcode(0xB6), reg_reg(res, res)); + reg_mem(newval, mem)); ins_pipe(pipe_cmpxchg); %} -// Conditional-store of a long value -// ZF flag is set on success, reset otherwise. Implemented with a -// CMPXCHG8 on Intel. mem_ptr can actually be in either RSI or RDI -instruct storeLConditional_flags(memory mem_ptr, - rax_RegL oldval, rRegL newval, - rFlagsReg cr, - immI0 zero) -%{ - match(Set cr (CmpI (StoreLConditional mem_ptr (Binary oldval newval)) zero)); - - format %{ "cmpxchgq $mem_ptr, $newval\t# (long) " - "If rax == $mem_ptr then store $newval into $mem_ptr" %} +// Conditional-store of a long value. +// ZF flag is set on success, reset otherwise. Implemented with a CMPXCHG. +instruct storeLConditional(memory mem, rax_RegL oldval, rRegL newval, rFlagsReg cr) +%{ + match(Set cr (StoreLConditional mem (Binary oldval newval))); + effect(KILL oldval); + + format %{ "cmpxchgq $mem, $newval\t# If rax == $mem then store $newval into $mem" %} opcode(0x0F, 0xB1); ins_encode(lock_prefix, - REX_reg_mem_wide(newval, mem_ptr), + REX_reg_mem_wide(newval, mem), OpcP, OpcS, - reg_mem(newval, mem_ptr)); + reg_mem(newval, mem)); ins_pipe(pipe_cmpxchg); %} + +// XXX No flag versions for CompareAndSwap{P,I,L} because matcher can't match them instruct compareAndSwapP(rRegI res, memory mem_ptr, rax_RegP oldval, rRegP newval, @@ -7816,7 +7913,6 @@ ins_pipe( pipe_cmpxchg ); %} -// XXX No flag versions for CompareAndSwap{P,I,L} because matcher can't match them instruct compareAndSwapL(rRegI res, memory mem_ptr, rax_RegL oldval, rRegL newval, @@ -8766,6 +8862,7 @@ ins_pipe(ialu_reg); %} + // Logical Shift Right by 8-bit immediate instruct shrL_mem_imm(memory dst, immI8 shift, rFlagsReg cr) %{ @@ -9475,6 +9572,18 @@ ins_pipe(ialu_reg_reg); %} +// Use any_RegP to match R15 (TLS register) without spilling. +instruct orL_rReg_castP2X(rRegL dst, any_RegP src, rFlagsReg cr) %{ + match(Set dst (OrL dst (CastP2X src))); + effect(KILL cr); + + format %{ "orq $dst, $src\t# long" %} + opcode(0x0B); + ins_encode(REX_reg_reg_wide(dst, src), OpcP, reg_reg(dst, src)); + ins_pipe(ialu_reg_reg); +%} + + // Or Register with Immediate instruct orL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr) %{ @@ -9716,6 +9825,17 @@ ins_pipe(pipe_slow); %} +instruct cmpF_cc_reg_CF(rFlagsRegUCF cr, regF src1, regF src2) %{ + match(Set cr (CmpF src1 src2)); + + ins_cost(145); + format %{ "ucomiss $src1, $src2" %} + ins_encode %{ + __ ucomiss($src1$$XMMRegister, $src2$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + instruct cmpF_cc_mem(rFlagsRegU cr, regF src1, memory src2) %{ match(Set cr (CmpF src1 (LoadF src2))); @@ -9733,6 +9853,16 @@ ins_pipe(pipe_slow); %} +instruct cmpF_cc_memCF(rFlagsRegUCF cr, regF src1, memory src2) %{ + match(Set cr (CmpF src1 (LoadF src2))); + + ins_cost(100); + format %{ "ucomiss $src1, $src2" %} + opcode(0x0F, 0x2E); + ins_encode(REX_reg_mem(src1, src2), OpcP, OpcS, reg_mem(src1, src2)); + ins_pipe(pipe_slow); +%} + instruct cmpF_cc_imm(rFlagsRegU cr, regF src1, immF src2) %{ match(Set cr (CmpF src1 src2)); @@ -9750,6 +9880,16 @@ ins_pipe(pipe_slow); %} +instruct cmpF_cc_immCF(rFlagsRegUCF cr, regF src1, immF src2) %{ + match(Set cr (CmpF src1 src2)); + + ins_cost(100); + format %{ "ucomiss $src1, $src2" %} + opcode(0x0F, 0x2E); + ins_encode(REX_reg_mem(src1, src2), OpcP, OpcS, load_immF(src1, src2)); + ins_pipe(pipe_slow); +%} + instruct cmpD_cc_reg(rFlagsRegU cr, regD src1, regD src2) %{ match(Set cr (CmpD src1 src2)); @@ -9767,6 +9907,17 @@ ins_pipe(pipe_slow); %} +instruct cmpD_cc_reg_CF(rFlagsRegUCF cr, regD src1, regD src2) %{ + match(Set cr (CmpD src1 src2)); + + ins_cost(100); + format %{ "ucomisd $src1, $src2 test" %} + ins_encode %{ + __ ucomisd($src1$$XMMRegister, $src2$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + instruct cmpD_cc_mem(rFlagsRegU cr, regD src1, memory src2) %{ match(Set cr (CmpD src1 (LoadD src2))); @@ -9784,6 +9935,16 @@ ins_pipe(pipe_slow); %} +instruct cmpD_cc_memCF(rFlagsRegUCF cr, regD src1, memory src2) %{ + match(Set cr (CmpD src1 (LoadD src2))); + + ins_cost(100); + format %{ "ucomisd $src1, $src2" %} + opcode(0x66, 0x0F, 0x2E); + ins_encode(OpcP, REX_reg_mem(src1, src2), OpcS, OpcT, reg_mem(src1, src2)); + ins_pipe(pipe_slow); +%} + instruct cmpD_cc_imm(rFlagsRegU cr, regD src1, immD src2) %{ match(Set cr (CmpD src1 src2)); @@ -9801,6 +9962,16 @@ ins_pipe(pipe_slow); %} +instruct cmpD_cc_immCF(rFlagsRegUCF cr, regD src1, immD src2) %{ + match(Set cr (CmpD src1 src2)); + + ins_cost(100); + format %{ "ucomisd $src1, [$src2]" %} + opcode(0x66, 0x0F, 0x2E); + ins_encode(OpcP, REX_reg_mem(src1, src2), OpcS, OpcT, load_immD(src1, src2)); + ins_pipe(pipe_slow); +%} + // Compare into -1,0,1 instruct cmpF_reg(rRegI dst, regF src1, regF src2, rFlagsReg cr) %{ @@ -11406,8 +11577,7 @@ %} // Jump Direct Conditional - Label defines a relative address from Jcc+1 -instruct jmpLoopEndU(cmpOpU cop, rFlagsRegU cmp, label labl) -%{ +instruct jmpLoopEndU(cmpOpU cop, rFlagsRegU cmp, label labl) %{ match(CountedLoopEnd cop cmp); effect(USE labl); @@ -11420,14 +11590,39 @@ ins_pc_relative(1); %} +instruct jmpLoopEndUCF(cmpOpUCF cop, rFlagsRegUCF cmp, label labl) %{ + match(CountedLoopEnd cop cmp); + effect(USE labl); + + ins_cost(200); + format %{ "j$cop,u $labl\t# loop end" %} + size(6); + opcode(0x0F, 0x80); + ins_encode(Jcc(cop, labl)); + ins_pipe(pipe_jcc); + ins_pc_relative(1); +%} + // Jump Direct Conditional - using unsigned comparison -instruct jmpConU(cmpOpU cop, rFlagsRegU cmp, label labl) -%{ +instruct jmpConU(cmpOpU cop, rFlagsRegU cmp, label labl) %{ match(If cop cmp); effect(USE labl); ins_cost(300); - format %{ "j$cop,u $labl" %} + format %{ "j$cop,u $labl" %} + size(6); + opcode(0x0F, 0x80); + ins_encode(Jcc(cop, labl)); + ins_pipe(pipe_jcc); + ins_pc_relative(1); +%} + +instruct jmpConUCF(cmpOpUCF cop, rFlagsRegUCF cmp, label labl) %{ + match(If cop cmp); + effect(USE labl); + + ins_cost(200); + format %{ "j$cop,u $labl" %} size(6); opcode(0x0F, 0x80); ins_encode(Jcc(cop, labl)); @@ -11435,6 +11630,46 @@ ins_pc_relative(1); %} +instruct jmpConUCF2(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{ + match(If cop cmp); + effect(USE labl); + + ins_cost(200); + format %{ $$template + if ($cop$$cmpcode == Assembler::notEqual) { + $$emit$$"jp,u $labl\n\t" + $$emit$$"j$cop,u $labl" + } else { + $$emit$$"jp,u done\n\t" + $$emit$$"j$cop,u $labl\n\t" + $$emit$$"done:" + } + %} + size(12); + opcode(0x0F, 0x80); + ins_encode %{ + Label* l = $labl$$label; + $$$emit8$primary; + emit_cc(cbuf, $secondary, Assembler::parity); + int parity_disp = -1; + if ($cop$$cmpcode == Assembler::notEqual) { + // the two jumps 6 bytes apart so the jump distances are too + parity_disp = l ? (l->loc_pos() - (cbuf.code_size() + 4)) : 0; + } else if ($cop$$cmpcode == Assembler::equal) { + parity_disp = 6; + } else { + ShouldNotReachHere(); + } + emit_d32(cbuf, parity_disp); + $$$emit8$primary; + emit_cc(cbuf, $secondary, $cop$$cmpcode); + int disp = l ? (l->loc_pos() - (cbuf.code_size() + 4)) : 0; + emit_d32(cbuf, disp); + %} + ins_pipe(pipe_jcc); + ins_pc_relative(1); +%} + // ============================================================================ // The 2nd slow-half of a subtype check. Scan the subklass's 2ndary // superklass array for an instance of the superklass. Set a hidden @@ -11505,8 +11740,7 @@ // specific code section of the file. // Jump Direct - Label defines a relative address from JMP+1 -instruct jmpDir_short(label labl) -%{ +instruct jmpDir_short(label labl) %{ match(Goto); effect(USE labl); @@ -11521,8 +11755,7 @@ %} // Jump Direct Conditional - Label defines a relative address from Jcc+1 -instruct jmpCon_short(cmpOp cop, rFlagsReg cr, label labl) -%{ +instruct jmpCon_short(cmpOp cop, rFlagsReg cr, label labl) %{ match(If cop cr); effect(USE labl); @@ -11537,13 +11770,12 @@ %} // Jump Direct Conditional - Label defines a relative address from Jcc+1 -instruct jmpLoopEnd_short(cmpOp cop, rFlagsReg cr, label labl) -%{ +instruct jmpLoopEnd_short(cmpOp cop, rFlagsReg cr, label labl) %{ match(CountedLoopEnd cop cr); effect(USE labl); ins_cost(300); - format %{ "j$cop,s $labl" %} + format %{ "j$cop,s $labl\t# loop end" %} size(2); opcode(0x70); ins_encode(JccShort(cop, labl)); @@ -11553,12 +11785,40 @@ %} // Jump Direct Conditional - Label defines a relative address from Jcc+1 -instruct jmpLoopEndU_short(cmpOpU cop, rFlagsRegU cmp, label labl) -%{ +instruct jmpLoopEndU_short(cmpOpU cop, rFlagsRegU cmp, label labl) %{ + match(CountedLoopEnd cop cmp); + effect(USE labl); + + ins_cost(300); + format %{ "j$cop,us $labl\t# loop end" %} + size(2); + opcode(0x70); + ins_encode(JccShort(cop, labl)); + ins_pipe(pipe_jcc); + ins_pc_relative(1); + ins_short_branch(1); +%} + +instruct jmpLoopEndUCF_short(cmpOpUCF cop, rFlagsRegUCF cmp, label labl) %{ match(CountedLoopEnd cop cmp); effect(USE labl); ins_cost(300); + format %{ "j$cop,us $labl\t# loop end" %} + size(2); + opcode(0x70); + ins_encode(JccShort(cop, labl)); + ins_pipe(pipe_jcc); + ins_pc_relative(1); + ins_short_branch(1); +%} + +// Jump Direct Conditional - using unsigned comparison +instruct jmpConU_short(cmpOpU cop, rFlagsRegU cmp, label labl) %{ + match(If cop cmp); + effect(USE labl); + + ins_cost(300); format %{ "j$cop,us $labl" %} size(2); opcode(0x70); @@ -11568,9 +11828,7 @@ ins_short_branch(1); %} -// Jump Direct Conditional - using unsigned comparison -instruct jmpConU_short(cmpOpU cop, rFlagsRegU cmp, label labl) -%{ +instruct jmpConUCF_short(cmpOpUCF cop, rFlagsRegUCF cmp, label labl) %{ match(If cop cmp); effect(USE labl); @@ -11584,6 +11842,46 @@ ins_short_branch(1); %} +instruct jmpConUCF2_short(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{ + match(If cop cmp); + effect(USE labl); + + ins_cost(300); + format %{ $$template + if ($cop$$cmpcode == Assembler::notEqual) { + $$emit$$"jp,u,s $labl\n\t" + $$emit$$"j$cop,u,s $labl" + } else { + $$emit$$"jp,u,s done\n\t" + $$emit$$"j$cop,u,s $labl\n\t" + $$emit$$"done:" + } + %} + size(4); + opcode(0x70); + ins_encode %{ + Label* l = $labl$$label; + emit_cc(cbuf, $primary, Assembler::parity); + int parity_disp = -1; + if ($cop$$cmpcode == Assembler::notEqual) { + parity_disp = l ? (l->loc_pos() - (cbuf.code_size() + 1)) : 0; + } else if ($cop$$cmpcode == Assembler::equal) { + parity_disp = 2; + } else { + ShouldNotReachHere(); + } + emit_d8(cbuf, parity_disp); + emit_cc(cbuf, $primary, $cop$$cmpcode); + int disp = l ? (l->loc_pos() - (cbuf.code_size() + 1)) : 0; + emit_d8(cbuf, disp); + assert(-128 <= disp && disp <= 127, "Displacement too large for short jmp"); + assert(-128 <= parity_disp && parity_disp <= 127, "Displacement too large for short jmp"); + %} + ins_pipe(pipe_jcc); + ins_pc_relative(1); + ins_short_branch(1); +%} + // ============================================================================ // inlined locking and unlocking diff -r 8fa025608ec6 -r b5e603f2e024 src/os_cpu/linux_x86/vm/linux_x86_32.ad --- a/src/os_cpu/linux_x86/vm/linux_x86_32.ad Tue Nov 18 14:52:33 2008 -0800 +++ b/src/os_cpu/linux_x86/vm/linux_x86_32.ad Wed Nov 19 14:20:51 2008 -0800 @@ -103,16 +103,16 @@ // This name is KNOWN by the ADLC and cannot be changed. // The ADLC forces a 'TypeRawPtr::BOTTOM' output type // for this guy. -instruct tlsLoadP(eAXRegP dst, eFlagsReg cr) %{ +instruct tlsLoadP(eRegP dst, eFlagsReg cr) %{ match(Set dst (ThreadLocal)); effect(DEF dst, KILL cr); - format %{ "MOV EAX, Thread::current()" %} + format %{ "MOV $dst, Thread::current()" %} ins_encode( linux_tlsencode(dst) ); ins_pipe( ialu_reg_fat ); %} -instruct TLS(eAXRegP dst) %{ +instruct TLS(eRegP dst) %{ match(Set dst (ThreadLocal)); expand %{ diff -r 8fa025608ec6 -r b5e603f2e024 src/os_cpu/solaris_x86/vm/solaris_x86_32.ad --- a/src/os_cpu/solaris_x86/vm/solaris_x86_32.ad Tue Nov 18 14:52:33 2008 -0800 +++ b/src/os_cpu/solaris_x86/vm/solaris_x86_32.ad Wed Nov 19 14:20:51 2008 -0800 @@ -110,16 +110,16 @@ // This name is KNOWN by the ADLC and cannot be changed. // The ADLC forces a 'TypeRawPtr::BOTTOM' output type // for this guy. -instruct tlsLoadP(eAXRegP dst, eFlagsReg cr) %{ +instruct tlsLoadP(eRegP dst, eFlagsReg cr) %{ match(Set dst (ThreadLocal)); effect(DEF dst, KILL cr); - format %{ "MOV EAX, Thread::current()" %} + format %{ "MOV $dst, Thread::current()" %} ins_encode( solaris_tlsencode(dst) ); ins_pipe( ialu_reg_fat ); %} -instruct TLS(eAXRegP dst) %{ +instruct TLS(eRegP dst) %{ match(Set dst (ThreadLocal)); expand %{ diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Bytecodes/src/com/sun/hotspot/igv/bytecodes/BytecodeViewTopComponent.java --- a/src/share/tools/IdealGraphVisualizer/Bytecodes/src/com/sun/hotspot/igv/bytecodes/BytecodeViewTopComponent.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Bytecodes/src/com/sun/hotspot/igv/bytecodes/BytecodeViewTopComponent.java Wed Nov 19 14:20:51 2008 -0800 @@ -28,6 +28,7 @@ import com.sun.hotspot.igv.data.services.InputGraphProvider; import java.awt.BorderLayout; import java.io.Serializable; +import javax.swing.SwingUtilities; import org.openide.ErrorManager; import org.openide.explorer.ExplorerManager; import org.openide.explorer.ExplorerUtils; @@ -151,14 +152,18 @@ } public void resultChanged(LookupEvent lookupEvent) { - InputGraphProvider p = Lookup.getDefault().lookup(InputGraphProvider.class); + final InputGraphProvider p = Lookup.getDefault().lookup(InputGraphProvider.class); if (p != null) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { InputGraph graph = p.getGraph(); if (graph != null) { Group g = graph.getGroup(); rootNode.update(graph, g.getMethod()); } } + }); + } } final static class ResolvableHelper implements Serializable { diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/ControlFlow/src/com/sun/hotspot/igv/controlflow/ControlFlowScene.java --- a/src/share/tools/IdealGraphVisualizer/ControlFlow/src/com/sun/hotspot/igv/controlflow/ControlFlowScene.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/ControlFlow/src/com/sun/hotspot/igv/controlflow/ControlFlowScene.java Wed Nov 19 14:20:51 2008 -0800 @@ -33,7 +33,7 @@ import java.awt.Rectangle; import java.util.ArrayList; import java.util.HashSet; -import java.util.Hashtable; +import java.util.HashMap; import java.util.Set; import javax.swing.BorderFactory; import org.netbeans.api.visual.action.ActionFactory; @@ -44,7 +44,6 @@ import org.netbeans.api.visual.action.WidgetAction; import org.netbeans.api.visual.anchor.AnchorFactory; import org.netbeans.api.visual.anchor.AnchorShape; -import com.sun.hotspot.igv.controlflow.HierarchicalGraphLayout; import org.netbeans.api.visual.layout.LayoutFactory; import org.netbeans.api.visual.router.RouterFactory; import org.netbeans.api.visual.widget.LayerWidget; @@ -61,8 +60,8 @@ */ public class ControlFlowScene extends GraphScene implements SelectProvider, MoveProvider, RectangularSelectDecorator, RectangularSelectProvider { - private Set selection; - private Hashtable blockMap; + private HashSet selection; + private HashMap blockMap; private InputGraph oldGraph; private LayerWidget edgeLayer; private LayerWidget mainLayer; diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/ControlFlow/src/com/sun/hotspot/igv/controlflow/ControlFlowTopComponent.java --- a/src/share/tools/IdealGraphVisualizer/ControlFlow/src/com/sun/hotspot/igv/controlflow/ControlFlowTopComponent.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/ControlFlow/src/com/sun/hotspot/igv/controlflow/ControlFlowTopComponent.java Wed Nov 19 14:20:51 2008 -0800 @@ -28,6 +28,7 @@ import java.awt.BorderLayout; import java.io.Serializable; import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; import org.openide.ErrorManager; import org.openide.util.Lookup; import org.openide.util.LookupEvent; @@ -143,13 +144,17 @@ public void resultChanged(LookupEvent lookupEvent) { - InputGraphProvider p = Lookup.getDefault().lookup(InputGraphProvider.class); + final InputGraphProvider p = Lookup.getDefault().lookup(InputGraphProvider.class); if (p != null) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { InputGraph g = p.getGraph(); if (g != null) { scene.setGraph(g); } } + }); + } } @Override diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/FolderNode.java --- a/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/FolderNode.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/FolderNode.java Wed Nov 19 14:20:51 2008 -0800 @@ -24,6 +24,7 @@ package com.sun.hotspot.igv.coordinator; import com.sun.hotspot.igv.coordinator.actions.RemoveCookie; +import com.sun.hotspot.igv.data.ChangedListener; import com.sun.hotspot.igv.data.Group; import com.sun.hotspot.igv.data.services.GroupOrganizer; import com.sun.hotspot.igv.data.InputGraph; @@ -50,17 +51,24 @@ private List subFolders; private FolderChildren children; - private static class FolderChildren extends Children.Keys { + private static class FolderChildren extends Children.Keys implements ChangedListener { private FolderNode parent; + private List registeredGroups; public void setParent(FolderNode parent) { this.parent = parent; + this.registeredGroups = new ArrayList(); } @Override protected Node[] createNodes(Object arg0) { + for(Group g : registeredGroups) { + g.getChangedEvent().removeListener(this); + } + registeredGroups.clear(); + Pair> p = (Pair>) arg0; if (p.getLeft().length() == 0) { @@ -69,6 +77,8 @@ for (InputGraph graph : g.getGraphs()) { curNodes.add(new GraphNode(graph)); } + g.getChangedEvent().addListener(this); + registeredGroups.add(g); } Node[] result = new Node[curNodes.size()]; @@ -85,7 +95,13 @@ @Override public void addNotify() { this.setKeys(parent.structure); + } + public void changed(Group source) { + List>> newStructure = new ArrayList>>(); + for(Pair> p : parent.structure) { + refreshKey(p); + } } } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/GraphDocument.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/GraphDocument.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/GraphDocument.java Wed Nov 19 14:20:51 2008 -0800 @@ -31,7 +31,7 @@ * * @author Thomas Wuerthinger */ -public class GraphDocument extends Properties.Object implements ChangedEventProvider { +public class GraphDocument extends Properties.Entity implements ChangedEventProvider { private List groups; private ChangedEvent changedEvent; diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Group.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Group.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Group.java Wed Nov 19 14:20:51 2008 -0800 @@ -37,7 +37,7 @@ * * @author Thomas Wuerthinger */ -public class Group extends Properties.Object implements ChangedEventProvider { +public class Group extends Properties.Entity implements ChangedEventProvider { private List graphs; private transient ChangedEvent changedEvent; diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java Wed Nov 19 14:20:51 2008 -0800 @@ -23,26 +23,25 @@ */ package com.sun.hotspot.igv.data; -import com.sun.hotspot.igv.data.Properties; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; -import java.util.Hashtable; +import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Set; /** * * @author Thomas Wuerthinger */ -public class InputGraph extends Properties.Object { +public class InputGraph extends Properties.Entity { - private Map nodes; - private Set edges; + private HashMap nodes; + private ArrayList edges; private Group parent; - private Map blocks; - private Map nodeToBlock; + private HashMap blocks; + private HashMap nodeToBlock; private boolean isDifferenceGraph; public InputGraph(Group parent) { @@ -61,10 +60,10 @@ public InputGraph(Group parent, InputGraph last, String name) { this.parent = parent; setName(name); - nodes = new Hashtable(); - edges = new HashSet(); - blocks = new Hashtable(); - nodeToBlock = new Hashtable(); + nodes = new HashMap(); + edges = new ArrayList(); + blocks = new HashMap(); + nodeToBlock = new HashMap(); if (last != null) { for (InputNode n : last.getNodes()) { @@ -182,8 +181,8 @@ return nodes.remove(index); } - public Set getEdges() { - return Collections.unmodifiableSet(edges); + public Collection getEdges() { + return Collections.unmodifiableList(edges); } public void removeEdge(InputEdge c) { diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputMethod.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputMethod.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputMethod.java Wed Nov 19 14:20:51 2008 -0800 @@ -32,7 +32,7 @@ * * @author Thomas Wuerthinger */ -public class InputMethod extends Properties.Object { +public class InputMethod extends Properties.Entity { private String name; private int bci; diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputNode.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputNode.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputNode.java Wed Nov 19 14:20:51 2008 -0800 @@ -27,7 +27,7 @@ * * @author Thomas Wuerthinger */ -public class InputNode extends Properties.Object { +public class InputNode extends Properties.Entity { private int id; diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java Wed Nov 19 14:20:51 2008 -0800 @@ -26,24 +26,22 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; +import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; + /** * * @author Thomas Wuerthinger */ -public class Properties implements Serializable { +public class Properties implements Serializable, Iterable { public static final long serialVersionUID = 1L; - private Map map; + private String[] map = new String[4]; public Properties() { - map = new HashMap(5); } @Override @@ -54,10 +52,7 @@ Properties p = (Properties) o; - if (getProperties().size() != p.getProperties().size()) { - return false; - } - for (Property prop : getProperties()) { + for (Property prop : this) { String value = p.get(prop.getName()); if (value == null || !value.equals(prop.getValue())) { return false; @@ -75,32 +70,33 @@ public Properties(String name, String value) { this(); - this.add(new Property(name, value)); + this.setProperty(name, value); } public Properties(String name, String value, String name1, String value1) { this(name, value); - this.add(new Property(name1, value1)); + this.setProperty(name1, value1); } public Properties(String name, String value, String name1, String value1, String name2, String value2) { this(name, value, name1, value1); - this.add(new Property(name2, value2)); + this.setProperty(name2, value2); } public Properties(Properties p) { - map = new HashMap(p.map); + map = new String[p.map.length]; + System.arraycopy(map, 0, p.map, 0, p.map.length); } - public static class Object implements Provider { + public static class Entity implements Provider { private Properties properties; - public Object() { + public Entity() { properties = new Properties(); } - public Object(Properties.Object object) { + public Entity(Properties.Entity object) { properties = new Properties(object.getProperties()); } @@ -109,6 +105,14 @@ } } + private String getProperty(String key) { + for (int i = 0; i < map.length; i += 2) + if (map[i] != null && map[i].equals(key)) { + return map[i + 1]; + } + return null; + } + public interface PropertyMatcher { String getName(); @@ -173,13 +177,15 @@ } public Property selectSingle(PropertyMatcher matcher) { - - Property p = this.map.get(matcher.getName()); - if (p == null) { - return null; + String value = null; + for (int i = 0; i < map.length; i += 2) { + if (map[i] != null && matcher.getName().equals(map[i])) { + value = map[i + 1]; + break; + } } - if (matcher.match(p.getValue())) { - return p; + if (value != null && matcher.match(value)) { + return new Property(matcher.getName(), value); } else { return null; } @@ -194,8 +200,11 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append("["); - for (Property p : map.values()) { - sb.append(p.toString()); + for (int i = 0; i < map.length; i += 2) { + if (map[i + 1] != null) { + String p = map[i + 1]; + sb.append(map[i] + " = " + map[i + 1] + "; "); + } } return sb.append("]").toString(); } @@ -241,41 +250,51 @@ } public String get(String key) { - Property p = map.get(key); - if (p == null) { - return null; - } else { - return p.getValue(); + for (int i = 0; i < map.length; i += 2) { + if (map[i] != null && map[i].equals(key)) { + return map[i + 1]; + } } - } - - public String getProperty(String string) { - return get(string); + return null; } - public Property setProperty(String name, String value) { - + public void setProperty(String name, String value) { + for (int i = 0; i < map.length; i += 2) { + if (map[i] != null && map[i].equals(name)) { + String p = map[i + 1]; + if (value == null) { + // remove this property + map[i] = null; + map[i + 1] = null; + } else { + map[i + 1] = value; + } + return; + } + } if (value == null) { - // remove this property - return map.remove(name); - } else { - Property p = map.get(name); - if (p == null) { - p = new Property(name, value); - map.put(name, p); - } else { - p.setValue(value); + return; + } + for (int i = 0; i < map.length; i += 2) { + if (map[i] == null) { + map[i] = name; + map[i + 1] = value; + return; } - return p; } + String[] newMap = new String[map.length + 4]; + System.arraycopy(map, 0, newMap, 0, map.length); + newMap[map.length] = name; + newMap[map.length + 1] = value; + map = newMap; } - public Collection getProperties() { - return Collections.unmodifiableCollection(map.values()); + public Iterator getProperties() { + return iterator(); } public void add(Properties properties) { - for (Property p : properties.getProperties()) { + for (Property p : properties) { add(p); } } @@ -283,6 +302,35 @@ public void add(Property property) { assert property.getName() != null; assert property.getValue() != null; - map.put(property.getName(), property); + setProperty(property.getName(), property.getValue()); + } + class PropertiesIterator implements Iterator, Iterable { + public Iterator iterator() { + return this; + } + + int index; + + public boolean hasNext() { + while (index < map.length && map[index + 1] == null) + index += 2; + return index < map.length; + } + + public Property next() { + if (index < map.length) { + index += 2; + return new Property(map[index - 2], map[index - 1]); + } + return null; + } + + public void remove() { + throw new UnsupportedOperationException("Not supported yet."); + } + + } + public Iterator iterator() { + return new PropertiesIterator(); } } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Property.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Property.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Property.java Wed Nov 19 14:20:51 2008 -0800 @@ -32,18 +32,19 @@ public class Property implements Serializable { public static final long serialVersionUID = 1L; + private String name; private String value; - public Property() { + private Property() { this(null, null); } - public Property(Property p) { + private Property(Property p) { this(p.getName(), p.getValue()); } - public Property(String name) { + private Property(String name) { this(name, null); } @@ -60,16 +61,19 @@ return value; } - public void setName(String s) { - this.name = s; - } - - public void setValue(String s) { - this.value = s; - } - @Override public String toString() { return name + " = " + value + "; "; } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Property)) return false; + Property p2 = (Property)o; + return name.equals(p2.name) && value.equals(p2.value); + } + @Override + public int hashCode() { + return name.hashCode() + value == null ? 0 : value.hashCode(); + } } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java Wed Nov 19 14:20:51 2008 -0800 @@ -38,6 +38,7 @@ import com.sun.hotspot.igv.data.serialization.XMLParser.ParseMonitor; import com.sun.hotspot.igv.data.serialization.XMLParser.TopElementHandler; import java.io.IOException; +import java.util.HashMap; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; @@ -88,6 +89,18 @@ private TopElementHandler xmlDocument = new TopElementHandler(); private boolean difference; private GroupCallback groupCallback; + private HashMap idCache = new HashMap(); + private int maxId = 0; + + private int lookupID(String i) { + Integer id = idCache.get(i); + if (id == null) { + id = maxId++; + idCache.put(i, id); + } + return id.intValue(); + } + // private ElementHandler topHandler = new ElementHandler(TOP_ELEMENT) { @@ -187,13 +200,13 @@ previous = null; } InputGraph curGraph = new InputGraph(getParentObject(), previous, name); - getParentObject().addGraph(curGraph); this.graph = curGraph; return curGraph; } @Override protected void end(String text) throws SAXException { + getParentObject().addGraph(graph); graph.resolveBlockLinks(); } }; @@ -207,7 +220,7 @@ @Override protected InputBlock start() throws SAXException { InputGraph graph = getParentObject(); - String name = readRequiredAttribute(BLOCK_NAME_PROPERTY); + String name = readRequiredAttribute(BLOCK_NAME_PROPERTY).intern(); InputBlock b = new InputBlock(getParentObject(), name); graph.addBlock(b); return b; @@ -224,7 +237,7 @@ int id = 0; try { - id = Integer.parseInt(s); + id = lookupID(s); } catch (NumberFormatException e) { throw new SAXException(e); } @@ -252,7 +265,7 @@ String s = readRequiredAttribute(NODE_ID_PROPERTY); int id = 0; try { - id = Integer.parseInt(s); + id = lookupID(s); } catch (NumberFormatException e) { throw new SAXException(e); } @@ -269,7 +282,7 @@ String s = readRequiredAttribute(NODE_ID_PROPERTY); int id = 0; try { - id = Integer.parseInt(s); + id = lookupID(s); } catch (NumberFormatException e) { throw new SAXException(e); } @@ -280,7 +293,7 @@ private HandoverElementHandler edgesHandler = new HandoverElementHandler(EDGES_ELEMENT); // Local class for edge elements - private static class EdgeElementHandler extends ElementHandler { + private class EdgeElementHandler extends ElementHandler { public EdgeElementHandler(String name) { super(name); @@ -298,8 +311,8 @@ toIndex = Integer.parseInt(toIndexString); } - from = Integer.parseInt(readRequiredAttribute(FROM_PROPERTY)); - to = Integer.parseInt(readRequiredAttribute(TO_PROPERTY)); + from = lookupID(readRequiredAttribute(FROM_PROPERTY)); + to = lookupID(readRequiredAttribute(TO_PROPERTY)); } catch (NumberFormatException e) { throw new SAXException(e); } @@ -344,18 +357,16 @@ } }; // - private ElementHandler propertyHandler = new XMLParser.ElementHandler(PROPERTY_ELEMENT, true) { + private ElementHandler propertyHandler = new XMLParser.ElementHandler(PROPERTY_ELEMENT, true) { @Override - public Property start() throws SAXException { - String value = ""; - String name = readRequiredAttribute(PROPERTY_NAME_PROPERTY).intern(); - return getParentObject().getProperties().setProperty(name, value); + public String start() throws SAXException { + return readRequiredAttribute(PROPERTY_NAME_PROPERTY).intern(); } @Override public void end(String text) { - getObject().setValue(text.trim().intern()); + getParentObject().getProperties().setProperty(getObject(), text.trim().intern()); } }; diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Printer.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Printer.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Printer.java Wed Nov 19 14:20:51 2008 -0800 @@ -67,7 +67,7 @@ private void export(XMLWriter writer, Group g) throws IOException { Properties attributes = new Properties(); - attributes.add(new Property("difference", Boolean.toString(true))); + attributes.setProperty("difference", Boolean.toString(true)); writer.startTag(Parser.GROUP_ELEMENT, attributes); writer.writeProperties(g.getProperties()); diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/XMLParser.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/XMLParser.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/XMLParser.java Wed Nov 19 14:20:51 2008 -0800 @@ -25,7 +25,7 @@ import com.sun.hotspot.igv.data.Property; import com.sun.hotspot.igv.data.Properties; -import java.util.Hashtable; +import java.util.HashMap; import java.util.Stack; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; @@ -89,7 +89,7 @@ private Attributes attr; private StringBuilder currentText; private ParseMonitor monitor; - private Hashtable> hashtable; + private HashMap> hashtable; private boolean needsText; private ElementHandler parentElement; @@ -110,7 +110,7 @@ } public ElementHandler(String name, boolean needsText) { - this.hashtable = new Hashtable>(); + this.hashtable = new HashMap>(); this.name = name; this.needsText = needsText; } @@ -153,7 +153,7 @@ for (int i = 0; i < length; i++) { String val = attr.getValue(i).intern(); String localName = attr.getLocalName(i).intern(); - p.add(new Property(val, localName)); + p.setProperty(val, localName); } } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/XMLWriter.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/XMLWriter.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/XMLWriter.java Wed Nov 19 14:20:51 2008 -0800 @@ -89,7 +89,7 @@ inner.write("<" + name); elementStack.push(name); - for (Property p : attributes.getProperties()) { + for (Property p : attributes) { inner.write(" " + p.getName() + "=\""); write(p.getValue().toCharArray()); inner.write("\""); @@ -101,7 +101,7 @@ public void simpleTag(String name, Properties attributes) throws IOException { inner.write("<" + name); - for (Property p : attributes.getProperties()) { + for (Property p : attributes) { inner.write(" " + p.getName() + "=\""); write(p.getValue().toCharArray()); inner.write("\""); @@ -111,13 +111,13 @@ } public void writeProperties(Properties props) throws IOException { - if (props.getProperties().size() == 0) { + if (props.getProperties().hasNext() == false) { return; } startTag(Parser.PROPERTIES_ELEMENT); - for (Property p : props.getProperties()) { + for (Property p : props) { startTag(Parser.PROPERTY_ELEMENT, new Properties(Parser.PROPERTY_NAME_PROPERTY, p.getName())); this.write(p.getValue().toCharArray()); endTag(); diff -r 8fa025608ec6 -r b5e603f2e024 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 Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Difference/src/com/sun/hotspot/igv/difference/Difference.java Wed Nov 19 14:20:51 2008 -0800 @@ -29,6 +29,7 @@ import com.sun.hotspot.igv.data.InputGraph; import com.sun.hotspot.igv.data.InputNode; import com.sun.hotspot.igv.data.Property; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -124,8 +125,8 @@ inputNodeMap.put(n, n2); } - Set edgesA = a.getEdges(); - Set edgesB = b.getEdges(); + Collection edgesA = a.getEdges(); + Collection edgesB = b.getEdges(); Set newEdges = new HashSet(); @@ -182,7 +183,7 @@ public double getValue() { double result = 0.0; - for (Property p : n1.getProperties().getProperties()) { + for (Property p : n1.getProperties()) { double faktor = 1.0; for (String forbidden : IGNORE_PROPERTIES) { if (p.getName().equals(forbidden)) { @@ -287,34 +288,34 @@ private static void markAsChanged(InputNode n, InputNode firstNode, InputNode otherNode) { boolean difference = false; - for (Property p : otherNode.getProperties().getProperties()) { - String s = firstNode.getProperties().getProperty(p.getName()); + for (Property p : otherNode.getProperties()) { + String s = firstNode.getProperties().get(p.getName()); if (!p.getValue().equals(s)) { difference = true; - n.getProperties().add(new Property(OLD_PREFIX + p.getName(), p.getValue())); + n.getProperties().setProperty(OLD_PREFIX + p.getName(), p.getValue()); } } - for (Property p : firstNode.getProperties().getProperties()) { - String s = otherNode.getProperties().getProperty(p.getName()); + for (Property p : firstNode.getProperties()) { + String s = otherNode.getProperties().get(p.getName()); if (s == null && p.getValue().length() > 0) { difference = true; - n.getProperties().add(new Property(OLD_PREFIX + p.getName(), "")); + n.getProperties().setProperty(OLD_PREFIX + p.getName(), ""); } } if (difference) { - n.getProperties().add(new Property(PROPERTY_STATE, VALUE_CHANGED)); + n.getProperties().setProperty(PROPERTY_STATE, VALUE_CHANGED); } else { - n.getProperties().add(new Property(PROPERTY_STATE, VALUE_SAME)); + n.getProperties().setProperty(PROPERTY_STATE, VALUE_SAME); } } private static void markAsDeleted(InputNode n) { - n.getProperties().add(new Property(PROPERTY_STATE, VALUE_DELETED)); + n.getProperties().setProperty(PROPERTY_STATE, VALUE_DELETED); } private static void markAsNew(InputNode n) { - n.getProperties().add(new Property(PROPERTY_STATE, VALUE_NEW)); + n.getProperties().setProperty(PROPERTY_STATE, VALUE_NEW); } } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Filter/manifest.mf --- a/src/share/tools/IdealGraphVisualizer/Filter/manifest.mf Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Filter/manifest.mf Wed Nov 19 14:20:51 2008 -0800 @@ -1,6 +1,6 @@ -Manifest-Version: 1.0 -OpenIDE-Module: com.sun.hotspot.igv.filter -OpenIDE-Module-Layer: com/sun/hotspot/igv/filter/layer.xml -OpenIDE-Module-Localizing-Bundle: com/sun/hotspot/igv/filter/Bundle.properties -OpenIDE-Module-Specification-Version: 1.0 - +Manifest-Version: 1.0 +OpenIDE-Module: com.sun.hotspot.igv.filter +OpenIDE-Module-Layer: com/sun/hotspot/igv/filter/layer.xml +OpenIDE-Module-Localizing-Bundle: com/sun/hotspot/igv/filter/Bundle.properties +OpenIDE-Module-Specification-Version: 1.0 + diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/CustomFilter.java --- a/src/share/tools/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/CustomFilter.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/CustomFilter.java Wed Nov 19 14:20:51 2008 -0800 @@ -25,7 +25,6 @@ package com.sun.hotspot.igv.filter; import com.sun.hotspot.igv.graph.Diagram; -import com.sun.hotspot.igv.data.Property; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -56,7 +55,7 @@ public CustomFilter(String name, String code) { this.name = name; this.code = code; - getProperties().add(new Property("name", name)); + getProperties().setProperty("name", name); } public String getName() { diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/SplitFilter.java --- a/src/share/tools/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/SplitFilter.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Filter/src/com/sun/hotspot/igv/filter/SplitFilter.java Wed Nov 19 14:20:51 2008 -0800 @@ -56,8 +56,8 @@ for (OutputSlot os : f.getOutputSlots()) { for (Connection c : os.getConnections()) { InputSlot is = c.getInputSlot(); - is.setName(f.getProperties().getProperty("dump_spec")); - String s = f.getProperties().getProperty("short_name"); + is.setName(f.getProperties().get("dump_spec")); + String s = f.getProperties().get("short_name"); if (s != null) { is.setShortName(s); } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java --- a/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java Wed Nov 19 14:20:51 2008 -0800 @@ -35,7 +35,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; -import java.util.Hashtable; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -126,7 +126,7 @@ d.updateBlocks(); Collection nodes = graph.getNodes(); - Hashtable figureHash = new Hashtable(); + HashMap figureHash = new HashMap(); for (InputNode n : nodes) { Figure f = d.createFigure(); f.getSource().addSourceNode(n); diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Figure.java --- a/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Figure.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Figure.java Wed Nov 19 14:20:51 2008 -0800 @@ -42,7 +42,7 @@ * * @author Thomas Wuerthinger */ -public class Figure extends Properties.Object implements Source.Provider, Vertex { +public class Figure extends Properties.Entity implements Source.Provider, Vertex { public static final int INSET = 6; public static final int SLOT_WIDTH = 10; diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/Graph.java --- a/src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/Graph.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/Graph.java Wed Nov 19 14:20:51 2008 -0800 @@ -26,7 +26,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Hashtable; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Queue; @@ -37,13 +37,13 @@ */ public class Graph { - private Hashtable> nodes; - private Hashtable> edges; + private HashMap> nodes; + private HashMap> edges; private List> nodeList; public Graph() { - nodes = new Hashtable>(); - edges = new Hashtable>(); + nodes = new HashMap>(); + edges = new HashMap>(); nodeList = new ArrayList>(); } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalClusterLayoutManager.java --- a/src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalClusterLayoutManager.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalClusterLayoutManager.java Wed Nov 19 14:20:51 2008 -0800 @@ -25,7 +25,7 @@ import java.awt.Point; import java.awt.Rectangle; -import java.util.Hashtable; +import java.util.HashMap; import java.util.List; import java.util.Set; import java.util.ArrayList; @@ -69,19 +69,19 @@ assert graph.verify(); - Hashtable> lists = new Hashtable>(); - Hashtable> listsConnection = new Hashtable>(); - Hashtable> clusterInputSlotHash = new Hashtable>(); - Hashtable> clusterOutputSlotHash = new Hashtable>(); + HashMap> lists = new HashMap>(); + HashMap> listsConnection = new HashMap>(); + HashMap> clusterInputSlotHash = new HashMap>(); + HashMap> clusterOutputSlotHash = new HashMap>(); - Hashtable clusterNodes = new Hashtable(); - Hashtable> clusterInputSlotSet = new Hashtable>(); - Hashtable> clusterOutputSlotSet = new Hashtable>(); + HashMap clusterNodes = new HashMap(); + HashMap> clusterInputSlotSet = new HashMap>(); + HashMap> clusterOutputSlotSet = new HashMap>(); Set clusterEdges = new HashSet(); Set interClusterEdges = new HashSet(); - Hashtable linkClusterOutgoingConnection = new Hashtable(); - Hashtable linkInterClusterConnection = new Hashtable(); - Hashtable linkClusterIngoingConnection = new Hashtable(); + HashMap linkClusterOutgoingConnection = new HashMap(); + HashMap linkInterClusterConnection = new HashMap(); + HashMap linkClusterIngoingConnection = new HashMap(); Set clusterNodeSet = new HashSet(); Set cluster = graph.getClusters(); @@ -89,8 +89,8 @@ for (Cluster c : cluster) { lists.put(c, new ArrayList()); listsConnection.put(c, new ArrayList()); - clusterInputSlotHash.put(c, new Hashtable()); - clusterOutputSlotHash.put(c, new Hashtable()); + clusterInputSlotHash.put(c, new HashMap()); + clusterOutputSlotHash.put(c, new HashMap()); clusterOutputSlotSet.put(c, new TreeSet()); clusterInputSlotSet.put(c, new TreeSet()); ClusterNode cn = new ClusterNode(c, "" + z); diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Layout/src/com/sun/hotspot/igv/layout/LayoutGraph.java --- a/src/share/tools/IdealGraphVisualizer/Layout/src/com/sun/hotspot/igv/layout/LayoutGraph.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Layout/src/com/sun/hotspot/igv/layout/LayoutGraph.java Wed Nov 19 14:20:51 2008 -0800 @@ -24,7 +24,7 @@ package com.sun.hotspot.igv.layout; import java.util.HashSet; -import java.util.Hashtable; +import java.util.HashMap; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; @@ -37,9 +37,9 @@ private Set links; private SortedSet vertices; - private Hashtable> inputPorts; - private Hashtable> outputPorts; - private Hashtable> portLinks; + private HashMap> inputPorts; + private HashMap> outputPorts; + private HashMap> portLinks; public LayoutGraph(Set links) { this(links, new HashSet()); @@ -50,9 +50,9 @@ assert verify(); vertices = new TreeSet(); - portLinks = new Hashtable>(); - inputPorts = new Hashtable>(); - outputPorts = new Hashtable>(); + portLinks = new HashMap>(); + inputPorts = new HashMap>(); + outputPorts = new HashMap>(); for (Link l : links) { Port p = l.getFrom(); diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/README --- a/src/share/tools/IdealGraphVisualizer/README Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/README Wed Nov 19 14:20:51 2008 -0800 @@ -5,21 +5,16 @@ was the primary target of the tool. The tool itself is fairly general with only a few modules that contain C2 specific elements. -The tool is built on top of the NetBeans 6.0 rich client +The tool is built on top of the NetBeans 6.1 rich client infrastructure and so requires NetBeans to build. It currently requires Java 6 to run as it needs support for JavaScript for its filtering mechanism and assumes it's built into the platform. It -should build out of the box whit NetBeans 6 and Java 6 or later. It's -possible to run it on 1.5 by including Rhino on the classpath though -that currently isn't working correctly. Support for exporting graphs -as SVG can be enabled by adding batik to the classpath which isn't -included by default. - -It can be built on top of NetBeans 6.1 if you change the required -modules to be platform8 instead of platform7. The tool could run on -JDK 1.5 with some reworking of the how the JavaScript support is -enabled but currently it requires some tweaking of the setup. This -will be fixed in a later setup. +should build out of the box with NetBeans 6.1 and Java 6 or later. +It's possible to run it on 1.5 by including Rhino on the classpath +though that currently isn't working correctly. Support for exporting +graphs as SVG can be enabled by adding batik to the classpath which +isn't included by default. It can be built on top of NetBeans 6.0 if +you change the required modules to be platform7 instead of platform8. The JVM support is controlled by the flag -XX:PrintIdealGraphLevel=# where # is: diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/PropertiesSheet.java --- a/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/PropertiesSheet.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/PropertiesSheet.java Wed Nov 19 14:20:51 2008 -0800 @@ -36,11 +36,11 @@ */ public class PropertiesSheet { - public static void initializeSheet(Properties properties, Sheet s) { + public static void initializeSheet(final Properties properties, Sheet s) { Sheet.Set set1 = Sheet.createPropertiesSet(); set1.setDisplayName("Properties"); - for (final Property p : properties.getProperties()) { + for (final Property p : properties) { Node.Property prop = new Node.Property(String.class) { @Override @@ -60,7 +60,7 @@ @Override public void setValue(String arg0) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { - p.setValue(arg0); + properties.setProperty(p.getName(), arg0); } }; prop.setName(p.getName()); diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/RangeSliderModel.java --- a/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/RangeSliderModel.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/RangeSliderModel.java Wed Nov 19 14:20:51 2008 -0800 @@ -65,13 +65,19 @@ public RangeSliderModel(List positions) { assert positions.size() > 0; - this.positions = positions; this.changedEvent = new ChangedEvent(this); this.colorChangedEvent = new ChangedEvent(this); + setPositions(positions); + } + + protected void setPositions(List positions) { + this.positions = positions; colors = new ArrayList(); for (int i = 0; i < positions.size(); i++) { colors.add(Color.black); } + changedEvent.fire(); + colorChangedEvent.fire(); } public void setColors(List colors) { diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java Wed Nov 19 14:20:51 2008 -0800 @@ -63,7 +63,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.HashSet; -import java.util.Hashtable; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -104,10 +104,10 @@ */ public class DiagramScene extends Scene implements ChangedListener { - private Hashtable figureWidgets; - private Hashtable slotWidgets; - private Hashtable connectionWidgets; - private Hashtable blockWidgets; + private HashMap figureWidgets; + private HashMap slotWidgets; + private HashMap connectionWidgets; + private HashMap blockWidgets; private Widget hoverWidget; private WidgetAction hoverAction; private List selectedWidgets; @@ -414,7 +414,7 @@ this.addChild(selectLayer); this.getActions().addAction(ActionFactory.createRectangularSelectAction(rectangularSelectDecorator, selectLayer, rectangularSelectProvider)); - blockWidgets = new Hashtable(); + blockWidgets = new HashMap(); boolean b = this.getUndoRedoEnabled(); this.setUndoRedoEnabled(false); @@ -543,9 +543,9 @@ blockLayer.removeChildren(); blockWidgets.clear(); - figureWidgets = new Hashtable(); - slotWidgets = new Hashtable(); - connectionWidgets = new Hashtable(); + figureWidgets = new HashMap(); + slotWidgets = new HashMap(); + connectionWidgets = new HashMap(); WidgetAction selectAction = new ExtendedSelectAction(selectProvider); Diagram d = getModel().getDiagramToView(); diff -r 8fa025608ec6 -r b5e603f2e024 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 Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java Wed Nov 19 14:20:51 2008 -0800 @@ -55,6 +55,7 @@ private FilterChain filterChain; private FilterChain sequenceFilterChain; private Diagram diagram; + private ChangedEvent groupChangedEvent; private ChangedEvent diagramChangedEvent; private ChangedEvent viewChangedEvent; private ChangedEvent viewPropertiesChangedEvent; @@ -67,6 +68,7 @@ } }; + @Override public DiagramViewModel copy() { DiagramViewModel result = new DiagramViewModel(group, filterChain, sequenceFilterChain); result.setData(this); @@ -79,6 +81,7 @@ boolean viewChanged = false; boolean viewPropertiesChanged = false; + boolean groupChanged = (group == newModel.group); this.group = newModel.group; diagramChanged |= (filterChain != newModel.filterChain); this.filterChain = newModel.filterChain; @@ -97,6 +100,10 @@ viewPropertiesChanged |= (showNodeHull != newModel.showNodeHull); this.showNodeHull = newModel.showNodeHull; + if(groupChanged) { + groupChangedEvent.fire(); + } + if (diagramChanged) { diagramChangedEvent.fire(); } @@ -143,11 +150,38 @@ diagramChangedEvent = new ChangedEvent(this); viewChangedEvent = new ChangedEvent(this); viewPropertiesChangedEvent = new ChangedEvent(this); + groupChangedEvent = new ChangedEvent(this); + groupChangedEvent.addListener(groupChangedListener); + groupChangedEvent.fire(); filterChain.getChangedEvent().addListener(filterChainChangedListener); sequenceFilterChain.getChangedEvent().addListener(filterChainChangedListener); } + private final ChangedListener groupChangedListener = new ChangedListener() { + + private Group oldGroup; + + public void changed(DiagramViewModel source) { + if(oldGroup != null) { + oldGroup.getChangedEvent().removeListener(groupContentChangedListener); + } + group.getChangedEvent().addListener(groupContentChangedListener); + oldGroup = group; + } + }; + + + private final ChangedListener groupContentChangedListener = new ChangedListener() { + + public void changed(Group source) { + assert source == group; + setPositions(calculateStringList(source)); + setSelectedNodes(selectedNodes); + } + + }; + public ChangedEvent getDiagramChangedEvent() { return diagramChangedEvent; } @@ -268,7 +302,10 @@ } public InputGraph getSecondGraph() { - return group.getGraphs().get(getSecondPosition()); + List graphs = group.getGraphs(); + if (graphs.size() >= getSecondPosition()) + return group.getGraphs().get(getSecondPosition()); + return getFirstGraph(); } public void selectGraph(InputGraph g) { diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/FindPanel.java --- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/FindPanel.java Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/FindPanel.java Wed Nov 19 14:20:51 2008 -0800 @@ -67,7 +67,7 @@ for (Figure f : figures) { Properties prop = f.getProperties(); - for (Property p : prop.getProperties()) { + for (Property p : prop) { if (!propertyNames.contains(p.getName())) { propertyNames.add(p.getName()); } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/nbproject/platform.properties --- a/src/share/tools/IdealGraphVisualizer/nbproject/platform.properties Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/nbproject/platform.properties Wed Nov 19 14:20:51 2008 -0800 @@ -1,16 +1,16 @@ # Deprecated since 5.0u1; for compatibility with 5.0: disabled.clusters=\ apisupport1,\ + gsf1,\ harness,\ - ide8,\ - java1,\ - nb6.0,\ - profiler2 + ide9,\ + java2,\ + nb6.1,\ + profiler3 disabled.modules=\ org.netbeans.core.execution,\ org.netbeans.core.multiview,\ org.netbeans.core.output2,\ - org.netbeans.modules.applemenu,\ org.netbeans.modules.autoupdate.services,\ org.netbeans.modules.autoupdate.ui,\ org.netbeans.modules.core.kit,\ @@ -24,6 +24,6 @@ org.openide.execution,\ org.openide.util.enumerations enabled.clusters=\ - platform7 + platform8 nbjdk.active=default nbplatform.active=default diff -r 8fa025608ec6 -r b5e603f2e024 src/share/tools/IdealGraphVisualizer/nbproject/project.properties --- a/src/share/tools/IdealGraphVisualizer/nbproject/project.properties Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/tools/IdealGraphVisualizer/nbproject/project.properties Wed Nov 19 14:20:51 2008 -0800 @@ -15,7 +15,6 @@ ${project.com.sun.hotspot.igv.difference}:\ ${project.com.sun.hotspot.igv.settings}:\ ${project.com.sun.hotspot.igv.util}:\ - ${project.com.sun.hotspot.igv.rhino}:\ ${project.com.sun.hotspot.igv.svg}:\ ${project.com.sun.hotspot.connection}:\ ${project.com.sun.hotspot.igv.servercompilerscheduler}:\ @@ -31,10 +30,10 @@ project.com.sun.hotspot.igv.graph=Graph project.com.sun.hotspot.igv.hierarchicallayout=HierarchicalLayout project.com.sun.hotspot.igv.layout=Layout -project.com.sun.hotspot.igv.rhino=RhinoScriptEngineProxy project.com.sun.hotspot.igv.servercompilerscheduler=ServerCompiler project.com.sun.hotspot.igv.settings=Settings project.com.sun.hotspot.igv.svg=BatikSVGProxy project.com.sun.hotspot.igv.view=View project.com.sun.hotspot.igv.util=Util -run.args = -server -J-Xms64m -J-Xmx512m -J-da +run.args = -J-server -J-Xms64m -J-Xmx1g -J-da +run.args.extra = -J-server -J-Xms64m -J-Xmx1g -J-da diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/adlc/adlparse.cpp --- a/src/share/vm/adlc/adlparse.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/adlc/adlparse.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -33,7 +33,6 @@ _globalNames(archDesc.globalNames()) { _AD._syntax_errs = _AD._semantic_errs = 0; // No errors so far this file _AD._warnings = 0; // No warnings either - _linenum = 0; // Will increment to first line _curline = _ptr = NULL; // No pointers into buffer yet _preproc_depth = 0; @@ -76,7 +75,7 @@ } if (!_AD._quiet_mode) fprintf(stderr,"-----------------------------------------------------------------------------\n"); - _AD._TotalLines += _linenum-1; // -1 for overshoot in "nextline" routine + _AD._TotalLines += linenum()-1; // -1 for overshoot in "nextline" routine // Write out information we have stored // // UNIXism == fsync(stderr); @@ -148,7 +147,7 @@ if( (ident = get_unique_ident(_globalNames,"instruction")) == NULL ) return; instr = new InstructForm(ident); // Create new instruction form - instr->_linenum = _linenum; + instr->_linenum = linenum(); _globalNames.Insert(ident, instr); // Add name to the name table // Debugging Stuff if (_AD._adl_debug > 1) @@ -404,7 +403,7 @@ if( (ident = get_unique_ident(_globalNames,"operand")) == NULL ) return; oper = new OperandForm(ident); // Create new operand form - oper->_linenum = _linenum; + oper->_linenum = linenum(); _globalNames.Insert(ident, oper); // Add name to the name table // Debugging Stuff @@ -774,7 +773,7 @@ // Create the RegisterForm for the architecture description. RegisterForm *regBlock = new RegisterForm(); // Build new Source object - regBlock->_linenum = _linenum; + regBlock->_linenum = linenum(); _AD.addForm(regBlock); skipws(); // Skip leading whitespace @@ -847,7 +846,7 @@ } EncClass *encoding = _AD._encode->add_EncClass(ec_name); - encoding->_linenum = _linenum; + encoding->_linenum = linenum(); skipws(); // Skip leading whitespace // Check for optional parameter list @@ -905,7 +904,7 @@ // Prepend location descriptor, for debugging; cf. ADLParser::find_cpp_block if (_AD._adlocation_debug) { const char* file = _AD._ADL_file._name; - int line = _linenum; + int line = linenum(); char* location = (char *)malloc(strlen(file) + 100); sprintf(location, "#line %d \"%s\"\n", line, file); encoding->add_code(location); @@ -2776,7 +2775,7 @@ assert(_AD._encode->encClass(ec_name) == NULL, "shouldn't already exist"); EncClass *encoding = _AD._encode->add_EncClass(ec_name); - encoding->_linenum = _linenum; + encoding->_linenum = linenum(); // synthesize the arguments list for the enc_class from the // arguments to the instruct definition. @@ -2852,7 +2851,7 @@ skipws(); InsEncode *encrule = new InsEncode(); // Encode class for instruction - encrule->_linenum = _linenum; + encrule->_linenum = linenum(); char *ec_name = NULL; // String representation of encode rule // identifier is optional. while (_curchar != ')') { @@ -3203,6 +3202,12 @@ char *greater_equal; char *less_equal; char *greater; + const char *equal_format = "eq"; + const char *not_equal_format = "ne"; + const char *less_format = "lt"; + const char *greater_equal_format = "ge"; + const char *less_equal_format = "le"; + const char *greater_format = "gt"; if (_curchar != '%') { parse_err(SYNERR, "Missing '%{' for 'cond_interface' block.\n"); @@ -3222,22 +3227,22 @@ return NULL; } if ( strcmp(field,"equal") == 0 ) { - equal = interface_field_parse(); + equal = interface_field_parse(&equal_format); } else if ( strcmp(field,"not_equal") == 0 ) { - not_equal = interface_field_parse(); + not_equal = interface_field_parse(¬_equal_format); } else if ( strcmp(field,"less") == 0 ) { - less = interface_field_parse(); + less = interface_field_parse(&less_format); } else if ( strcmp(field,"greater_equal") == 0 ) { - greater_equal = interface_field_parse(); + greater_equal = interface_field_parse(&greater_equal_format); } else if ( strcmp(field,"less_equal") == 0 ) { - less_equal = interface_field_parse(); + less_equal = interface_field_parse(&less_equal_format); } else if ( strcmp(field,"greater") == 0 ) { - greater = interface_field_parse(); + greater = interface_field_parse(&greater_format); } else { parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%}' ending interface.\n"); @@ -3252,14 +3257,18 @@ next_char(); // Skip '}' // Construct desired object and return - Interface *inter = new CondInterface(equal, not_equal, less, greater_equal, - less_equal, greater); + Interface *inter = new CondInterface(equal, equal_format, + not_equal, not_equal_format, + less, less_format, + greater_equal, greater_equal_format, + less_equal, less_equal_format, + greater, greater_format); return inter; } //------------------------------interface_field_parse-------------------------- -char *ADLParser::interface_field_parse(void) { +char *ADLParser::interface_field_parse(const char ** format) { char *iface_field = NULL; // Get interface field @@ -3280,6 +3289,32 @@ return NULL; } skipws(); + if (format != NULL && _curchar == ',') { + next_char(); + skipws(); + if (_curchar != '"') { + parse_err(SYNERR, "Missing '\"' in field format .\n"); + return NULL; + } + next_char(); + char *start = _ptr; // Record start of the next string + while ((_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) { + if (_curchar == '\\') next_char(); // superquote + if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented! + next_char(); + } + if (_curchar != '"') { + parse_err(SYNERR, "Missing '\"' at end of field format .\n"); + return NULL; + } + // If a string was found, terminate it and record in FormatRule + if ( start != _ptr ) { + *_ptr = '\0'; // Terminate the string + *format = start; + } + next_char(); + skipws(); + } if (_curchar != ')') { parse_err(SYNERR, "Missing ')' after interface field.\n"); return NULL; @@ -3342,6 +3377,12 @@ next_char(); // Move past the '{' skipws(); + if (_curchar == '$') { + char* ident = get_rep_var_ident(); + if (strcmp(ident, "$$template") == 0) return template_parse(); + parse_err(SYNERR, "Unknown \"%s\" directive in format", ident); + return NULL; + } // Check for the opening '"' inside the format description if ( _curchar == '"' ) { next_char(); // Move past the initial '"' @@ -3433,6 +3474,131 @@ } +//------------------------------template_parse----------------------------------- +FormatRule* ADLParser::template_parse(void) { + char *desc = NULL; + FormatRule *format = (new FormatRule(desc)); + + skipws(); + while ( (_curchar != '%') && (*(_ptr+1) != '}') ) { + + // (1) + // Check if there is a string to pass through to output + char *start = _ptr; // Record start of the next string + while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) { + // If at the start of a comment, skip past it + if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) { + skipws_no_preproc(); + } else { + // ELSE advance to the next character, or start of the next line + next_char_or_line(); + } + } + // If a string was found, terminate it and record in EncClass + if ( start != _ptr ) { + *_ptr = '\0'; // Terminate the string + // Add flag to _strings list indicating we should check _rep_vars + format->_strings.addName(NameList::_signal2); + format->_strings.addName(start); + } + + // (2) + // If we are at a replacement variable, + // copy it and record in EncClass + if ( _curchar == '$' ) { + // Found replacement Variable + char *rep_var = get_rep_var_ident_dup(); + if (strcmp(rep_var, "$emit") == 0) { + // switch to normal format parsing + next_char(); + next_char(); + skipws(); + // Check for the opening '"' inside the format description + if ( _curchar == '"' ) { + next_char(); // Move past the initial '"' + if( _curchar == '"' ) { // Handle empty format string case + *_ptr = '\0'; // Terminate empty string + format->_strings.addName(_ptr); + } + + // Collect the parts of the format description + // (1) strings that are passed through to tty->print + // (2) replacement/substitution variable, preceeded by a '$' + // (3) multi-token ANSIY C style strings + while ( true ) { + if ( _curchar == '%' || _curchar == '\n' ) { + parse_err(SYNERR, "missing '\"' at end of format block"); + return NULL; + } + + // (1) + // Check if there is a string to pass through to output + char *start = _ptr; // Record start of the next string + while ((_curchar != '$') && (_curchar != '"') && (_curchar != '%') && (_curchar != '\n')) { + if (_curchar == '\\') next_char(); // superquote + if (_curchar == '\n') parse_err(SYNERR, "newline in string"); // unimplemented! + next_char(); + } + // If a string was found, terminate it and record in FormatRule + if ( start != _ptr ) { + *_ptr = '\0'; // Terminate the string + format->_strings.addName(start); + } + + // (2) + // If we are at a replacement variable, + // copy it and record in FormatRule + if ( _curchar == '$' ) { + next_char(); // Move past the '$' + char* rep_var = get_ident(); // Nil terminate the variable name + rep_var = strdup(rep_var);// Copy the string + *_ptr = _curchar; // and replace Nil with original character + format->_rep_vars.addName(rep_var); + // Add flag to _strings list indicating we should check _rep_vars + format->_strings.addName(NameList::_signal); + } + + // (3) + // Allow very long strings to be broken up, + // using the ANSI C syntax "foo\n" "bar" + if ( _curchar == '"') { + next_char(); // Move past the '"' + skipws(); // Skip white space before next string token + if ( _curchar != '"') { + break; + } else { + // Found one. Skip both " and the whitespace in between. + next_char(); + } + } + } // end while part of format description + } + } else { + // Add flag to _strings list indicating we should check _rep_vars + format->_rep_vars.addName(rep_var); + // Add flag to _strings list indicating we should check _rep_vars + format->_strings.addName(NameList::_signal3); + } + } // end while part of format description + } + + skipws(); + // Past format description, at '%' + if ( _curchar != '%' || *(_ptr+1) != '}' ) { + parse_err(SYNERR, "missing '%}' at end of format block"); + return NULL; + } + next_char(); // Move past the '%' + next_char(); // Move past the '}' + + // Debug Stuff + if (_AD._adl_debug > 1) fprintf(stderr,"Format Rule: %s\n", desc); + + skipws(); + return format; +} + + //------------------------------effect_parse----------------------------------- void ADLParser::effect_parse(InstructForm *instr) { char* desc = NULL; @@ -3777,7 +3943,7 @@ skipws_no_preproc(); // Skip leading whitespace cppBlock = _ptr; // Point to start of expression const char* file = _AD._ADL_file._name; - int line = _linenum; + int line = linenum(); next = _ptr + 1; while(((_curchar != '%') || (*next != '}')) && (_curchar != '\0')) { next_char_or_line(); @@ -4297,11 +4463,11 @@ va_start(args, fmt); if (flag == 1) - _AD._syntax_errs += _AD.emit_msg(0, flag, _linenum, fmt, args); + _AD._syntax_errs += _AD.emit_msg(0, flag, linenum(), fmt, args); else if (flag == 2) - _AD._semantic_errs += _AD.emit_msg(0, flag, _linenum, fmt, args); + _AD._semantic_errs += _AD.emit_msg(0, flag, linenum(), fmt, args); else - _AD._warnings += _AD.emit_msg(0, flag, _linenum, fmt, args); + _AD._warnings += _AD.emit_msg(0, flag, linenum(), fmt, args); int error_char = _curchar; char* error_ptr = _ptr+1; @@ -4515,7 +4681,7 @@ //---------------------------next_line----------------------------------------- void ADLParser::next_line() { - _curline = _buf.get_line(); _linenum++; + _curline = _buf.get_line(); } //-------------------------is_literal_constant--------------------------------- diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/adlc/adlparse.hpp --- a/src/share/vm/adlc/adlparse.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/adlc/adlparse.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -70,7 +70,6 @@ protected: char *_curline; // Start of current line char *_ptr; // Pointer into current location in File Buffer - int _linenum; // Count of line numbers seen so far char _curchar; // Current character from buffer FormDict &_globalNames; // Global names @@ -160,9 +159,10 @@ Interface *interface_parse(); // Parse operand interface rule Interface *mem_interface_parse(); // Parse memory interface rule Interface *cond_interface_parse(); // Parse conditional interface rule - char *interface_field_parse();// Parse field contents + char *interface_field_parse(const char** format = NULL);// Parse field contents FormatRule *format_parse(void); // Parse format rule + FormatRule *template_parse(void); // Parse format rule void effect_parse(InstructForm *instr); // Parse effect rule ExpandRule *expand_parse(InstructForm *instr); // Parse expand rule RewriteRule *rewrite_parse(void); // Parse rewrite rule @@ -263,7 +263,7 @@ void parse(void); // Do the parsing & build forms lists - int getlines( ) { return _linenum; } + int linenum() { return _buf.linenum(); } static bool is_literal_constant(const char *hex_string); static bool is_hex_digit(char digit); diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/adlc/archDesc.cpp --- a/src/share/vm/adlc/archDesc.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/adlc/archDesc.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -212,9 +212,9 @@ // Initialize I/O Files _ADL_file._name = NULL; _ADL_file._fp = NULL; // Machine dependent output files - _DFA_file._name = "dfa_i486.cpp"; _DFA_file._fp = NULL; - _HPP_file._name = "ad_i486.hpp"; _HPP_file._fp = NULL; - _CPP_file._name = "ad_i486.cpp"; _CPP_file._fp = NULL; + _DFA_file._name = NULL; _DFA_file._fp = NULL; + _HPP_file._name = NULL; _HPP_file._fp = NULL; + _CPP_file._name = NULL; _CPP_file._fp = NULL; _bug_file._name = "bugs.out"; _bug_file._fp = NULL; // Initialize Register & Pipeline Form Pointers diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/adlc/filebuff.cpp --- a/src/share/vm/adlc/filebuff.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/adlc/filebuff.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -41,6 +41,7 @@ exit(1); // Exit on seek error } _filepos = ftell(_fp->_fp); // Reset current file position + _linenum = 0; _bigbuf = new char[_bufferSize]; // Create buffer to hold text for parser if( !_bigbuf ) { @@ -76,6 +77,7 @@ // Check for end of file & return NULL if (_bufeol >= _bufmax) return NULL; + _linenum++; retval = ++_bufeol; // return character following end of previous line if (*retval == '\0') return NULL; // Check for EOF sentinal // Search for newline character which must end each line diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/adlc/filebuff.hpp --- a/src/share/vm/adlc/filebuff.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/adlc/filebuff.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -51,6 +51,7 @@ int _err; // Error flag for file seek/read operations long _filepos; // Current offset from start of file + int _linenum; ArchDesc& _AD; // Reference to Architecture Description @@ -66,6 +67,7 @@ // This returns a pointer to the start of the current line in the buffer, // and increments bufeol and filepos to point at the end of that line. char *get_line(void); + int linenum() const { return _linenum; } // This converts a pointer into the buffer to a file offset. It only works // when the pointer is valid (i.e. just obtained from getline()). diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/adlc/forms.cpp --- a/src/share/vm/adlc/forms.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/adlc/forms.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -35,6 +35,8 @@ //------------------------------NameList--------------------------------------- // reserved user-defined string const char *NameList::_signal = "$$SIGNAL$$"; +const char *NameList::_signal2 = "$$SIGNAL2$$"; +const char *NameList::_signal3 = "$$SIGNAL3$$"; // Constructor and Destructor NameList::NameList() : _cur(0), _max(4), _iter(0), _justReset(true) { diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/adlc/forms.hpp --- a/src/share/vm/adlc/forms.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/adlc/forms.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -329,6 +329,8 @@ public: static const char *_signal; // reserved user-defined string + static const char *_signal2; // reserved user-defined string + static const char *_signal3; // reserved user-defined string enum { Not_in_list = -1 }; void addName(const char *name); diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/adlc/formssel.cpp --- a/src/share/vm/adlc/formssel.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/adlc/formssel.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -1574,10 +1574,10 @@ return Opcode::NOT_AN_OPCODE; } -void Opcode::print_opcode(FILE *fp, Opcode::opcode_type desired_opcode) { +bool Opcode::print_opcode(FILE *fp, Opcode::opcode_type desired_opcode) { // Default values previously provided by MachNode::primary()... - const char *description = "default_opcode()"; - const char *value = "-1"; + const char *description = NULL; + const char *value = NULL; // Check if user provided any opcode definitions if( this != NULL ) { // Update 'value' if user provided a definition in the instruction @@ -1599,7 +1599,10 @@ break; } } - fprintf(fp, "(%s /*%s*/)", value, description); + if (value != NULL) { + fprintf(fp, "(%s /*%s*/)", value, description); + } + return value != NULL; } void Opcode::dump() { @@ -2610,14 +2613,19 @@ } //------------------------------CondInterface---------------------------------- -CondInterface::CondInterface(char *equal, char *not_equal, - char *less, char *greater_equal, - char *less_equal, char *greater) +CondInterface::CondInterface(const char* equal, const char* equal_format, + const char* not_equal, const char* not_equal_format, + const char* less, const char* less_format, + const char* greater_equal, const char* greater_equal_format, + const char* less_equal, const char* less_equal_format, + const char* greater, const char* greater_format) : Interface("COND_INTER"), - _equal(equal), _not_equal(not_equal), - _less(less), _greater_equal(greater_equal), - _less_equal(less_equal), _greater(greater) { - // + _equal(equal), _equal_format(equal_format), + _not_equal(not_equal), _not_equal_format(not_equal_format), + _less(less), _less_format(less_format), + _greater_equal(greater_equal), _greater_equal_format(greater_equal_format), + _less_equal(less_equal), _less_equal_format(less_equal_format), + _greater(greater), _greater_format(greater_format) { } CondInterface::~CondInterface() { // not owner of any character arrays @@ -3316,7 +3324,7 @@ "Load8B" ,"Load4B" ,"Load8C" ,"Load4C" ,"Load2C" ,"Load8S", "Load4S","Load2S", "LoadRange", "LoadKlass", "LoadNKlass", "LoadL_unaligned", "LoadD_unaligned", "LoadPLocked", "LoadLLocked", - "StorePConditional", "StoreLConditional", + "StorePConditional", "StoreIConditional", "StoreLConditional", "CompareAndSwapI", "CompareAndSwapL", "CompareAndSwapP", "CompareAndSwapN", "StoreCM", "ClearArray" diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/adlc/formssel.hpp --- a/src/share/vm/adlc/formssel.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/adlc/formssel.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -397,7 +397,7 @@ void output(FILE *fp); // --------------------------- FILE *output_routines - void print_opcode(FILE *fp, Opcode::opcode_type desired_opcode); + bool print_opcode(FILE *fp, Opcode::opcode_type desired_opcode); }; //------------------------------InsEncode-------------------------------------- @@ -779,10 +779,20 @@ const char *_greater_equal; const char *_less_equal; const char *_greater; + const char *_equal_format; + const char *_not_equal_format; + const char *_less_format; + const char *_greater_equal_format; + const char *_less_equal_format; + const char *_greater_format; // Public Methods - CondInterface(char *equal, char *not_equal, char *less, char *greater_equal, - char *less_equal, char *greater); + CondInterface(const char* equal, const char* equal_format, + const char* not_equal, const char* not_equal_format, + const char* less, const char* less_format, + const char* greater_equal, const char* greater_equal_format, + const char* less_equal, const char* less_equal_format, + const char* greater, const char* greater_format); ~CondInterface(); void dump(); diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/adlc/output_c.cpp --- a/src/share/vm/adlc/output_c.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/adlc/output_c.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -1619,6 +1619,7 @@ } // Iterate over the new instruction's operands + int prev_pos = -1; for( expand_instr->reset(); (opid = expand_instr->iter()) != NULL; ) { // Use 'parameter' at current position in list of new instruction's formals // instead of 'opid' when looking up info internal to new_inst @@ -1642,6 +1643,18 @@ // ins = (InstructForm *) _globalNames[new_id]; exp_pos = node->operand_position_format(opid); assert(exp_pos != -1, "Bad expand rule"); + if (prev_pos > exp_pos && expand_instruction->_matrule != NULL) { + // For the add_req calls below to work correctly they need + // to added in the same order that a match would add them. + // This means that they would need to be in the order of + // the components list instead of the formal parameters. + // This is a sort of hidden invariant that previously + // wasn't checked and could lead to incorrectly + // constructed nodes. + syntax_err(node->_linenum, "For expand in %s to work, parameter declaration order in %s must follow matchrule\n", + node->_ident, new_inst->_ident); + } + prev_pos = exp_pos; new_pos = new_inst->operand_position(parameter,Component::USE); if (new_pos != -1) { @@ -2306,7 +2319,12 @@ _processing_noninput = false; // A replacement variable, originally '$' if ( Opcode::as_opcode_type(rep_var) != Opcode::NOT_AN_OPCODE ) { - _inst._opcode->print_opcode(_fp, Opcode::as_opcode_type(rep_var) ); + if (!_inst._opcode->print_opcode(_fp, Opcode::as_opcode_type(rep_var) )) { + // Missing opcode + _AD.syntax_err( _inst._linenum, + "Missing $%s opcode definition in %s, used by encoding %s\n", + rep_var, _inst._ident, _encoding._name); + } } else { // Lookup its position in parameter list @@ -2348,7 +2366,13 @@ else if( Opcode::as_opcode_type(inst_rep_var) != Opcode::NOT_AN_OPCODE ) { // else check if "primary", "secondary", "tertiary" assert( _constant_status == LITERAL_ACCESSED, "Must be processing a literal constant parameter"); - _inst._opcode->print_opcode(_fp, Opcode::as_opcode_type(inst_rep_var) ); + if (!_inst._opcode->print_opcode(_fp, Opcode::as_opcode_type(inst_rep_var) )) { + // Missing opcode + _AD.syntax_err( _inst._linenum, + "Missing $%s opcode definition in %s\n", + rep_var, _inst._ident); + + } _constant_status = LITERAL_OUTPUT; } else if((_AD.get_registers() != NULL ) && (_AD.get_registers()->getRegDef(inst_rep_var) != NULL)) { diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/adlc/output_h.cpp --- a/src/share/vm/adlc/output_h.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/adlc/output_h.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -355,17 +355,19 @@ // --------------------------------------------------------------------------- // Generate the format rule for condition codes -static void defineCCodeDump(FILE *fp, int i) { - fprintf(fp, " if( _c%d == BoolTest::eq ) st->print(\"eq\");\n",i); - fprintf(fp, " else if( _c%d == BoolTest::ne ) st->print(\"ne\");\n",i); - fprintf(fp, " else if( _c%d == BoolTest::le ) st->print(\"le\");\n",i); - fprintf(fp, " else if( _c%d == BoolTest::ge ) st->print(\"ge\");\n",i); - fprintf(fp, " else if( _c%d == BoolTest::lt ) st->print(\"lt\");\n",i); - fprintf(fp, " else if( _c%d == BoolTest::gt ) st->print(\"gt\");\n",i); +static void defineCCodeDump(OperandForm* oper, FILE *fp, int i) { + assert(oper != NULL, "what"); + CondInterface* cond = oper->_interface->is_CondInterface(); + fprintf(fp, " if( _c%d == BoolTest::eq ) st->print(\"%s\");\n",i,cond->_equal_format); + fprintf(fp, " else if( _c%d == BoolTest::ne ) st->print(\"%s\");\n",i,cond->_not_equal_format); + fprintf(fp, " else if( _c%d == BoolTest::le ) st->print(\"%s\");\n",i,cond->_less_equal_format); + fprintf(fp, " else if( _c%d == BoolTest::ge ) st->print(\"%s\");\n",i,cond->_greater_equal_format); + fprintf(fp, " else if( _c%d == BoolTest::lt ) st->print(\"%s\");\n",i,cond->_less_format); + fprintf(fp, " else if( _c%d == BoolTest::gt ) st->print(\"%s\");\n",i,cond->_greater_format); } // Output code that dumps constant values, increment "i" if type is constant -static uint dump_spec_constant(FILE *fp, const char *ideal_type, uint i) { +static uint dump_spec_constant(FILE *fp, const char *ideal_type, uint i, OperandForm* oper) { if (!strcmp(ideal_type, "ConI")) { fprintf(fp," st->print(\"#%%d\", _c%d);\n", i); ++i; @@ -375,7 +377,7 @@ ++i; } else if (!strcmp(ideal_type, "ConN")) { - fprintf(fp," _c%d->dump();\n", i); + fprintf(fp," _c%d->dump_on(st);\n", i); ++i; } else if (!strcmp(ideal_type, "ConL")) { @@ -391,7 +393,7 @@ ++i; } else if (!strcmp(ideal_type, "Bool")) { - defineCCodeDump(fp,i); + defineCCodeDump(oper, fp,i); ++i; } @@ -476,7 +478,7 @@ } // ALWAYS! Provide a special case output for condition codes. if( oper.is_ideal_bool() ) { - defineCCodeDump(fp,0); + defineCCodeDump(&oper, fp,0); } fprintf(fp,"}\n"); @@ -549,7 +551,7 @@ } // ALWAYS! Provide a special case output for condition codes. if( oper.is_ideal_bool() ) { - defineCCodeDump(fp,0); + defineCCodeDump(&oper, fp,0); } fprintf(fp, "}\n"); fprintf(fp, "#endif\n"); @@ -583,10 +585,53 @@ while( (string = inst._format->_strings.iter()) != NULL ) { fprintf(fp," "); // Check if this is a standard string or a replacement variable - if( string != NameList::_signal ) // Normal string. Pass through. + if( string == NameList::_signal ) { // Replacement variable + const char* rep_var = inst._format->_rep_vars.iter(); + inst.rep_var_format( fp, rep_var); + } else if( string == NameList::_signal3 ) { // Replacement variable in raw text + const char* rep_var = inst._format->_rep_vars.iter(); + const Form *form = inst._localNames[rep_var]; + if (form == NULL) { + fprintf(stderr, "unknown replacement variable in format statement: '%s'\n", rep_var); + assert(false, "ShouldNotReachHere()"); + } + OpClassForm *opc = form->is_opclass(); + assert( opc, "replacement variable was not found in local names"); + // Lookup the index position of the replacement variable + int idx = inst.operand_position_format(rep_var); + if ( idx == -1 ) { + assert( strcmp(opc->_ident,"label")==0, "Unimplemented"); + assert( false, "ShouldNotReachHere()"); + } + + if (inst.is_noninput_operand(idx)) { + assert( false, "ShouldNotReachHere()"); + } else { + // Output the format call for this operand + fprintf(fp,"opnd_array(%d)",idx); + } + rep_var = inst._format->_rep_vars.iter(); + inst._format->_strings.iter(); + if ( strcmp(rep_var,"$constant") == 0 && opc->is_operand()) { + Form::DataType constant_type = form->is_operand()->is_base_constant(globals); + if ( constant_type == Form::idealD ) { + fprintf(fp,"->constantD()"); + } else if ( constant_type == Form::idealF ) { + fprintf(fp,"->constantF()"); + } else if ( constant_type == Form::idealL ) { + fprintf(fp,"->constantL()"); + } else { + fprintf(fp,"->constant()"); + } + } else if ( strcmp(rep_var,"$cmpcode") == 0) { + fprintf(fp,"->ccode()"); + } else { + assert( false, "ShouldNotReachHere()"); + } + } else if( string == NameList::_signal2 ) // Raw program text + fputs(inst._format->_strings.iter(), fp); + else fprintf(fp,"st->print(\"%s\");\n", string); - else // Replacement variable - inst.rep_var_format( fp, inst._format->_rep_vars.iter() ); } // Done with all format strings } // Done generating the user-defined portion of the format @@ -1404,7 +1449,7 @@ oper->_components.reset(); if ((comp = oper->_components.iter()) == NULL) { assert(num_consts == 1, "Bad component list detected.\n"); - i = dump_spec_constant( fp, type, i ); + i = dump_spec_constant( fp, type, i, oper ); // Check that type actually matched assert( i != 0, "Non-constant operand lacks component list."); } // end if NULL @@ -1414,7 +1459,7 @@ oper->_components.reset(); while((comp = oper->_components.iter()) != NULL) { type = comp->base_type(_globalNames); - i = dump_spec_constant( fp, type, i ); + i = dump_spec_constant( fp, type, i, NULL ); } } // finish line (3) diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/c1/c1_IR.cpp --- a/src/share/vm/c1/c1_IR.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/c1/c1_IR.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -574,12 +574,23 @@ TRACE_LINEAR_SCAN(3, tty->print_cr("backward branch")); assert(is_visited(cur), "block must be visisted when block is active"); assert(parent != NULL, "must have parent"); - assert(parent->number_of_sux() == 1, "loop end blocks must have one successor (critical edges are split)"); cur->set(BlockBegin::linear_scan_loop_header_flag); cur->set(BlockBegin::backward_branch_target_flag); parent->set(BlockBegin::linear_scan_loop_end_flag); + + // When a loop header is also the start of an exception handler, then the backward branch is + // an exception edge. Because such edges are usually critical edges which cannot be split, the + // loop must be excluded here from processing. + if (cur->is_set(BlockBegin::exception_entry_flag)) { + // Make sure that dominators are correct in this weird situation + _iterative_dominators = true; + return; + } + assert(parent->number_of_sux() == 1 && parent->sux_at(0) == cur, + "loop end blocks must have one successor (critical edges are split)"); + _loop_end_blocks.append(parent); return; } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/ci/ciEnv.cpp --- a/src/share/vm/ci/ciEnv.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/ci/ciEnv.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -484,11 +484,16 @@ } else if (tag.is_double()) { return ciConstant((jdouble)cpool->double_at(index)); } else if (tag.is_string() || tag.is_unresolved_string()) { - oop string = cpool->string_at(index, THREAD); - if (HAS_PENDING_EXCEPTION) { - CLEAR_PENDING_EXCEPTION; - record_out_of_memory_failure(); - return ciConstant(); + oop string = NULL; + if (cpool->is_pseudo_string_at(index)) { + string = cpool->pseudo_string_at(index); + } else { + string = cpool->string_at(index, THREAD); + if (HAS_PENDING_EXCEPTION) { + CLEAR_PENDING_EXCEPTION; + record_out_of_memory_failure(); + return ciConstant(); + } } ciObject* constant = get_object(string); assert (constant->is_instance(), "must be an instance, or not? "); diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/classfile/classFileParser.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -168,11 +168,23 @@ // Got utf8 string, guarantee utf8_length+1 bytes, set stream position forward. cfs->guarantee_more(utf8_length+1, CHECK); // utf8 string, tag/access_flags cfs->skip_u1_fast(utf8_length); + // Before storing the symbol, make sure it's legal if (_need_verify) { verify_legal_utf8((unsigned char*)utf8_buffer, utf8_length, CHECK); } + if (AnonymousClasses && has_cp_patch_at(index)) { + Handle patch = clear_cp_patch_at(index); + guarantee_property(java_lang_String::is_instance(patch()), + "Illegal utf8 patch at %d in class file %s", + index, CHECK); + char* str = java_lang_String::as_utf8_string(patch()); + // (could use java_lang_String::as_symbol instead, but might as well batch them) + utf8_buffer = (u1*) str; + utf8_length = (int) strlen(str); + } + unsigned int hash; symbolOop result = SymbolTable::lookup_only((char*)utf8_buffer, utf8_length, hash); if (result == NULL) { @@ -245,7 +257,7 @@ int klass_ref_index = cp->klass_ref_index_at(index); int name_and_type_ref_index = cp->name_and_type_ref_index_at(index); check_property(valid_cp_range(klass_ref_index, length) && - cp->tag_at(klass_ref_index).is_klass_reference(), + is_klass_reference(cp, klass_ref_index), "Invalid constant pool index %u in class file %s", klass_ref_index, CHECK_(nullHandle)); @@ -326,16 +338,46 @@ } // end of switch } // end of for + if (_cp_patches != NULL) { + // need to treat this_class specially... + assert(AnonymousClasses, ""); + int this_class_index; + { + cfs->guarantee_more(8, CHECK_(nullHandle)); // flags, this_class, super_class, infs_len + u1* mark = cfs->current(); + u2 flags = cfs->get_u2_fast(); + this_class_index = cfs->get_u2_fast(); + cfs->set_current(mark); // revert to mark + } + + for (index = 1; index < length; index++) { // Index 0 is unused + if (has_cp_patch_at(index)) { + guarantee_property(index != this_class_index, + "Illegal constant pool patch to self at %d in class file %s", + index, CHECK_(nullHandle)); + patch_constant_pool(cp, index, cp_patch_at(index), CHECK_(nullHandle)); + } + } + // Ensure that all the patches have been used. + for (index = 0; index < _cp_patches->length(); index++) { + guarantee_property(!has_cp_patch_at(index), + "Unused constant pool patch at %d in class file %s", + index, CHECK_(nullHandle)); + } + } + if (!_need_verify) { return cp; } // second verification pass - checks the strings are of the right format. + // but not yet to the other entries for (index = 1; index < length; index++) { jbyte tag = cp->tag_at(index).value(); switch (tag) { case JVM_CONSTANT_UnresolvedClass: { symbolHandle class_name(THREAD, cp->unresolved_klass_at(index)); + // check the name, even if _cp_patches will overwrite it verify_legal_class_name(class_name, CHECK_(nullHandle)); break; } @@ -378,6 +420,73 @@ } +void ClassFileParser::patch_constant_pool(constantPoolHandle cp, int index, Handle patch, TRAPS) { + assert(AnonymousClasses, ""); + BasicType patch_type = T_VOID; + switch (cp->tag_at(index).value()) { + + case JVM_CONSTANT_UnresolvedClass : + // Patching a class means pre-resolving it. + // The name in the constant pool is ignored. + if (patch->klass() == SystemDictionary::class_klass()) { // %%% java_lang_Class::is_instance + guarantee_property(!java_lang_Class::is_primitive(patch()), + "Illegal class patch at %d in class file %s", + index, CHECK); + cp->klass_at_put(index, java_lang_Class::as_klassOop(patch())); + } else { + guarantee_property(java_lang_String::is_instance(patch()), + "Illegal class patch at %d in class file %s", + index, CHECK); + symbolHandle name = java_lang_String::as_symbol(patch(), CHECK); + cp->unresolved_klass_at_put(index, name()); + } + break; + + case JVM_CONSTANT_UnresolvedString : + // Patching a string means pre-resolving it. + // The spelling in the constant pool is ignored. + // The constant reference may be any object whatever. + // If it is not a real interned string, the constant is referred + // to as a "pseudo-string", and must be presented to the CP + // explicitly, because it may require scavenging. + cp->pseudo_string_at_put(index, patch()); + break; + + case JVM_CONSTANT_Integer : patch_type = T_INT; goto patch_prim; + case JVM_CONSTANT_Float : patch_type = T_FLOAT; goto patch_prim; + case JVM_CONSTANT_Long : patch_type = T_LONG; goto patch_prim; + case JVM_CONSTANT_Double : patch_type = T_DOUBLE; goto patch_prim; + patch_prim: + { + jvalue value; + BasicType value_type = java_lang_boxing_object::get_value(patch(), &value); + guarantee_property(value_type == patch_type, + "Illegal primitive patch at %d in class file %s", + index, CHECK); + switch (value_type) { + case T_INT: cp->int_at_put(index, value.i); break; + case T_FLOAT: cp->float_at_put(index, value.f); break; + case T_LONG: cp->long_at_put(index, value.j); break; + case T_DOUBLE: cp->double_at_put(index, value.d); break; + default: assert(false, ""); + } + } + break; + + default: + // %%% TODO: put method handles into CONSTANT_InterfaceMethodref, etc. + guarantee_property(!has_cp_patch_at(index), + "Illegal unexpected patch at %d in class file %s", + index, CHECK); + return; + } + + // On fall-through, mark the patch as used. + clear_cp_patch_at(index); +} + + + class NameSigHash: public ResourceObj { public: symbolOop _name; // name @@ -448,25 +557,32 @@ int index; for (index = 0; index < length; index++) { u2 interface_index = cfs->get_u2(CHECK_(nullHandle)); + KlassHandle interf; check_property( valid_cp_range(interface_index, cp->length()) && - cp->tag_at(interface_index).is_unresolved_klass(), + is_klass_reference(cp, interface_index), "Interface name has bad constant pool index %u in class file %s", interface_index, CHECK_(nullHandle)); - symbolHandle unresolved_klass (THREAD, cp->klass_name_at(interface_index)); - - // Don't need to check legal name because it's checked when parsing constant pool. - // But need to make sure it's not an array type. - guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY, - "Bad interface name in class file %s", CHECK_(nullHandle)); - - vmtimer->suspend(); // do not count recursive loading twice - // Call resolve_super so classcircularity is checked - klassOop k = SystemDictionary::resolve_super_or_fail(class_name, - unresolved_klass, class_loader, protection_domain, - false, CHECK_(nullHandle)); - KlassHandle interf (THREAD, k); - vmtimer->resume(); + if (cp->tag_at(interface_index).is_klass()) { + interf = KlassHandle(THREAD, cp->resolved_klass_at(interface_index)); + } else { + symbolHandle unresolved_klass (THREAD, cp->klass_name_at(interface_index)); + + // Don't need to check legal name because it's checked when parsing constant pool. + // But need to make sure it's not an array type. + guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY, + "Bad interface name in class file %s", CHECK_(nullHandle)); + + vmtimer->suspend(); // do not count recursive loading twice + // Call resolve_super so classcircularity is checked + klassOop k = SystemDictionary::resolve_super_or_fail(class_name, + unresolved_klass, class_loader, protection_domain, + false, CHECK_(nullHandle)); + interf = KlassHandle(THREAD, k); + vmtimer->resume(); + + cp->klass_at_put(interface_index, interf()); // eagerly resolve + } if (!Klass::cast(interf())->is_interface()) { THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", nullHandle); @@ -877,8 +993,7 @@ "Illegal exception table handler in class file %s", CHECK_(nullHandle)); if (catch_type_index != 0) { guarantee_property(valid_cp_range(catch_type_index, cp->length()) && - (cp->tag_at(catch_type_index).is_klass() || - cp->tag_at(catch_type_index).is_unresolved_klass()), + is_klass_reference(cp, catch_type_index), "Catch type in exception table has bad constant type in class file %s", CHECK_(nullHandle)); } } @@ -1117,7 +1232,7 @@ } else if (tag == ITEM_Object) { u2 class_index = u2_array[i2++] = cfs->get_u2(CHECK); guarantee_property(valid_cp_range(class_index, cp->length()) && - cp->tag_at(class_index).is_unresolved_klass(), + is_klass_reference(cp, class_index), "Bad class index %u in StackMap in class file %s", class_index, CHECK); } else if (tag == ITEM_Uninitialized) { @@ -1183,7 +1298,7 @@ checked_exception = cfs->get_u2_fast(); check_property( valid_cp_range(checked_exception, cp->length()) && - cp->tag_at(checked_exception).is_klass_reference(), + is_klass_reference(cp, checked_exception), "Exception name has bad type at constant pool %u in class file %s", checked_exception, CHECK_NULL); } @@ -1918,7 +2033,7 @@ check_property( inner_class_info_index == 0 || (valid_cp_range(inner_class_info_index, cp_size) && - cp->tag_at(inner_class_info_index).is_klass_reference()), + is_klass_reference(cp, inner_class_info_index)), "inner_class_info_index %u has bad constant type in class file %s", inner_class_info_index, CHECK_0); // Outer class index @@ -1926,7 +2041,7 @@ check_property( outer_class_info_index == 0 || (valid_cp_range(outer_class_info_index, cp_size) && - cp->tag_at(outer_class_info_index).is_klass_reference()), + is_klass_reference(cp, outer_class_info_index)), "outer_class_info_index %u has bad constant type in class file %s", outer_class_info_index, CHECK_0); // Inner class name @@ -2088,7 +2203,7 @@ } // Validate the constant pool indices and types if (!cp->is_within_bounds(class_index) || - !cp->tag_at(class_index).is_klass_reference()) { + !is_klass_reference(cp, class_index)) { classfile_parse_error("Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK); } if (method_index != 0 && @@ -2349,6 +2464,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name, Handle class_loader, Handle protection_domain, + GrowableArray* cp_patches, symbolHandle& parsed_name, TRAPS) { // So that JVMTI can cache class file in the state before retransformable agents @@ -2380,6 +2496,7 @@ } } + _cp_patches = cp_patches; instanceKlassHandle nullHandle; @@ -2510,14 +2627,22 @@ CHECK_(nullHandle)); } else { check_property(valid_cp_range(super_class_index, cp_size) && - cp->tag_at(super_class_index).is_unresolved_klass(), + is_klass_reference(cp, super_class_index), "Invalid superclass index %u in class file %s", super_class_index, CHECK_(nullHandle)); // The class name should be legal because it is checked when parsing constant pool. // However, make sure it is not an array type. + bool is_array = false; + if (cp->tag_at(super_class_index).is_klass()) { + super_klass = instanceKlassHandle(THREAD, cp->resolved_klass_at(super_class_index)); + if (_need_verify) + is_array = super_klass->oop_is_array(); + } else if (_need_verify) { + is_array = (cp->unresolved_klass_at(super_class_index)->byte_at(0) == JVM_SIGNATURE_ARRAY); + } if (_need_verify) { - guarantee_property(cp->unresolved_klass_at(super_class_index)->byte_at(0) != JVM_SIGNATURE_ARRAY, + guarantee_property(!is_array, "Bad superclass name in class file %s", CHECK_(nullHandle)); } } @@ -2557,7 +2682,7 @@ objArrayHandle methods_default_annotations(THREAD, methods_default_annotations_oop); // We check super class after class file is parsed and format is checked - if (super_class_index > 0) { + if (super_class_index > 0 && super_klass.is_null()) { symbolHandle sk (THREAD, cp->klass_name_at(super_class_index)); if (access_flags.is_interface()) { // Before attempting to resolve the superclass, check for class format @@ -2574,6 +2699,9 @@ CHECK_(nullHandle)); KlassHandle kh (THREAD, k); super_klass = instanceKlassHandle(THREAD, kh()); + cp->klass_at_put(super_class_index, super_klass()); // eagerly resolve + } + if (super_klass.not_null()) { if (super_klass->is_interface()) { ResourceMark rm(THREAD); Exceptions::fthrow( @@ -3000,6 +3128,7 @@ this_klass->set_method_ordering(method_ordering()); this_klass->set_initial_method_idnum(methods->length()); this_klass->set_name(cp->klass_name_at(this_class_index)); + cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve this_klass->set_protection_domain(protection_domain()); this_klass->set_fields_annotations(fields_annotations()); this_klass->set_methods_annotations(methods_annotations()); diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/classfile/classFileParser.hpp --- a/src/share/vm/classfile/classFileParser.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/classfile/classFileParser.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -33,6 +33,7 @@ u2 _major_version; u2 _minor_version; symbolHandle _class_name; + GrowableArray* _cp_patches; // overrides for CP entries bool _has_finalizer; bool _has_empty_finalizer; @@ -203,6 +204,35 @@ char* skip_over_field_name(char* name, bool slash_ok, unsigned int length); char* skip_over_field_signature(char* signature, bool void_ok, unsigned int length, TRAPS); + bool has_cp_patch_at(int index) { + assert(AnonymousClasses, ""); + assert(index >= 0, "oob"); + return (_cp_patches != NULL + && index < _cp_patches->length() + && _cp_patches->adr_at(index)->not_null()); + } + Handle cp_patch_at(int index) { + assert(has_cp_patch_at(index), "oob"); + return _cp_patches->at(index); + } + Handle clear_cp_patch_at(int index) { + Handle patch = cp_patch_at(index); + _cp_patches->at_put(index, Handle()); + assert(!has_cp_patch_at(index), ""); + return patch; + } + void patch_constant_pool(constantPoolHandle cp, int index, Handle patch, TRAPS); + + // Wrapper for constantTag.is_klass_[or_]reference. + // In older versions of the VM, klassOops cannot sneak into early phases of + // constant pool construction, but in later versions they can. + // %%% Let's phase out the old is_klass_reference. + bool is_klass_reference(constantPoolHandle cp, int index) { + return ((LinkWellKnownClasses || AnonymousClasses) + ? cp->tag_at(index).is_klass_or_reference() + : cp->tag_at(index).is_klass_reference()); + } + public: // Constructor ClassFileParser(ClassFileStream* st) { set_stream(st); } @@ -218,6 +248,14 @@ Handle class_loader, Handle protection_domain, symbolHandle& parsed_name, + TRAPS) { + return parseClassFile(name, class_loader, protection_domain, NULL, parsed_name, THREAD); + } + instanceKlassHandle parseClassFile(symbolHandle name, + Handle class_loader, + Handle protection_domain, + GrowableArray* cp_patches, + symbolHandle& parsed_name, TRAPS); // Verifier checks diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/classfile/systemDictionary.cpp --- a/src/share/vm/classfile/systemDictionary.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/classfile/systemDictionary.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -937,6 +937,8 @@ Handle class_loader, Handle protection_domain, ClassFileStream* st, + KlassHandle host_klass, + GrowableArray* cp_patches, TRAPS) { symbolHandle parsed_name; @@ -953,10 +955,10 @@ instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name, class_loader, protection_domain, + cp_patches, parsed_name, THREAD); - // We don't redefine the class, so we just need to clean up whether there // was an error or not (don't want to modify any system dictionary // data structures). @@ -973,6 +975,30 @@ } } + if (host_klass.not_null() && k.not_null()) { + assert(AnonymousClasses, ""); + // If it's anonymous, initialize it now, since nobody else will. + k->set_host_klass(host_klass()); + + { + MutexLocker mu_r(Compile_lock, THREAD); + + // Add to class hierarchy, initialize vtables, and do possible + // deoptimizations. + add_to_hierarchy(k, CHECK_NULL); // No exception, but can block + + // But, do not add to system dictionary. + } + + k->eager_initialize(THREAD); + + // notify jvmti + if (JvmtiExport::should_post_class_load()) { + assert(THREAD->is_Java_thread(), "thread->is_Java_thread()"); + JvmtiExport::post_class_load((JavaThread *) THREAD, k()); + } + } + return k(); } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/classfile/systemDictionary.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -228,6 +228,16 @@ Handle class_loader, Handle protection_domain, ClassFileStream* st, + TRAPS) { + KlassHandle nullHandle; + return parse_stream(class_name, class_loader, protection_domain, st, nullHandle, NULL, THREAD); + } + static klassOop parse_stream(symbolHandle class_name, + Handle class_loader, + Handle protection_domain, + ClassFileStream* st, + KlassHandle host_klass, + GrowableArray* cp_patches, TRAPS); // Resolve from stream (called by jni_DefineClass and JVM_DefineClass) diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/classfile/verifier.cpp --- a/src/share/vm/classfile/verifier.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/classfile/verifier.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -1600,7 +1600,11 @@ types = (1 << JVM_CONSTANT_Double) | (1 << JVM_CONSTANT_Long); verify_cp_type(index, cp, types, CHECK_VERIFY(this)); } - if (tag.is_string() || tag.is_unresolved_string()) { + if (tag.is_string() && cp->is_pseudo_string_at(index)) { + current_frame->push_stack( + VerificationType::reference_type( + vmSymbols::java_lang_Object()), CHECK_VERIFY(this)); + } else if (tag.is_string() || tag.is_unresolved_string()) { current_frame->push_stack( VerificationType::reference_type( vmSymbols::java_lang_String()), CHECK_VERIFY(this)); diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/includeDB_gc_parallel --- a/src/share/vm/includeDB_gc_parallel Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/includeDB_gc_parallel Wed Nov 19 14:20:51 2008 -0800 @@ -30,6 +30,12 @@ compiledICHolderKlass.cpp oop.pcgc.inline.hpp +constantPoolKlass.cpp cardTableRS.hpp +constantPoolKlass.cpp oop.pcgc.inline.hpp +constantPoolKlass.cpp psPromotionManager.inline.hpp +constantPoolKlass.cpp psScavenge.inline.hpp +constantPoolKlass.cpp parOopClosures.inline.hpp + genCollectedHeap.cpp concurrentMarkSweepThread.hpp genCollectedHeap.cpp vmCMSOperations.hpp diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/oops/constantPoolKlass.cpp --- a/src/share/vm/oops/constantPoolKlass.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/oops/constantPoolKlass.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -35,6 +35,7 @@ c->set_tags(NULL); c->set_cache(NULL); c->set_pool_holder(NULL); + c->set_flags(0); // only set to non-zero if constant pool is merged by RedefineClasses c->set_orig_length(0); // all fields are initialized; needed for GC @@ -261,10 +262,32 @@ void constantPoolKlass::oop_copy_contents(PSPromotionManager* pm, oop obj) { assert(obj->is_constantPool(), "should be constant pool"); + constantPoolOop cp = (constantPoolOop) obj; + if (AnonymousClasses && cp->has_pseudo_string() && cp->tags() != NULL) { + oop* base = (oop*)cp->base(); + for (int i = 0; i < cp->length(); ++i, ++base) { + if (cp->tag_at(i).is_string()) { + if (PSScavenge::should_scavenge(base)) { + pm->claim_or_forward_breadth(base); + } + } + } + } } void constantPoolKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->is_constantPool(), "should be constant pool"); + constantPoolOop cp = (constantPoolOop) obj; + if (AnonymousClasses && cp->has_pseudo_string() && cp->tags() != NULL) { + oop* base = (oop*)cp->base(); + for (int i = 0; i < cp->length(); ++i, ++base) { + if (cp->tag_at(i).is_string()) { + if (PSScavenge::should_scavenge(base)) { + pm->claim_or_forward_depth(base); + } + } + } + } } #endif // SERIALGC @@ -278,6 +301,11 @@ assert(obj->is_constantPool(), "must be constantPool"); Klass::oop_print_on(obj, st); constantPoolOop cp = constantPoolOop(obj); + if (cp->flags() != 0) { + st->print(" - flags : 0x%x", cp->flags()); + if (cp->has_pseudo_string()) st->print(" has_pseudo_string"); + st->cr(); + } // Temp. remove cache so we can do lookups with original indicies. constantPoolCacheHandle cache (THREAD, cp->cache()); @@ -302,7 +330,11 @@ break; case JVM_CONSTANT_UnresolvedString : case JVM_CONSTANT_String : - anObj = cp->string_at(index, CATCH); + if (cp->is_pseudo_string_at(index)) { + anObj = cp->pseudo_string_at(index); + } else { + anObj = cp->string_at(index, CATCH); + } anObj->print_value_on(st); st->print(" {0x%lx}", (address)anObj); break; @@ -382,8 +414,12 @@ "should be symbol or instance"); } if (cp->tag_at(i).is_string()) { - guarantee((*base)->is_perm(), "should be in permspace"); - guarantee((*base)->is_instance(), "should be instance"); + if (!cp->has_pseudo_string()) { + guarantee((*base)->is_perm(), "should be in permspace"); + guarantee((*base)->is_instance(), "should be instance"); + } else { + // can be non-perm, can be non-instance (array) + } } base++; } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/oops/constantPoolOop.cpp --- a/src/share/vm/oops/constantPoolOop.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/oops/constantPoolOop.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -25,6 +25,18 @@ # include "incls/_precompiled.incl" # include "incls/_constantPoolOop.cpp.incl" +void constantPoolOopDesc::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 +} + klassOop constantPoolOopDesc::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS) { // A resolved constantPool entry will contain a klassOop, otherwise a symbolOop. // It is not safe to rely on the tag bit's here, since we don't have a lock, and the entry and @@ -333,8 +345,10 @@ oop entry = *(obj_at_addr(which)); if (entry->is_symbol()) { return ((symbolOop)entry)->as_C_string(); + } else if (java_lang_String::is_instance(entry)) { + return java_lang_String::as_utf8_string(entry); } else { - return java_lang_String::as_utf8_string(entry); + return (char*)""; } } @@ -385,6 +399,19 @@ } +bool constantPoolOopDesc::is_pseudo_string_at(int which) { + oop entry = *(obj_at_addr(which)); + if (entry->is_symbol()) + // Not yet resolved, but it will resolve to a string. + return false; + else if (java_lang_String::is_instance(entry)) + return false; // actually, it might be a non-interned or non-perm string + else + // truly pseudo + return true; +} + + bool constantPoolOopDesc::klass_name_at_matches(instanceKlassHandle k, int which) { // Names are interned, so we can compare symbolOops directly diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/oops/constantPoolOop.hpp --- a/src/share/vm/oops/constantPoolOop.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/oops/constantPoolOop.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -41,6 +41,7 @@ typeArrayOop _tags; // the tag array describing the constant pool's contents constantPoolCacheOop _cache; // the cache holding interpreter runtime information klassOop _pool_holder; // the corresponding class + int _flags; // a few header bits to describe contents for GC int _length; // number of elements in the array // only set to non-zero if constant pool is merged by RedefineClasses int _orig_length; @@ -49,6 +50,16 @@ void tag_at_put(int which, jbyte t) { tags()->byte_at_put(which, t); } void release_tag_at_put(int which, jbyte t) { tags()->release_byte_at_put(which, t); } + enum FlagBit { + FB_has_pseudo_string = 2 + }; + + 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 + private: intptr_t* base() const { return (intptr_t*) (((char*) this) + sizeof(constantPoolOopDesc)); } oop* tags_addr() { return (oop*)&_tags; } @@ -82,6 +93,9 @@ public: typeArrayOop tags() const { return _tags; } + bool has_pseudo_string() const { return flag_at(FB_has_pseudo_string); } + void set_pseudo_string() { set_flag_at(FB_has_pseudo_string); } + // Klass holding pool klassOop pool_holder() const { return _pool_holder; } void set_pool_holder(klassOop k) { oop_store_without_check((oop*)&_pool_holder, (oop) k); } @@ -272,6 +286,27 @@ return string_at_impl(h_this, which, CHECK_NULL); } + // A "pseudo-string" is an non-string oop that has found is way into + // a String entry. + // Under AnonymousClasses this can happen if the user patches a live + // object into a CONSTANT_String entry of an anonymous class. + // Method oops internally created for method handles may also + // use pseudo-strings to link themselves to related metaobjects. + + bool is_pseudo_string_at(int which); + + oop pseudo_string_at(int which) { + assert(tag_at(which).is_string(), "Corrupted constant pool"); + return *obj_at_addr(which); + } + + void pseudo_string_at_put(int which, oop x) { + assert(AnonymousClasses, ""); + set_pseudo_string(); // mark header + assert(tag_at(which).is_string() || tag_at(which).is_unresolved_string(), "Corrupted constant pool"); + string_at_put(which, x); // this works just fine + } + // only called when we are sure a string entry is already resolved (via an // earlier string_at call. oop resolved_string_at(int which) { @@ -293,6 +328,7 @@ // UTF8 char* representation was chosen to avoid conversion of // java_lang_Strings at resolved entries into symbolOops // or vice versa. + // Caller is responsible for checking for pseudo-strings. char* string_at_noresolve(int which); jint name_and_type_at(int which) { diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/oops/instanceKlass.hpp --- a/src/share/vm/oops/instanceKlass.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/oops/instanceKlass.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -147,6 +147,10 @@ oop _class_loader; // Protection domain. oop _protection_domain; + // Host class, which grants its access privileges to this class also. + // This is only non-null for an anonymous class (AnonymousClasses enabled). + // The host class is either named, or a previously loaded anonymous class. + klassOop _host_klass; // Class signers. objArrayOop _signers; // Name of source file containing this klass, NULL if not specified. @@ -375,6 +379,11 @@ oop protection_domain() { return _protection_domain; } void set_protection_domain(oop pd) { oop_store((oop*) &_protection_domain, pd); } + // host class + oop host_klass() const { return _host_klass; } + void set_host_klass(oop host) { oop_store((oop*) &_host_klass, host); } + bool is_anonymous() const { return _host_klass != NULL; } + // signers objArrayOop signers() const { return _signers; } void set_signers(objArrayOop s) { oop_store((oop*) &_signers, oop(s)); } @@ -709,6 +718,7 @@ oop* adr_constants() const { return (oop*)&this->_constants;} oop* adr_class_loader() const { return (oop*)&this->_class_loader;} oop* adr_protection_domain() const { return (oop*)&this->_protection_domain;} + oop* adr_host_klass() const { return (oop*)&this->_host_klass;} oop* adr_signers() const { return (oop*)&this->_signers;} oop* adr_source_file_name() const { return (oop*)&this->_source_file_name;} oop* adr_source_debug_extension() const { return (oop*)&this->_source_debug_extension;} diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/oops/instanceKlassKlass.cpp --- a/src/share/vm/oops/instanceKlassKlass.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/oops/instanceKlassKlass.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -81,6 +81,7 @@ MarkSweep::mark_and_push(ik->adr_source_debug_extension()); MarkSweep::mark_and_push(ik->adr_inner_classes()); MarkSweep::mark_and_push(ik->adr_protection_domain()); + MarkSweep::mark_and_push(ik->adr_host_klass()); MarkSweep::mark_and_push(ik->adr_signers()); MarkSweep::mark_and_push(ik->adr_generic_signature()); MarkSweep::mark_and_push(ik->adr_class_annotations()); @@ -120,6 +121,7 @@ PSParallelCompact::mark_and_push(cm, ik->adr_source_debug_extension()); PSParallelCompact::mark_and_push(cm, ik->adr_inner_classes()); PSParallelCompact::mark_and_push(cm, ik->adr_protection_domain()); + PSParallelCompact::mark_and_push(cm, ik->adr_host_klass()); PSParallelCompact::mark_and_push(cm, ik->adr_signers()); PSParallelCompact::mark_and_push(cm, ik->adr_generic_signature()); PSParallelCompact::mark_and_push(cm, ik->adr_class_annotations()); @@ -159,6 +161,7 @@ blk->do_oop(ik->adr_constants()); blk->do_oop(ik->adr_class_loader()); blk->do_oop(ik->adr_protection_domain()); + blk->do_oop(ik->adr_host_klass()); blk->do_oop(ik->adr_signers()); blk->do_oop(ik->adr_source_file_name()); blk->do_oop(ik->adr_source_debug_extension()); @@ -211,6 +214,8 @@ if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_protection_domain(); if (mr.contains(adr)) blk->do_oop(adr); + adr = ik->adr_host_klass(); + if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_signers(); if (mr.contains(adr)) blk->do_oop(adr); adr = ik->adr_source_file_name(); @@ -260,6 +265,7 @@ MarkSweep::adjust_pointer(ik->adr_constants()); MarkSweep::adjust_pointer(ik->adr_class_loader()); MarkSweep::adjust_pointer(ik->adr_protection_domain()); + MarkSweep::adjust_pointer(ik->adr_host_klass()); MarkSweep::adjust_pointer(ik->adr_signers()); MarkSweep::adjust_pointer(ik->adr_source_file_name()); MarkSweep::adjust_pointer(ik->adr_source_debug_extension()); @@ -295,6 +301,11 @@ pm->claim_or_forward_breadth(pd_addr); } + oop* hk_addr = ik->adr_host_klass(); + if (PSScavenge::should_scavenge(hk_addr)) { + pm->claim_or_forward_breadth(hk_addr); + } + oop* sg_addr = ik->adr_signers(); if (PSScavenge::should_scavenge(sg_addr)) { pm->claim_or_forward_breadth(sg_addr); @@ -318,6 +329,11 @@ pm->claim_or_forward_depth(pd_addr); } + oop* hk_addr = ik->adr_host_klass(); + if (PSScavenge::should_scavenge(hk_addr)) { + pm->claim_or_forward_depth(hk_addr); + } + oop* sg_addr = ik->adr_signers(); if (PSScavenge::should_scavenge(sg_addr)) { pm->claim_or_forward_depth(sg_addr); @@ -421,6 +437,7 @@ ik->set_constants(NULL); ik->set_class_loader(NULL); ik->set_protection_domain(NULL); + ik->set_host_klass(NULL); ik->set_signers(NULL); ik->set_source_file_name(NULL); ik->set_source_debug_extension(NULL); @@ -526,6 +543,7 @@ st->print(" - constants: "); ik->constants()->print_value_on(st); st->cr(); st->print(" - class loader: "); ik->class_loader()->print_value_on(st); st->cr(); st->print(" - protection domain: "); ik->protection_domain()->print_value_on(st); st->cr(); + st->print(" - host class: "); ik->host_klass()->print_value_on(st); st->cr(); st->print(" - signers: "); ik->signers()->print_value_on(st); st->cr(); if (ik->source_file_name() != NULL) { st->print(" - source file: "); @@ -626,7 +644,7 @@ ik->_verify_count = Universe::verify_count(); #endif // Verify that klass is present in SystemDictionary - if (ik->is_loaded()) { + if (ik->is_loaded() && !ik->is_anonymous()) { symbolHandle h_name (thread, ik->name()); Handle h_loader (thread, ik->class_loader()); Handle h_obj(thread, obj); @@ -764,6 +782,9 @@ if (ik->protection_domain() != NULL) { guarantee(ik->protection_domain()->is_oop(), "should be oop"); } + if (ik->host_klass() != NULL) { + guarantee(ik->host_klass()->is_oop(), "should be oop"); + } if (ik->signers() != NULL) { guarantee(ik->signers()->is_objArray(), "should be obj array"); } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/oops/klass.cpp --- a/src/share/vm/oops/klass.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/oops/klass.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -478,6 +478,24 @@ const char* Klass::external_name() const { + if (oop_is_instance()) { + instanceKlass* ik = (instanceKlass*) this; + if (ik->is_anonymous()) { + assert(AnonymousClasses, ""); + intptr_t hash = ik->java_mirror()->identity_hash(); + char hash_buf[40]; + sprintf(hash_buf, "/" UINTX_FORMAT, (uintx)hash); + size_t hash_len = strlen(hash_buf); + + size_t result_len = name()->utf8_length(); + char* result = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1); + name()->as_klass_external_name(result, (int) result_len + 1); + assert(strlen(result) == result_len, ""); + strcpy(result + result_len, hash_buf); + assert(strlen(result) == result_len + hash_len, ""); + return result; + } + } return name()->as_klass_external_name(); } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/block.cpp --- a/src/share/vm/opto/block.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/block.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -57,6 +57,14 @@ _blocks[i] = b; } +#ifndef PRODUCT +void Block_List::print() { + for (uint i=0; i < size(); i++) { + tty->print("B%d ", _blocks[i]->_pre_order); + } + tty->print("size = %d\n", size()); +} +#endif //============================================================================= @@ -66,6 +74,12 @@ // Check for Start block if( _pre_order == 1 ) return InteriorEntryAlignment; // Check for loop alignment + if (has_loop_alignment()) return loop_alignment(); + + return 1; // no particular alignment +} + +uint Block::compute_loop_alignment() { Node *h = head(); if( h->is_Loop() && h->as_Loop()->is_inner_loop() ) { // Pre- and post-loops have low trip count so do not bother with @@ -83,13 +97,15 @@ } return OptoLoopAlignment; // Otherwise align loop head } + return 1; // no particular alignment } //----------------------------------------------------------------------------- // Compute the size of first 'inst_cnt' instructions in this block. // Return the number of instructions left to compute if the block has -// less then 'inst_cnt' instructions. +// less then 'inst_cnt' instructions. Stop, and return 0 if sum_size +// exceeds OptoLoopAlignment. uint Block::compute_first_inst_size(uint& sum_size, uint inst_cnt, PhaseRegAlloc* ra) { uint last_inst = _nodes.size(); @@ -307,6 +323,8 @@ tty->print("\tLoop: B%d-B%d ", bhead->_pre_order, bx->_pre_order); // Dump any loop-specific bits, especially for CountedLoops. loop->dump_spec(tty); + } else if (has_loop_alignment()) { + tty->print(" top-of-loop"); } tty->print(" Freq: %g",_freq); if( Verbose || WizardMode ) { @@ -509,9 +527,11 @@ int branch_idx = b->_nodes.size() - b->_num_succs-1; if( branch_idx < 1 ) return false; Node *bra = b->_nodes[branch_idx]; - if( bra->is_Catch() ) return true; + if( bra->is_Catch() ) + return true; if( bra->is_Mach() ) { - if( bra->is_MachNullCheck() ) return true; + if( bra->is_MachNullCheck() ) + return true; int iop = bra->as_Mach()->ideal_Opcode(); if( iop == Op_FastLock || iop == Op_FastUnlock ) return true; @@ -557,10 +577,10 @@ dead->_nodes[k]->del_req(j); } -//------------------------------MoveToNext------------------------------------- +//------------------------------move_to_next----------------------------------- // Helper function to move block bx to the slot following b_index. Return // true if the move is successful, otherwise false -bool PhaseCFG::MoveToNext(Block* bx, uint b_index) { +bool PhaseCFG::move_to_next(Block* bx, uint b_index) { if (bx == NULL) return false; // Return false if bx is already scheduled. @@ -591,9 +611,9 @@ return true; } -//------------------------------MoveToEnd-------------------------------------- +//------------------------------move_to_end------------------------------------ // Move empty and uncommon blocks to the end. -void PhaseCFG::MoveToEnd(Block *b, uint i) { +void PhaseCFG::move_to_end(Block *b, uint i) { int e = b->is_Empty(); if (e != Block::not_empty) { if (e == Block::empty_with_goto) { @@ -609,15 +629,31 @@ _blocks.push(b); } -//------------------------------RemoveEmpty------------------------------------ -// Remove empty basic blocks and useless branches. -void PhaseCFG::RemoveEmpty() { +//---------------------------set_loop_alignment-------------------------------- +// Set loop alignment for every block +void PhaseCFG::set_loop_alignment() { + uint last = _num_blocks; + assert( _blocks[0] == _broot, "" ); + + for (uint i = 1; i < last; i++ ) { + Block *b = _blocks[i]; + if (b->head()->is_Loop()) { + b->set_loop_alignment(b); + } + } +} + +//-----------------------------remove_empty------------------------------------ +// Make empty basic blocks to be "connector" blocks, Move uncommon blocks +// to the end. +void PhaseCFG::remove_empty() { // Move uncommon blocks to the end uint last = _num_blocks; - uint i; assert( _blocks[0] == _broot, "" ); - for( i = 1; i < last; i++ ) { + + for (uint i = 1; i < last; i++) { Block *b = _blocks[i]; + if (b->is_connector()) break; // Check for NeverBranch at block end. This needs to become a GOTO to the // true target. NeverBranch are treated as a conditional branch that @@ -629,37 +665,40 @@ convert_NeverBranch_to_Goto(b); // Look for uncommon blocks and move to end. - if( b->is_uncommon(_bbs) ) { - MoveToEnd(b, i); - last--; // No longer check for being uncommon! - if( no_flip_branch(b) ) { // Fall-thru case must follow? - b = _blocks[i]; // Find the fall-thru block - MoveToEnd(b, i); - last--; + if (!C->do_freq_based_layout()) { + if( b->is_uncommon(_bbs) ) { + move_to_end(b, i); + last--; // No longer check for being uncommon! + if( no_flip_branch(b) ) { // Fall-thru case must follow? + b = _blocks[i]; // Find the fall-thru block + move_to_end(b, i); + last--; + } + i--; // backup block counter post-increment } - i--; // backup block counter post-increment } } - // Remove empty blocks - uint j1; + // Move empty blocks to the end last = _num_blocks; - for( i=0; i < last; i++ ) { + for (uint i = 1; i < last; i++) { Block *b = _blocks[i]; - if (i > 0) { - if (b->is_Empty() != Block::not_empty) { - MoveToEnd(b, i); - last--; - i--; - } + if (b->is_Empty() != Block::not_empty) { + move_to_end(b, i); + last--; + i--; } } // End of for all blocks +} +//-----------------------------fixup_flow-------------------------------------- +// Fix up the final control flow for basic blocks. +void PhaseCFG::fixup_flow() { // Fixup final control flow for the blocks. Remove jump-to-next // block. If neither arm of a IF follows the conditional branch, we // have to add a second jump after the conditional. We place the // TRUE branch target in succs[0] for both GOTOs and IFs. - for( i=0; i < _num_blocks; i++ ) { + for (uint i=0; i < _num_blocks; i++) { Block *b = _blocks[i]; b->_pre_order = i; // turn pre-order into block-index @@ -700,7 +739,7 @@ } } // Remove all CatchProjs - for (j1 = 0; j1 < b->_num_succs; j1++) b->_nodes.pop(); + for (uint j1 = 0; j1 < b->_num_succs; j1++) b->_nodes.pop(); } else if (b->_num_succs == 1) { // Block ends in a Goto? @@ -730,8 +769,7 @@ // successors after the current one, provided that the // successor was previously unscheduled, but moveable // (i.e., all paths to it involve a branch). - if( bnext != bs0 && bnext != bs1 ) { - + if( !C->do_freq_based_layout() && bnext != bs0 && bnext != bs1 ) { // Choose the more common successor based on the probability // of the conditional branch. Block *bx = bs0; @@ -751,9 +789,9 @@ } // Attempt the more common successor first - if (MoveToNext(bx, i)) { + if (move_to_next(bx, i)) { bnext = bx; - } else if (MoveToNext(by, i)) { + } else if (move_to_next(by, i)) { bnext = by; } } @@ -774,10 +812,8 @@ // Flip projection for each target { ProjNode *tmp = proj0; proj0 = proj1; proj1 = tmp; } - } else if( bnext == bs1 ) { // Fall-thru is already in succs[1] - - } else { // Else need a double-branch - + } else if( bnext != bs1 ) { + // Need a double-branch // The existing conditional branch need not change. // Add a unconditional branch to the false target. // Alas, it must appear in its own block and adding a @@ -786,8 +822,9 @@ } // Make sure we TRUE branch to the target - if( proj0->Opcode() == Op_IfFalse ) + if( proj0->Opcode() == Op_IfFalse ) { iff->negate(); + } b->_nodes.pop(); // Remove IfFalse & IfTrue projections b->_nodes.pop(); @@ -796,9 +833,7 @@ // Multi-exit block, e.g. a switch statement // But we don't need to do anything here } - } // End of for all blocks - } @@ -905,7 +940,7 @@ // Force the Union-Find mapping to be at least this large extend(max,0); // Initialize to be the ID mapping. - for( uint i=0; i<_max; i++ ) map(i,i); + for( uint i=0; i= _max ) return idx; uint next = lookup(idx); while( next != idx ) { // Scan chain of equivalences - assert( next < idx, "always union smaller" ); idx = next; // until find a fixed-point next = lookup(idx); } @@ -956,3 +990,491 @@ assert( src < dst, "always union smaller" ); map(dst,src); } + +#ifndef PRODUCT +static void edge_dump(GrowableArray *edges) { + tty->print_cr("---- Edges ----"); + for (int i = 0; i < edges->length(); i++) { + CFGEdge *e = edges->at(i); + if (e != NULL) { + edges->at(i)->dump(); + } + } +} + +static void trace_dump(Trace *traces[], int count) { + tty->print_cr("---- Traces ----"); + for (int i = 0; i < count; i++) { + Trace *tr = traces[i]; + if (tr != NULL) { + tr->dump(); + } + } +} + +void Trace::dump( ) const { + tty->print_cr("Trace (freq %f)", first_block()->_freq); + for (Block *b = first_block(); b != NULL; b = next(b)) { + tty->print(" B%d", b->_pre_order); + if (b->head()->is_Loop()) { + tty->print(" (L%d)", b->compute_loop_alignment()); + } + if (b->has_loop_alignment()) { + tty->print(" (T%d)", b->code_alignment()); + } + } + tty->cr(); +} + +void CFGEdge::dump( ) const { + tty->print(" B%d --> B%d Freq: %f out:%3d%% in:%3d%% State: ", + from()->_pre_order, to()->_pre_order, freq(), _from_pct, _to_pct); + switch(state()) { + case connected: + tty->print("connected"); + break; + case open: + tty->print("open"); + break; + case interior: + tty->print("interior"); + break; + } + if (infrequent()) { + tty->print(" infrequent"); + } + tty->cr(); +} +#endif + +//============================================================================= + +//------------------------------edge_order------------------------------------- +// Comparison function for edges +static int edge_order(CFGEdge **e0, CFGEdge **e1) { + float freq0 = (*e0)->freq(); + float freq1 = (*e1)->freq(); + if (freq0 != freq1) { + return freq0 > freq1 ? -1 : 1; + } + + int dist0 = (*e0)->to()->_rpo - (*e0)->from()->_rpo; + int dist1 = (*e1)->to()->_rpo - (*e1)->from()->_rpo; + + return dist1 - dist0; +} + +//------------------------------trace_frequency_order-------------------------- +// Comparison function for edges +static int trace_frequency_order(const void *p0, const void *p1) { + Trace *tr0 = *(Trace **) p0; + Trace *tr1 = *(Trace **) p1; + Block *b0 = tr0->first_block(); + Block *b1 = tr1->first_block(); + + // The trace of connector blocks goes at the end; + // we only expect one such trace + if (b0->is_connector() != b1->is_connector()) { + return b1->is_connector() ? -1 : 1; + } + + // Pull more frequently executed blocks to the beginning + float freq0 = b0->_freq; + float freq1 = b1->_freq; + if (freq0 != freq1) { + return freq0 > freq1 ? -1 : 1; + } + + int diff = tr0->first_block()->_rpo - tr1->first_block()->_rpo; + + return diff; +} + +//------------------------------find_edges------------------------------------- +// Find edges of interest, i.e, those which can fall through. Presumes that +// edges which don't fall through are of low frequency and can be generally +// ignored. Initialize the list of traces. +void PhaseBlockLayout::find_edges() +{ + // Walk the blocks, creating edges and Traces + uint i; + Trace *tr = NULL; + for (i = 0; i < _cfg._num_blocks; i++) { + Block *b = _cfg._blocks[i]; + tr = new Trace(b, next, prev); + traces[tr->id()] = tr; + + // All connector blocks should be at the end of the list + if (b->is_connector()) break; + + // If this block and the next one have a one-to-one successor + // predecessor relationship, simply append the next block + int nfallthru = b->num_fall_throughs(); + while (nfallthru == 1 && + b->succ_fall_through(0)) { + Block *n = b->_succs[0]; + + // Skip over single-entry connector blocks, we don't want to + // add them to the trace. + while (n->is_connector() && n->num_preds() == 1) { + n = n->_succs[0]; + } + + // We see a merge point, so stop search for the next block + if (n->num_preds() != 1) break; + + i++; + assert(n = _cfg._blocks[i], "expecting next block"); + tr->append(n); + uf->map(n->_pre_order, tr->id()); + traces[n->_pre_order] = NULL; + nfallthru = b->num_fall_throughs(); + b = n; + } + + if (nfallthru > 0) { + // Create a CFGEdge for each outgoing + // edge that could be a fall-through. + for (uint j = 0; j < b->_num_succs; j++ ) { + if (b->succ_fall_through(j)) { + Block *target = b->non_connector_successor(j); + float freq = b->_freq * b->succ_prob(j); + int from_pct = (int) ((100 * freq) / b->_freq); + int to_pct = (int) ((100 * freq) / target->_freq); + edges->append(new CFGEdge(b, target, freq, from_pct, to_pct)); + } + } + } + } + + // Group connector blocks into one trace + for (i++; i < _cfg._num_blocks; i++) { + Block *b = _cfg._blocks[i]; + assert(b->is_connector(), "connector blocks at the end"); + tr->append(b); + uf->map(b->_pre_order, tr->id()); + traces[b->_pre_order] = NULL; + } +} + +//------------------------------union_traces---------------------------------- +// Union two traces together in uf, and null out the trace in the list +void PhaseBlockLayout::union_traces(Trace* updated_trace, Trace* old_trace) +{ + uint old_id = old_trace->id(); + uint updated_id = updated_trace->id(); + + uint lo_id = updated_id; + uint hi_id = old_id; + + // If from is greater than to, swap values to meet + // UnionFind guarantee. + if (updated_id > old_id) { + lo_id = old_id; + hi_id = updated_id; + + // Fix up the trace ids + traces[lo_id] = traces[updated_id]; + updated_trace->set_id(lo_id); + } + + // Union the lower with the higher and remove the pointer + // to the higher. + uf->Union(lo_id, hi_id); + traces[hi_id] = NULL; +} + +//------------------------------grow_traces------------------------------------- +// Append traces together via the most frequently executed edges +void PhaseBlockLayout::grow_traces() +{ + // Order the edges, and drive the growth of Traces via the most + // frequently executed edges. + edges->sort(edge_order); + for (int i = 0; i < edges->length(); i++) { + CFGEdge *e = edges->at(i); + + if (e->state() != CFGEdge::open) continue; + + Block *src_block = e->from(); + Block *targ_block = e->to(); + + // Don't grow traces along backedges? + if (!BlockLayoutRotateLoops) { + if (targ_block->_rpo <= src_block->_rpo) { + targ_block->set_loop_alignment(targ_block); + continue; + } + } + + Trace *src_trace = trace(src_block); + Trace *targ_trace = trace(targ_block); + + // If the edge in question can join two traces at their ends, + // append one trace to the other. + if (src_trace->last_block() == src_block) { + if (src_trace == targ_trace) { + e->set_state(CFGEdge::interior); + if (targ_trace->backedge(e)) { + // Reset i to catch any newly eligible edge + // (Or we could remember the first "open" edge, and reset there) + i = 0; + } + } else if (targ_trace->first_block() == targ_block) { + e->set_state(CFGEdge::connected); + src_trace->append(targ_trace); + union_traces(src_trace, targ_trace); + } + } + } +} + +//------------------------------merge_traces----------------------------------- +// Embed one trace into another, if the fork or join points are sufficiently +// balanced. +void PhaseBlockLayout::merge_traces(bool fall_thru_only) +{ + // Walk the edge list a another time, looking at unprocessed edges. + // Fold in diamonds + for (int i = 0; i < edges->length(); i++) { + CFGEdge *e = edges->at(i); + + if (e->state() != CFGEdge::open) continue; + if (fall_thru_only) { + if (e->infrequent()) continue; + } + + Block *src_block = e->from(); + Trace *src_trace = trace(src_block); + bool src_at_tail = src_trace->last_block() == src_block; + + Block *targ_block = e->to(); + Trace *targ_trace = trace(targ_block); + bool targ_at_start = targ_trace->first_block() == targ_block; + + if (src_trace == targ_trace) { + // This may be a loop, but we can't do much about it. + e->set_state(CFGEdge::interior); + continue; + } + + if (fall_thru_only) { + // If the edge links the middle of two traces, we can't do anything. + // Mark the edge and continue. + if (!src_at_tail & !targ_at_start) { + continue; + } + + // Don't grow traces along backedges? + if (!BlockLayoutRotateLoops && (targ_block->_rpo <= src_block->_rpo)) { + continue; + } + + // If both ends of the edge are available, why didn't we handle it earlier? + assert(src_at_tail ^ targ_at_start, "Should have caught this edge earlier."); + + if (targ_at_start) { + // Insert the "targ" trace in the "src" trace if the insertion point + // is a two way branch. + // Better profitability check possible, but may not be worth it. + // Someday, see if the this "fork" has an associated "join"; + // then make a policy on merging this trace at the fork or join. + // For example, other things being equal, it may be better to place this + // trace at the join point if the "src" trace ends in a two-way, but + // the insertion point is one-way. + assert(src_block->num_fall_throughs() == 2, "unexpected diamond"); + e->set_state(CFGEdge::connected); + src_trace->insert_after(src_block, targ_trace); + union_traces(src_trace, targ_trace); + } else if (src_at_tail) { + if (src_trace != trace(_cfg._broot)) { + e->set_state(CFGEdge::connected); + targ_trace->insert_before(targ_block, src_trace); + union_traces(targ_trace, src_trace); + } + } + } else if (e->state() == CFGEdge::open) { + // Append traces, even without a fall-thru connection. + // But leave root entry at the begining of the block list. + if (targ_trace != trace(_cfg._broot)) { + e->set_state(CFGEdge::connected); + src_trace->append(targ_trace); + union_traces(src_trace, targ_trace); + } + } + } +} + +//----------------------------reorder_traces----------------------------------- +// Order the sequence of the traces in some desirable way, and fixup the +// jumps at the end of each block. +void PhaseBlockLayout::reorder_traces(int count) +{ + ResourceArea *area = Thread::current()->resource_area(); + Trace ** new_traces = NEW_ARENA_ARRAY(area, Trace *, count); + Block_List worklist; + int new_count = 0; + + // Compact the traces. + for (int i = 0; i < count; i++) { + Trace *tr = traces[i]; + if (tr != NULL) { + new_traces[new_count++] = tr; + } + } + + // The entry block should be first on the new trace list. + Trace *tr = trace(_cfg._broot); + assert(tr == new_traces[0], "entry trace misplaced"); + + // Sort the new trace list by frequency + qsort(new_traces + 1, new_count - 1, sizeof(new_traces[0]), trace_frequency_order); + + // Patch up the successor blocks + _cfg._blocks.reset(); + _cfg._num_blocks = 0; + for (int i = 0; i < new_count; i++) { + Trace *tr = new_traces[i]; + if (tr != NULL) { + tr->fixup_blocks(_cfg); + } + } +} + +//------------------------------PhaseBlockLayout------------------------------- +// Order basic blocks based on frequency +PhaseBlockLayout::PhaseBlockLayout(PhaseCFG &cfg) : + Phase(BlockLayout), + _cfg(cfg) +{ + ResourceMark rm; + ResourceArea *area = Thread::current()->resource_area(); + + // List of traces + int size = _cfg._num_blocks + 1; + traces = NEW_ARENA_ARRAY(area, Trace *, size); + memset(traces, 0, size*sizeof(Trace*)); + next = NEW_ARENA_ARRAY(area, Block *, size); + memset(next, 0, size*sizeof(Block *)); + prev = NEW_ARENA_ARRAY(area, Block *, size); + memset(prev , 0, size*sizeof(Block *)); + + // List of edges + edges = new GrowableArray; + + // Mapping block index --> block_trace + uf = new UnionFind(size); + uf->reset(size); + + // Find edges and create traces. + find_edges(); + + // Grow traces at their ends via most frequent edges. + grow_traces(); + + // Merge one trace into another, but only at fall-through points. + // This may make diamonds and other related shapes in a trace. + merge_traces(true); + + // Run merge again, allowing two traces to be catenated, even if + // one does not fall through into the other. This appends loosely + // related traces to be near each other. + merge_traces(false); + + // Re-order all the remaining traces by frequency + reorder_traces(size); + + assert(_cfg._num_blocks >= (uint) (size - 1), "number of blocks can not shrink"); +} + + +//------------------------------backedge--------------------------------------- +// Edge e completes a loop in a trace. If the target block is head of the +// loop, rotate the loop block so that the loop ends in a conditional branch. +bool Trace::backedge(CFGEdge *e) { + bool loop_rotated = false; + Block *src_block = e->from(); + Block *targ_block = e->to(); + + assert(last_block() == src_block, "loop discovery at back branch"); + if (first_block() == targ_block) { + if (BlockLayoutRotateLoops && last_block()->num_fall_throughs() < 2) { + // Find the last block in the trace that has a conditional + // branch. + Block *b; + for (b = last_block(); b != NULL; b = prev(b)) { + if (b->num_fall_throughs() == 2) { + break; + } + } + + if (b != last_block() && b != NULL) { + loop_rotated = true; + + // Rotate the loop by doing two-part linked-list surgery. + append(first_block()); + break_loop_after(b); + } + } + + // Backbranch to the top of a trace + // Scroll foward through the trace from the targ_block. If we find + // a loop head before another loop top, use the the loop head alignment. + for (Block *b = targ_block; b != NULL; b = next(b)) { + if (b->has_loop_alignment()) { + break; + } + if (b->head()->is_Loop()) { + targ_block = b; + break; + } + } + + first_block()->set_loop_alignment(targ_block); + + } else { + // Backbranch into the middle of a trace + targ_block->set_loop_alignment(targ_block); + } + + return loop_rotated; +} + +//------------------------------fixup_blocks----------------------------------- +// push blocks onto the CFG list +// ensure that blocks have the correct two-way branch sense +void Trace::fixup_blocks(PhaseCFG &cfg) { + Block *last = last_block(); + for (Block *b = first_block(); b != NULL; b = next(b)) { + cfg._blocks.push(b); + cfg._num_blocks++; + if (!b->is_connector()) { + int nfallthru = b->num_fall_throughs(); + if (b != last) { + if (nfallthru == 2) { + // Ensure that the sense of the branch is correct + Block *bnext = next(b); + Block *bs0 = b->non_connector_successor(0); + + MachNode *iff = b->_nodes[b->_nodes.size()-3]->as_Mach(); + ProjNode *proj0 = b->_nodes[b->_nodes.size()-2]->as_Proj(); + ProjNode *proj1 = b->_nodes[b->_nodes.size()-1]->as_Proj(); + + if (bnext == bs0) { + // Fall-thru case in succs[0], should be in succs[1] + + // Flip targets in _succs map + Block *tbs0 = b->_succs[0]; + Block *tbs1 = b->_succs[1]; + b->_succs.map( 0, tbs1 ); + b->_succs.map( 1, tbs0 ); + + // Flip projections to match targets + b->_nodes.map(b->_nodes.size()-2, proj1); + b->_nodes.map(b->_nodes.size()-1, proj0); + } + } + } + } + } +} diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/block.hpp --- a/src/share/vm/opto/block.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/block.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -75,6 +75,7 @@ void insert( uint i, Block *n ); uint size() const { return _cnt; } void reset() { _cnt = 0; } + void print(); }; @@ -129,7 +130,11 @@ uint _rpo; // Number in reverse post order walk virtual bool is_block() { return true; } - float succ_prob(uint i); // return probability of i'th successor + float succ_prob(uint i); // return probability of i'th successor + int num_fall_throughs(); // How many fall-through candidate this block has + void update_uncommon_branch(Block* un); // Lower branch prob to uncommon code + bool succ_fall_through(uint i); // Is successor "i" is a fall-through candidate + Block* lone_fall_through(); // Return lone fall-through Block or null Block* dom_lca(Block* that); // Compute LCA in dominator tree. #ifdef ASSERT @@ -144,6 +149,7 @@ // Report the alignment required by this block. Must be a power of 2. // The previous block will insert nops to get this alignment. uint code_alignment(); + uint compute_loop_alignment(); // BLOCK_FREQUENCY is a sentinel to mark uses of constant block frequencies. // It is currently also used to scale such frequencies relative to @@ -184,11 +190,12 @@ int current_alignment = current_offset & max_pad; if( current_alignment != 0 ) { uint padding = (block_alignment-current_alignment) & max_pad; - if( !head()->is_Loop() || - padding <= (uint)MaxLoopPad || - first_inst_size() > padding ) { - return padding; + if( has_loop_alignment() && + padding > (uint)MaxLoopPad && + first_inst_size() <= padding ) { + return 0; } + return padding; } } return 0; @@ -202,6 +209,21 @@ void set_connector() { _connector = true; } bool is_connector() const { return _connector; }; + // Loop_alignment will be set for blocks which are at the top of loops. + // The block layout pass may rotate loops such that the loop head may not + // be the sequentially first block of the loop encountered in the linear + // list of blocks. If the layout pass is not run, loop alignment is set + // for each block which is the head of a loop. + uint _loop_alignment; + void set_loop_alignment(Block *loop_top) { + uint new_alignment = loop_top->compute_loop_alignment(); + if (new_alignment > _loop_alignment) { + _loop_alignment = new_alignment; + } + } + uint loop_alignment() const { return _loop_alignment; } + bool has_loop_alignment() const { return loop_alignment() > 0; } + // Create a new Block with given head Node. // Creates the (empty) predecessor arrays. Block( Arena *a, Node *headnode ) @@ -219,7 +241,8 @@ _raise_LCA_mark(0), _raise_LCA_visited(0), _first_inst_size(999999), - _connector(false) { + _connector(false), + _loop_alignment(0) { _nodes.push(headnode); } @@ -275,6 +298,16 @@ return s; } + // Return true if b is a successor of this block + bool has_successor(Block* b) const { + for (uint i = 0; i < _num_succs; i++ ) { + if (non_connector_successor(i) == b) { + return true; + } + } + return false; + } + // Successor block, after forwarding through connectors Block* non_connector_successor(int i) const { return _succs[i]->non_connector(); @@ -319,7 +352,6 @@ // I'll need a few machine-specific GotoNodes. Clone from this one. MachNode *_goto; - void insert_goto_at(uint block_no, uint succ_no); Block* insert_anti_dependences(Block* LCA, Node* load, bool verify = false); void verify_anti_dependences(Block* LCA, Node* load) { @@ -379,10 +411,15 @@ // Compute the instruction global latency with a backwards walk void ComputeLatenciesBackwards(VectorSet &visited, Node_List &stack); + // Set loop alignment + void set_loop_alignment(); + // Remove empty basic blocks - void RemoveEmpty(); - bool MoveToNext(Block* bx, uint b_index); - void MoveToEnd(Block* bx, uint b_index); + void remove_empty(); + void fixup_flow(); + bool move_to_next(Block* bx, uint b_index); + void move_to_end(Block* bx, uint b_index); + void insert_goto_at(uint block_no, uint succ_no); // Check for NeverBranch at block end. This needs to become a GOTO to the // true target. NeverBranch are treated as a conditional branch that always @@ -413,7 +450,7 @@ }; -//------------------------------UnionFindInfo---------------------------------- +//------------------------------UnionFind-------------------------------------- // Map Block indices to a block-index for a cfg-cover. // Array lookup in the optimized case. class UnionFind : public ResourceObj { @@ -508,3 +545,166 @@ void dump_tree() const; #endif }; + + +//----------------------------------CFGEdge------------------------------------ +// A edge between two basic blocks that will be embodied by a branch or a +// fall-through. +class CFGEdge : public ResourceObj { + private: + Block * _from; // Source basic block + Block * _to; // Destination basic block + float _freq; // Execution frequency (estimate) + int _state; + bool _infrequent; + int _from_pct; + int _to_pct; + + // Private accessors + int from_pct() const { return _from_pct; } + int to_pct() const { return _to_pct; } + int from_infrequent() const { return from_pct() < BlockLayoutMinDiamondPercentage; } + int to_infrequent() const { return to_pct() < BlockLayoutMinDiamondPercentage; } + + public: + enum { + open, // initial edge state; unprocessed + connected, // edge used to connect two traces together + interior // edge is interior to trace (could be backedge) + }; + + CFGEdge(Block *from, Block *to, float freq, int from_pct, int to_pct) : + _from(from), _to(to), _freq(freq), + _from_pct(from_pct), _to_pct(to_pct), _state(open) { + _infrequent = from_infrequent() || to_infrequent(); + } + + float freq() const { return _freq; } + Block* from() const { return _from; } + Block* to () const { return _to; } + int infrequent() const { return _infrequent; } + int state() const { return _state; } + + void set_state(int state) { _state = state; } + +#ifndef PRODUCT + void dump( ) const; +#endif +}; + + +//-----------------------------------Trace------------------------------------- +// An ordered list of basic blocks. +class Trace : public ResourceObj { + private: + uint _id; // Unique Trace id (derived from initial block) + Block ** _next_list; // Array mapping index to next block + Block ** _prev_list; // Array mapping index to previous block + Block * _first; // First block in the trace + Block * _last; // Last block in the trace + + // Return the block that follows "b" in the trace. + Block * next(Block *b) const { return _next_list[b->_pre_order]; } + void set_next(Block *b, Block *n) const { _next_list[b->_pre_order] = n; } + + // Return the block that preceeds "b" in the trace. + Block * prev(Block *b) const { return _prev_list[b->_pre_order]; } + void set_prev(Block *b, Block *p) const { _prev_list[b->_pre_order] = p; } + + // We've discovered a loop in this trace. Reset last to be "b", and first as + // the block following "b + void break_loop_after(Block *b) { + _last = b; + _first = next(b); + set_prev(_first, NULL); + set_next(_last, NULL); + } + + public: + + Trace(Block *b, Block **next_list, Block **prev_list) : + _first(b), + _last(b), + _next_list(next_list), + _prev_list(prev_list), + _id(b->_pre_order) { + set_next(b, NULL); + set_prev(b, NULL); + }; + + // Return the id number + uint id() const { return _id; } + void set_id(uint id) { _id = id; } + + // Return the first block in the trace + Block * first_block() const { return _first; } + + // Return the last block in the trace + Block * last_block() const { return _last; } + + // Insert a trace in the middle of this one after b + void insert_after(Block *b, Trace *tr) { + set_next(tr->last_block(), next(b)); + if (next(b) != NULL) { + set_prev(next(b), tr->last_block()); + } + + set_next(b, tr->first_block()); + set_prev(tr->first_block(), b); + + if (b == _last) { + _last = tr->last_block(); + } + } + + void insert_before(Block *b, Trace *tr) { + Block *p = prev(b); + assert(p != NULL, "use append instead"); + insert_after(p, tr); + } + + // Append another trace to this one. + void append(Trace *tr) { + insert_after(_last, tr); + } + + // Append a block at the end of this trace + void append(Block *b) { + set_next(_last, b); + set_prev(b, _last); + _last = b; + } + + // Adjust the the blocks in this trace + void fixup_blocks(PhaseCFG &cfg); + bool backedge(CFGEdge *e); + +#ifndef PRODUCT + void dump( ) const; +#endif +}; + +//------------------------------PhaseBlockLayout------------------------------- +// Rearrange blocks into some canonical order, based on edges and their frequencies +class PhaseBlockLayout : public Phase { + PhaseCFG &_cfg; // Control flow graph + + GrowableArray *edges; + Trace **traces; + Block **next; + Block **prev; + UnionFind *uf; + + // Given a block, find its encompassing Trace + Trace * trace(Block *b) { + return traces[uf->Find_compress(b->_pre_order)]; + } + public: + PhaseBlockLayout(PhaseCFG &cfg); + + void find_edges(); + void grow_traces(); + void merge_traces(bool loose_connections); + void reorder_traces(int count); + void union_traces(Trace* from, Trace* to); +}; diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/c2_globals.hpp --- a/src/share/vm/opto/c2_globals.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/c2_globals.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -256,10 +256,10 @@ develop(intx, PrintIdealGraphPort, 4444, \ "Ideal graph printer to network port") \ \ - develop(ccstr, PrintIdealGraphAddress, "127.0.0.1", \ + notproduct(ccstr, PrintIdealGraphAddress, "127.0.0.1", \ "IP address to connect to visualizer") \ \ - develop(ccstr, PrintIdealGraphFile, NULL, \ + notproduct(ccstr, PrintIdealGraphFile, NULL, \ "File to dump ideal graph to. If set overrides the " \ "use of the network") \ \ @@ -388,6 +388,9 @@ product(intx, EliminateAllocationArraySizeLimit, 64, \ "Array size (number of elements) limit for scalar replacement") \ \ + product(bool, UseOptoBiasInlining, true, \ + "Generate biased locking code in C2 ideal graph") \ + \ product(intx, ValueSearchLimit, 1000, \ "Recursion limit in PhaseMacroExpand::value_from_mem_phi") \ \ @@ -396,5 +399,15 @@ \ diagnostic(intx, DominatorSearchLimit, 1000, \ "Iterations limit in Node::dominates") \ + \ + product(bool, BlockLayoutByFrequency, true, \ + "Use edge frequencies to drive block ordering") \ + \ + product(intx, BlockLayoutMinDiamondPercentage, 20, \ + "Miniumum %% of a successor (predecessor) for which block layout "\ + "a will allow a fork (join) in a single chain") \ + \ + product(bool, BlockLayoutRotateLoops, false, \ + "Allow back branches to be fall throughs in the block layour") \ C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_NOTPRODUCT_FLAG) diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/callnode.cpp --- a/src/share/vm/opto/callnode.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/callnode.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -967,6 +967,7 @@ init_class_id(Class_SafePointScalarObject); } +bool SafePointScalarObjectNode::pinned() const { return true; } uint SafePointScalarObjectNode::ideal_reg() const { return 0; // No matching to machine instruction diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/callnode.hpp --- a/src/share/vm/opto/callnode.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/callnode.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -433,6 +433,10 @@ uint n_fields() const { return _n_fields; } DEBUG_ONLY(AllocateNode* alloc() const { return _alloc; }) + // SafePointScalarObject should be always pinned to the control edge + // of the SafePoint node for which it was generated. + virtual bool pinned() const; // { return true; } + virtual uint size_of() const { return sizeof(*this); } // Assumes that "this" is an argument to a safepoint node "s", and that diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/chaitin.cpp --- a/src/share/vm/opto/chaitin.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/chaitin.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -440,9 +440,7 @@ assert((int)(_matcher._new_SP+_framesize) >= (int)_matcher._out_arg_limit, "framesize must be large enough"); // This frame must preserve the required fp alignment - const int stack_alignment_in_words = Matcher::stack_alignment_in_slots(); - if (stack_alignment_in_words > 0) - _framesize = round_to(_framesize, Matcher::stack_alignment_in_bytes()); + _framesize = round_to(_framesize, Matcher::stack_alignment_in_slots()); assert( _framesize >= 0 && _framesize <= 1000000, "sanity check" ); #ifndef PRODUCT _total_framesize += _framesize; diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/classes.hpp --- a/src/share/vm/opto/classes.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/classes.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -205,6 +205,7 @@ macro(StoreC) macro(StoreCM) macro(StorePConditional) +macro(StoreIConditional) macro(StoreLConditional) macro(StoreD) macro(StoreF) diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/compile.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -551,7 +551,7 @@ rethrow_exceptions(kit.transfer_exceptions_into_jvms()); } - print_method("Before RemoveUseless"); + print_method("Before RemoveUseless", 3); // Remove clutter produced by parsing. if (!failing()) { @@ -822,6 +822,7 @@ Copy::zero_to_bytes(_trap_hist, sizeof(_trap_hist)); set_decompile_count(0); + set_do_freq_based_layout(BlockLayoutByFrequency || method_has_option("BlockLayoutByFrequency")); // Compilation level related initialization if (env()->comp_level() == CompLevel_fast_compile) { set_num_loop_opts(Tier1LoopOptsCount); @@ -1701,8 +1702,14 @@ // are not adding any new instructions. If any basic block is empty, we // can now safely remove it. { - NOT_PRODUCT( TracePhase t2("removeEmpty", &_t_removeEmptyBlocks, TimeCompiler); ) - cfg.RemoveEmpty(); + NOT_PRODUCT( TracePhase t2("blockOrdering", &_t_blockOrdering, TimeCompiler); ) + cfg.remove_empty(); + if (do_freq_based_layout()) { + PhaseBlockLayout layout(cfg); + } else { + cfg.set_loop_alignment(); + } + cfg.fixup_flow(); } // Perform any platform dependent postallocation verifications. @@ -1994,6 +2001,7 @@ case Op_StorePConditional: case Op_StoreI: case Op_StoreL: + case Op_StoreIConditional: case Op_StoreLConditional: case Op_CompareAndSwapI: case Op_CompareAndSwapL: diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/compile.hpp --- a/src/share/vm/opto/compile.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/compile.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -154,6 +154,7 @@ uint _decompile_count; // Cumulative decompilation counts. bool _do_inlining; // True if we intend to do inlining bool _do_scheduling; // True if we intend to do scheduling + bool _do_freq_based_layout; // True if we intend to do frequency based block layout bool _do_count_invocations; // True if we generate code to count invocations bool _do_method_data_update; // True if we generate code to update methodDataOops int _AliasLevel; // Locally-adjusted version of AliasLevel flag. @@ -307,6 +308,8 @@ void set_do_inlining(bool z) { _do_inlining = z; } bool do_scheduling() const { return _do_scheduling; } void set_do_scheduling(bool z) { _do_scheduling = z; } + bool do_freq_based_layout() const{ return _do_freq_based_layout; } + void set_do_freq_based_layout(bool z){ _do_freq_based_layout = z; } bool do_count_invocations() const{ return _do_count_invocations; } void set_do_count_invocations(bool z){ _do_count_invocations = z; } bool do_method_data_update() const { return _do_method_data_update; } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/gcm.cpp --- a/src/share/vm/opto/gcm.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/gcm.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -1319,11 +1319,33 @@ //------------------------------Estimate_Block_Frequency----------------------- // Estimate block frequencies based on IfNode probabilities. void PhaseCFG::Estimate_Block_Frequency() { - int cnts = C->method() ? C->method()->interpreter_invocation_count() : 1; - // Most of our algorithms will die horribly if frequency can become - // negative so make sure cnts is a sane value. - if( cnts <= 0 ) cnts = 1; - float f = (float)cnts/(float)FreqCountInvocations; + + // Force conditional branches leading to uncommon traps to be unlikely, + // not because we get to the uncommon_trap with less relative frequency, + // but because an uncommon_trap typically causes a deopt, so we only get + // there once. + if (C->do_freq_based_layout()) { + Block_List worklist; + Block* root_blk = _blocks[0]; + for (uint i = 1; i < root_blk->num_preds(); i++) { + Block *pb = _bbs[root_blk->pred(i)->_idx]; + if (pb->has_uncommon_code()) { + worklist.push(pb); + } + } + while (worklist.size() > 0) { + Block* uct = worklist.pop(); + if (uct == _broot) continue; + for (uint i = 1; i < uct->num_preds(); i++) { + Block *pb = _bbs[uct->pred(i)->_idx]; + if (pb->_num_succs == 1) { + worklist.push(pb); + } else if (pb->num_fall_throughs() == 2) { + pb->update_uncommon_branch(uct); + } + } + } + } // Create the loop tree and calculate loop depth. _root_loop = create_loop_tree(); @@ -1333,25 +1355,27 @@ _root_loop->compute_freq(); // Adjust all frequencies to be relative to a single method entry - _root_loop->_freq = f * 1.0; + _root_loop->_freq = 1.0; _root_loop->scale_freq(); // force paths ending at uncommon traps to be infrequent - Block_List worklist; - Block* root_blk = _blocks[0]; - for (uint i = 0; i < root_blk->num_preds(); i++) { - Block *pb = _bbs[root_blk->pred(i)->_idx]; - if (pb->has_uncommon_code()) { - worklist.push(pb); + if (!C->do_freq_based_layout()) { + Block_List worklist; + Block* root_blk = _blocks[0]; + for (uint i = 1; i < root_blk->num_preds(); i++) { + Block *pb = _bbs[root_blk->pred(i)->_idx]; + if (pb->has_uncommon_code()) { + worklist.push(pb); + } } - } - while (worklist.size() > 0) { - Block* uct = worklist.pop(); - uct->_freq = PROB_MIN; - for (uint i = 0; i < uct->num_preds(); i++) { - Block *pb = _bbs[uct->pred(i)->_idx]; - if (pb->_num_succs == 1 && pb->_freq > PROB_MIN) { - worklist.push(pb); + while (worklist.size() > 0) { + Block* uct = worklist.pop(); + uct->_freq = PROB_MIN; + for (uint i = 1; i < uct->num_preds(); i++) { + Block *pb = _bbs[uct->pred(i)->_idx]; + if (pb->_num_succs == 1 && pb->_freq > PROB_MIN) { + worklist.push(pb); + } } } } @@ -1556,22 +1580,6 @@ } } -#if 0 - // Raise frequency of the loop backedge block, in an effort - // to keep it empty. Skip the method level "loop". - if (_parent != NULL) { - CFGElement* s = _members.at(_members.length() - 1); - if (s->is_block()) { - Block* bk = s->as_Block(); - if (bk->_num_succs == 1 && bk->_succs[0] == hd) { - // almost any value >= 1.0f works - // FIXME: raw constant - bk->_freq = 1.05f; - } - } - } -#endif - // For all loops other than the outer, "method" loop, // sum and normalize the exit probability. The "method" loop // should keep the initial exit probability of 1, so that @@ -1589,12 +1597,15 @@ // the probability of exit per loop entry. for (int i = 0; i < _exits.length(); i++) { Block* et = _exits.at(i).get_target(); - float new_prob = _exits.at(i).get_prob() / exits_sum; + float new_prob = 0.0f; + if (_exits.at(i).get_prob() > 0.0f) { + new_prob = _exits.at(i).get_prob() / exits_sum; + } BlockProbPair bpp(et, new_prob); _exits.at_put(i, bpp); } - // Save the total, but guard against unreasoable probability, + // Save the total, but guard against unreasonable probability, // as the value is used to estimate the loop trip count. // An infinite trip count would blur relative block // frequencies. @@ -1688,6 +1699,137 @@ return 0.0f; } +//------------------------------num_fall_throughs----------------------------- +// Return the number of fall-through candidates for a block +int Block::num_fall_throughs() { + int eidx = end_idx(); + Node *n = _nodes[eidx]; // Get ending Node + + int op = n->Opcode(); + if (n->is_Mach()) { + if (n->is_MachNullCheck()) { + // In theory, either side can fall-thru, for simplicity sake, + // let's say only the false branch can now. + return 1; + } + op = n->as_Mach()->ideal_Opcode(); + } + + // Switch on branch type + switch( op ) { + case Op_CountedLoopEnd: + case Op_If: + return 2; + + case Op_Root: + case Op_Goto: + return 1; + + case Op_Catch: { + for (uint i = 0; i < _num_succs; i++) { + const CatchProjNode *ci = _nodes[i + eidx + 1]->as_CatchProj(); + if (ci->_con == CatchProjNode::fall_through_index) { + return 1; + } + } + return 0; + } + + case Op_Jump: + case Op_NeverBranch: + case Op_TailCall: + case Op_TailJump: + case Op_Return: + case Op_Halt: + case Op_Rethrow: + return 0; + + default: + ShouldNotReachHere(); + } + + return 0; +} + +//------------------------------succ_fall_through----------------------------- +// Return true if a specific successor could be fall-through target. +bool Block::succ_fall_through(uint i) { + int eidx = end_idx(); + Node *n = _nodes[eidx]; // Get ending Node + + int op = n->Opcode(); + if (n->is_Mach()) { + if (n->is_MachNullCheck()) { + // In theory, either side can fall-thru, for simplicity sake, + // let's say only the false branch can now. + return _nodes[i + eidx + 1]->Opcode() == Op_IfFalse; + } + op = n->as_Mach()->ideal_Opcode(); + } + + // Switch on branch type + switch( op ) { + case Op_CountedLoopEnd: + case Op_If: + case Op_Root: + case Op_Goto: + return true; + + case Op_Catch: { + const CatchProjNode *ci = _nodes[i + eidx + 1]->as_CatchProj(); + return ci->_con == CatchProjNode::fall_through_index; + } + + case Op_Jump: + case Op_NeverBranch: + case Op_TailCall: + case Op_TailJump: + case Op_Return: + case Op_Halt: + case Op_Rethrow: + return false; + + default: + ShouldNotReachHere(); + } + + return false; +} + +//------------------------------update_uncommon_branch------------------------ +// Update the probability of a two-branch to be uncommon +void Block::update_uncommon_branch(Block* ub) { + int eidx = end_idx(); + Node *n = _nodes[eidx]; // Get ending Node + + int op = n->as_Mach()->ideal_Opcode(); + + assert(op == Op_CountedLoopEnd || op == Op_If, "must be a If"); + assert(num_fall_throughs() == 2, "must be a two way branch block"); + + // Which successor is ub? + uint s; + for (s = 0; s <_num_succs; s++) { + if (_succs[s] == ub) break; + } + assert(s < 2, "uncommon successor must be found"); + + // If ub is the true path, make the proability small, else + // ub is the false path, and make the probability large + bool invert = (_nodes[s + eidx + 1]->Opcode() == Op_IfFalse); + + // Get existing probability + float p = n->as_MachIf()->_prob; + + if (invert) p = 1.0 - p; + if (p > PROB_MIN) { + p = PROB_MIN; + } + if (invert) p = 1.0 - p; + + n->as_MachIf()->_prob = p; +} + //------------------------------update_succ_freq------------------------------- // Update the appropriate frequency associated with block 'b', a succesor of // a block in this loop. diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/library_call.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -3485,11 +3485,32 @@ const TypePtr *adr_type = _gvn.type(adr)->is_ptr(); int alias_idx = C->get_alias_index(adr_type); - Node *result = _gvn.transform(new (C, 5) StoreLConditionalNode(control(), memory(alias_idx), adr, newVal, oldVal)); - Node *store_proj = _gvn.transform( new (C, 1) SCMemProjNode(result)); + Node *cas = _gvn.transform(new (C, 5) StoreLConditionalNode(control(), memory(alias_idx), adr, newVal, oldVal)); + Node *store_proj = _gvn.transform( new (C, 1) SCMemProjNode(cas)); set_memory(store_proj, alias_idx); - - push(result); + Node *bol = _gvn.transform( new (C, 2) BoolNode( cas, BoolTest::eq ) ); + + Node *result; + // CMove node is not used to be able fold a possible check code + // after attemptUpdate() call. This code could be transformed + // into CMove node by loop optimizations. + { + RegionNode *r = new (C, 3) RegionNode(3); + result = new (C, 3) PhiNode(r, TypeInt::BOOL); + + Node *iff = create_and_xform_if(control(), bol, PROB_FAIR, COUNT_UNKNOWN); + Node *iftrue = opt_iff(r, iff); + r->init_req(1, iftrue); + result->init_req(1, intcon(1)); + result->init_req(2, intcon(0)); + + set_control(_gvn.transform(r)); + record_for_igvn(r); + + C->set_has_split_ifs(true); // Has chance for split-if optimization + } + + push(_gvn.transform(result)); return true; } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/loopTransform.cpp --- a/src/share/vm/opto/loopTransform.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/loopTransform.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -1519,6 +1519,7 @@ Node *bol = iff->in(1); if( bol && bol->req() > 1 && bol->in(1) && ((bol->in(1)->Opcode() == Op_StorePConditional ) || + (bol->in(1)->Opcode() == Op_StoreIConditional ) || (bol->in(1)->Opcode() == Op_StoreLConditional ) || (bol->in(1)->Opcode() == Op_CompareAndSwapI ) || (bol->in(1)->Opcode() == Op_CompareAndSwapL ) || diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/macro.cpp --- a/src/share/vm/opto/macro.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/macro.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -82,16 +82,31 @@ } } -Node* PhaseMacroExpand::opt_iff(Node* region, Node* iff) { - IfNode *opt_iff = transform_later(iff)->as_If(); +Node* PhaseMacroExpand::opt_bits_test(Node* ctrl, Node* region, int edge, Node* word, int mask, int bits, bool return_fast_path) { + Node* cmp; + if (mask != 0) { + Node* and_node = transform_later(new (C, 3) AndXNode(word, MakeConX(mask))); + cmp = transform_later(new (C, 3) CmpXNode(and_node, MakeConX(bits))); + } else { + cmp = word; + } + Node* bol = transform_later(new (C, 2) BoolNode(cmp, BoolTest::ne)); + IfNode* iff = new (C, 2) IfNode( ctrl, bol, PROB_MIN, COUNT_UNKNOWN ); + transform_later(iff); - // Fast path taken; set region slot 2 - Node *fast_taken = transform_later( new (C, 1) IfFalseNode(opt_iff) ); - region->init_req(2,fast_taken); // Capture fast-control + // Fast path taken. + Node *fast_taken = transform_later( new (C, 1) IfFalseNode(iff) ); // Fast path not-taken, i.e. slow path - Node *slow_taken = transform_later( new (C, 1) IfTrueNode(opt_iff) ); - return slow_taken; + Node *slow_taken = transform_later( new (C, 1) IfTrueNode(iff) ); + + if (return_fast_path) { + region->init_req(edge, slow_taken); // Capture slow-control + return fast_taken; + } else { + region->init_req(edge, fast_taken); // Capture fast-control + return slow_taken; + } } //--------------------copy_predefined_input_for_runtime_call-------------------- @@ -854,7 +869,7 @@ Node* PhaseMacroExpand::make_load(Node* ctl, Node* mem, Node* base, int offset, const Type* value_type, BasicType bt) { Node* adr = basic_plus_adr(base, offset); - const TypePtr* adr_type = TypeRawPtr::BOTTOM; + const TypePtr* adr_type = adr->bottom_type()->is_ptr(); Node* value = LoadNode::make(_igvn, ctl, mem, adr, adr_type, value_type, bt); transform_later(value); return value; @@ -1583,12 +1598,193 @@ Node* flock = lock->fastlock_node(); // Make the merge point - Node *region = new (C, 3) RegionNode(3); + Node *region; + Node *mem_phi; + Node *slow_path; + + if (UseOptoBiasInlining) { + /* + * See the full descrition in MacroAssembler::biased_locking_enter(). + * + * if( (mark_word & biased_lock_mask) == biased_lock_pattern ) { + * // The object is biased. + * proto_node = klass->prototype_header; + * o_node = thread | proto_node; + * x_node = o_node ^ mark_word; + * if( (x_node & ~age_mask) == 0 ) { // Biased to the current thread ? + * // Done. + * } else { + * if( (x_node & biased_lock_mask) != 0 ) { + * // The klass's prototype header is no longer biased. + * cas(&mark_word, mark_word, proto_node) + * goto cas_lock; + * } else { + * // The klass's prototype header is still biased. + * if( (x_node & epoch_mask) != 0 ) { // Expired epoch? + * old = mark_word; + * new = o_node; + * } else { + * // Different thread or anonymous biased. + * old = mark_word & (epoch_mask | age_mask | biased_lock_mask); + * new = thread | old; + * } + * // Try to rebias. + * if( cas(&mark_word, old, new) == 0 ) { + * // Done. + * } else { + * goto slow_path; // Failed. + * } + * } + * } + * } else { + * // The object is not biased. + * cas_lock: + * if( FastLock(obj) == 0 ) { + * // Done. + * } else { + * slow_path: + * OptoRuntime::complete_monitor_locking_Java(obj); + * } + * } + */ + + region = new (C, 5) RegionNode(5); + // create a Phi for the memory state + mem_phi = new (C, 5) PhiNode( region, Type::MEMORY, TypeRawPtr::BOTTOM); + + Node* fast_lock_region = new (C, 3) RegionNode(3); + Node* fast_lock_mem_phi = new (C, 3) PhiNode( fast_lock_region, Type::MEMORY, TypeRawPtr::BOTTOM); + + // First, check mark word for the biased lock pattern. + Node* mark_node = make_load(ctrl, mem, obj, oopDesc::mark_offset_in_bytes(), TypeX_X, TypeX_X->basic_type()); + + // Get fast path - mark word has the biased lock pattern. + ctrl = opt_bits_test(ctrl, fast_lock_region, 1, mark_node, + markOopDesc::biased_lock_mask_in_place, + markOopDesc::biased_lock_pattern, true); + // fast_lock_region->in(1) is set to slow path. + fast_lock_mem_phi->init_req(1, mem); + + // Now check that the lock is biased to the current thread and has + // the same epoch and bias as Klass::_prototype_header. + + // Special-case a fresh allocation to avoid building nodes: + Node* klass_node = AllocateNode::Ideal_klass(obj, &_igvn); + if (klass_node == NULL) { + Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes()); + klass_node = transform_later( LoadKlassNode::make(_igvn, mem, k_adr, _igvn.type(k_adr)->is_ptr()) ); + } + Node *proto_node = make_load(ctrl, mem, klass_node, Klass::prototype_header_offset_in_bytes() + sizeof(oopDesc), TypeX_X, TypeX_X->basic_type()); + + Node* thread = transform_later(new (C, 1) ThreadLocalNode()); + Node* cast_thread = transform_later(new (C, 2) CastP2XNode(ctrl, thread)); + Node* o_node = transform_later(new (C, 3) OrXNode(cast_thread, proto_node)); + Node* x_node = transform_later(new (C, 3) XorXNode(o_node, mark_node)); + + // Get slow path - mark word does NOT match the value. + Node* not_biased_ctrl = opt_bits_test(ctrl, region, 3, x_node, + (~markOopDesc::age_mask_in_place), 0); + // region->in(3) is set to fast path - the object is biased to the current thread. + mem_phi->init_req(3, mem); + + + // Mark word does NOT match the value (thread | Klass::_prototype_header). + - Node *bol = transform_later(new (C, 2) BoolNode(flock,BoolTest::ne)); - Node *iff = new (C, 2) IfNode( ctrl, bol, PROB_MIN, COUNT_UNKNOWN ); - // Optimize test; set region slot 2 - Node *slow_path = opt_iff(region,iff); + // First, check biased pattern. + // Get fast path - _prototype_header has the same biased lock pattern. + ctrl = opt_bits_test(not_biased_ctrl, fast_lock_region, 2, x_node, + markOopDesc::biased_lock_mask_in_place, 0, true); + + not_biased_ctrl = fast_lock_region->in(2); // Slow path + // fast_lock_region->in(2) - the prototype header is no longer biased + // and we have to revoke the bias on this object. + // We are going to try to reset the mark of this object to the prototype + // value and fall through to the CAS-based locking scheme. + Node* adr = basic_plus_adr(obj, oopDesc::mark_offset_in_bytes()); + Node* cas = new (C, 5) StoreXConditionalNode(not_biased_ctrl, mem, adr, + proto_node, mark_node); + transform_later(cas); + Node* proj = transform_later( new (C, 1) SCMemProjNode(cas)); + fast_lock_mem_phi->init_req(2, proj); + + + // Second, check epoch bits. + Node* rebiased_region = new (C, 3) RegionNode(3); + Node* old_phi = new (C, 3) PhiNode( rebiased_region, TypeX_X); + Node* new_phi = new (C, 3) PhiNode( rebiased_region, TypeX_X); + + // Get slow path - mark word does NOT match epoch bits. + Node* epoch_ctrl = opt_bits_test(ctrl, rebiased_region, 1, x_node, + markOopDesc::epoch_mask_in_place, 0); + // The epoch of the current bias is not valid, attempt to rebias the object + // toward the current thread. + rebiased_region->init_req(2, epoch_ctrl); + old_phi->init_req(2, mark_node); + new_phi->init_req(2, o_node); + + // rebiased_region->in(1) is set to fast path. + // The epoch of the current bias is still valid but we know + // nothing about the owner; it might be set or it might be clear. + Node* cmask = MakeConX(markOopDesc::biased_lock_mask_in_place | + markOopDesc::age_mask_in_place | + markOopDesc::epoch_mask_in_place); + Node* old = transform_later(new (C, 3) AndXNode(mark_node, cmask)); + cast_thread = transform_later(new (C, 2) CastP2XNode(ctrl, thread)); + Node* new_mark = transform_later(new (C, 3) OrXNode(cast_thread, old)); + old_phi->init_req(1, old); + new_phi->init_req(1, new_mark); + + transform_later(rebiased_region); + transform_later(old_phi); + transform_later(new_phi); + + // Try to acquire the bias of the object using an atomic operation. + // If this fails we will go in to the runtime to revoke the object's bias. + cas = new (C, 5) StoreXConditionalNode(rebiased_region, mem, adr, + new_phi, old_phi); + transform_later(cas); + proj = transform_later( new (C, 1) SCMemProjNode(cas)); + + // Get slow path - Failed to CAS. + not_biased_ctrl = opt_bits_test(rebiased_region, region, 4, cas, 0, 0); + mem_phi->init_req(4, proj); + // region->in(4) is set to fast path - the object is rebiased to the current thread. + + // Failed to CAS. + slow_path = new (C, 3) RegionNode(3); + Node *slow_mem = new (C, 3) PhiNode( slow_path, Type::MEMORY, TypeRawPtr::BOTTOM); + + slow_path->init_req(1, not_biased_ctrl); // Capture slow-control + slow_mem->init_req(1, proj); + + // Call CAS-based locking scheme (FastLock node). + + transform_later(fast_lock_region); + transform_later(fast_lock_mem_phi); + + // Get slow path - FastLock failed to lock the object. + ctrl = opt_bits_test(fast_lock_region, region, 2, flock, 0, 0); + mem_phi->init_req(2, fast_lock_mem_phi); + // region->in(2) is set to fast path - the object is locked to the current thread. + + slow_path->init_req(2, ctrl); // Capture slow-control + slow_mem->init_req(2, fast_lock_mem_phi); + + transform_later(slow_path); + transform_later(slow_mem); + // Reset lock's memory edge. + lock->set_req(TypeFunc::Memory, slow_mem); + + } else { + region = new (C, 3) RegionNode(3); + // create a Phi for the memory state + mem_phi = new (C, 3) PhiNode( region, Type::MEMORY, TypeRawPtr::BOTTOM); + + // Optimize test; set region slot 2 + slow_path = opt_bits_test(ctrl, region, 2, flock, 0, 0); + mem_phi->init_req(2, mem); + } // Make slow path call CallNode *call = make_slow_call( (CallNode *) lock, OptoRuntime::complete_monitor_enter_Type(), OptoRuntime::complete_monitor_locking_Java(), NULL, slow_path, obj, box ); @@ -1614,16 +1810,11 @@ transform_later(region); _igvn.subsume_node(_fallthroughproj, region); - // create a Phi for the memory state - Node *mem_phi = new (C, 3) PhiNode( region, Type::MEMORY, TypeRawPtr::BOTTOM); - Node *memproj = transform_later( new (C, 1) ProjNode(call, TypeFunc::Memory) ); + Node *memproj = transform_later( new(C, 1) ProjNode(call, TypeFunc::Memory) ); mem_phi->init_req(1, memproj ); - mem_phi->init_req(2, mem); transform_later(mem_phi); - _igvn.hash_delete(_memproj_fallthrough); + _igvn.hash_delete(_memproj_fallthrough); _igvn.subsume_node(_memproj_fallthrough, mem_phi); - - } //------------------------------expand_unlock_node---------------------- @@ -1637,14 +1828,31 @@ // No need for a null check on unlock // Make the merge point - RegionNode *region = new (C, 3) RegionNode(3); + Node *region; + Node *mem_phi; + + if (UseOptoBiasInlining) { + // Check for biased locking unlock case, which is a no-op. + // See the full descrition in MacroAssembler::biased_locking_exit(). + region = new (C, 4) RegionNode(4); + // create a Phi for the memory state + mem_phi = new (C, 4) PhiNode( region, Type::MEMORY, TypeRawPtr::BOTTOM); + mem_phi->init_req(3, mem); + + Node* mark_node = make_load(ctrl, mem, obj, oopDesc::mark_offset_in_bytes(), TypeX_X, TypeX_X->basic_type()); + ctrl = opt_bits_test(ctrl, region, 3, mark_node, + markOopDesc::biased_lock_mask_in_place, + markOopDesc::biased_lock_pattern); + } else { + region = new (C, 3) RegionNode(3); + // create a Phi for the memory state + mem_phi = new (C, 3) PhiNode( region, Type::MEMORY, TypeRawPtr::BOTTOM); + } FastUnlockNode *funlock = new (C, 3) FastUnlockNode( ctrl, obj, box ); funlock = transform_later( funlock )->as_FastUnlock(); - Node *bol = transform_later(new (C, 2) BoolNode(funlock,BoolTest::ne)); - Node *iff = new (C, 2) IfNode( ctrl, bol, PROB_MIN, COUNT_UNKNOWN ); // Optimize test; set region slot 2 - Node *slow_path = opt_iff(region,iff); + Node *slow_path = opt_bits_test(ctrl, region, 2, funlock, 0, 0); CallNode *call = make_slow_call( (CallNode *) unlock, OptoRuntime::complete_monitor_exit_Type(), CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C), "complete_monitor_unlocking_C", slow_path, obj, box ); @@ -1666,16 +1874,12 @@ transform_later(region); _igvn.subsume_node(_fallthroughproj, region); - // create a Phi for the memory state - Node *mem_phi = new (C, 3) PhiNode( region, Type::MEMORY, TypeRawPtr::BOTTOM); Node *memproj = transform_later( new(C, 1) ProjNode(call, TypeFunc::Memory) ); mem_phi->init_req(1, memproj ); mem_phi->init_req(2, mem); transform_later(mem_phi); - _igvn.hash_delete(_memproj_fallthrough); + _igvn.hash_delete(_memproj_fallthrough); _igvn.subsume_node(_memproj_fallthrough, mem_phi); - - } //------------------------------expand_macro_nodes---------------------- diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/macro.hpp --- a/src/share/vm/opto/macro.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/macro.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -93,7 +93,7 @@ int replace_input(Node *use, Node *oldref, Node *newref); void copy_call_debug_info(CallNode *oldcall, CallNode * newcall); - Node* opt_iff(Node* region, Node* iff); + Node* opt_bits_test(Node* ctrl, Node* region, int edge, Node* word, int mask, int bits, bool return_fast_path = false); void copy_predefined_input_for_runtime_call(Node * ctrl, CallNode* oldcall, CallNode* call); CallNode* make_slow_call(CallNode *oldcall, const TypeFunc* slow_call_type, address slow_call, const char* leaf_name, Node* slow_path, Node* parm0, Node* parm1); diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/matcher.cpp --- a/src/share/vm/opto/matcher.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/matcher.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -1951,6 +1951,7 @@ // Now hack a few special opcodes switch( n->Opcode() ) { // Handle some opcodes special case Op_StorePConditional: + case Op_StoreIConditional: case Op_StoreLConditional: case Op_CompareAndSwapI: case Op_CompareAndSwapL: diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/matcher.hpp --- a/src/share/vm/opto/matcher.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/matcher.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -324,7 +324,7 @@ virtual int regnum_to_fpu_offset(int regnum); // Is this branch offset small enough to be addressed by a short branch? - bool is_short_branch_offset(int offset); + bool is_short_branch_offset(int rule, int offset); // Optional scaling for the parameter to the ClearArray/CopyArray node. static const bool init_array_count_is_in_bytes; diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/memnode.cpp --- a/src/share/vm/opto/memnode.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/memnode.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -227,6 +227,14 @@ const Type *t_adr = phase->type( address ); if( t_adr == Type::TOP ) return NodeSentinel; // caller will return NULL + PhaseIterGVN *igvn = phase->is_IterGVN(); + if( can_reshape && igvn != NULL && igvn->_worklist.member(address) ) { + // The address's base and type may change when the address is processed. + // Delay this mem node transformation until the address is processed. + phase->is_IterGVN()->_worklist.push(this); + return NodeSentinel; // caller will return NULL + } + // Avoid independent memory operations Node* old_mem = mem; diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/memnode.hpp --- a/src/share/vm/opto/memnode.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/memnode.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -632,6 +632,17 @@ virtual uint ideal_reg() const { return Op_RegFlags; } }; +//------------------------------StoreIConditionalNode--------------------------- +// Conditionally store int to memory, if no change since prior +// load-locked. Sets flags for success or failure of the store. +class StoreIConditionalNode : public LoadStoreNode { +public: + StoreIConditionalNode( Node *c, Node *mem, Node *adr, Node *val, Node *ii ) : LoadStoreNode(c, mem, adr, val, ii) { } + virtual int Opcode() const; + // Produces flags + virtual uint ideal_reg() const { return Op_RegFlags; } +}; + //------------------------------StoreLConditionalNode--------------------------- // Conditionally store long to memory, if no change since prior // load-locked. Sets flags for success or failure of the store. @@ -639,6 +650,8 @@ public: StoreLConditionalNode( Node *c, Node *mem, Node *adr, Node *val, Node *ll ) : LoadStoreNode(c, mem, adr, val, ll) { } virtual int Opcode() const; + // Produces flags + virtual uint ideal_reg() const { return Op_RegFlags; } }; diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/output.cpp --- a/src/share/vm/opto/output.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/output.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -263,7 +263,7 @@ # endif // ENABLE_ZAP_DEAD_LOCALS //------------------------------compute_loop_first_inst_sizes------------------ -// Compute the size of first NumberOfLoopInstrToAlign instructions at head +// Compute the size of first NumberOfLoopInstrToAlign instructions at the top // of a loop. When aligning a loop we need to provide enough instructions // in cpu's fetch buffer to feed decoders. The loop alignment could be // avoided if we have enough instructions in fetch buffer at the head of a loop. @@ -284,34 +284,23 @@ for( uint i=1; i <= last_block; i++ ) { Block *b = _cfg->_blocks[i]; // Check the first loop's block which requires an alignment. - if( b->head()->is_Loop() && - b->code_alignment() > (uint)relocInfo::addr_unit() ) { + if( b->loop_alignment() > (uint)relocInfo::addr_unit() ) { uint sum_size = 0; uint inst_cnt = NumberOfLoopInstrToAlign; - inst_cnt = b->compute_first_inst_size(sum_size, inst_cnt, - _regalloc); - // Check the next fallthrough block if first loop's block does not have - // enough instructions. - if( inst_cnt > 0 && i < last_block ) { - // First, check if the first loop's block contains whole loop. - // LoopNode::LoopBackControl == 2. - Block *bx = _cfg->_bbs[b->pred(2)->_idx]; - // Skip connector blocks (with limit in case of irreducible loops). - int search_limit = 16; - while( bx->is_connector() && search_limit-- > 0) { - bx = _cfg->_bbs[bx->pred(1)->_idx]; - } - if( bx != b ) { // loop body is in several blocks. - Block *nb = NULL; - while( inst_cnt > 0 && i < last_block && nb != bx && - !_cfg->_blocks[i+1]->head()->is_Loop() ) { - i++; - nb = _cfg->_blocks[i]; - inst_cnt = nb->compute_first_inst_size(sum_size, inst_cnt, - _regalloc); - } // while( inst_cnt > 0 && i < last_block ) - } // if( bx != b ) - } // if( inst_cnt > 0 && i < last_block ) + inst_cnt = b->compute_first_inst_size(sum_size, inst_cnt, _regalloc); + + // Check subsequent fallthrough blocks if the loop's first + // block(s) does not have enough instructions. + Block *nb = b; + while( inst_cnt > 0 && + i < last_block && + !_cfg->_blocks[i+1]->has_loop_alignment() && + !nb->has_successor(b) ) { + i++; + nb = _cfg->_blocks[i]; + inst_cnt = nb->compute_first_inst_size(sum_size, inst_cnt, _regalloc); + } // while( inst_cnt > 0 && i < last_block ) + b->set_first_inst_size(sum_size); } // f( b->head()->is_Loop() ) } // for( i <= last_block ) @@ -332,6 +321,7 @@ uint *jmp_end = NEW_RESOURCE_ARRAY(uint,_cfg->_num_blocks); uint *blk_starts = NEW_RESOURCE_ARRAY(uint,_cfg->_num_blocks+1); DEBUG_ONLY( uint *jmp_target = NEW_RESOURCE_ARRAY(uint,_cfg->_num_blocks); ) + DEBUG_ONLY( uint *jmp_rule = NEW_RESOURCE_ARRAY(uint,_cfg->_num_blocks); ) blk_starts[0] = 0; // Initialize the sizes to 0 @@ -443,9 +433,9 @@ uintptr_t target = blk_starts[bnum]; if( mach->is_pc_relative() ) { int offset = target-(blk_starts[i] + jmp_end[i]); - if (_matcher->is_short_branch_offset(offset)) { + if (_matcher->is_short_branch_offset(mach->rule(), offset)) { // We've got a winner. Replace this branch. - MachNode *replacement = mach->short_branch_version(this); + MachNode* replacement = mach->short_branch_version(this); b->_nodes.map(j, replacement); mach->subsume_by(replacement); @@ -453,6 +443,7 @@ // next pass. jmp_end[i] -= (mach->size(_regalloc) - replacement->size(_regalloc)); DEBUG_ONLY( jmp_target[i] = bnum; ); + DEBUG_ONLY( jmp_rule[i] = mach->rule(); ); } } else { #ifndef PRODUCT @@ -510,7 +501,7 @@ // Get the size of the block uint blk_size = adr - blk_starts[i]; - // When the next block starts a loop, we may insert pad NOP + // When the next block is the top of a loop, we may insert pad NOP // instructions. Block *nb = _cfg->_blocks[i+1]; int current_offset = blk_starts[i] + blk_size; @@ -524,10 +515,10 @@ for( i=0; i<_cfg->_num_blocks; i++ ) { // For all blocks if( jmp_target[i] != 0 ) { int offset = blk_starts[jmp_target[i]]-(blk_starts[i] + jmp_end[i]); - if (!_matcher->is_short_branch_offset(offset)) { + if (!_matcher->is_short_branch_offset(jmp_rule[i], offset)) { tty->print_cr("target (%d) - jmp_end(%d) = offset (%d), jmp_block B%d, target_block B%d", blk_starts[jmp_target[i]], blk_starts[i] + jmp_end[i], offset, i, jmp_target[i]); } - assert(_matcher->is_short_branch_offset(offset), "Displacement too large for short jmp"); + assert(_matcher->is_short_branch_offset(jmp_rule[i], offset), "Displacement too large for short jmp"); } } #endif @@ -1069,7 +1060,7 @@ // If this machine supports different size branch offsets, then pre-compute // the length of the blocks - if( _matcher->is_short_branch_offset(0) ) { + if( _matcher->is_short_branch_offset(-1, 0) ) { Shorten_branches(blk_labels, code_req, locs_req, stub_req, const_req); labels_not_set = false; } @@ -1380,8 +1371,8 @@ } // End for all instructions in block - // If the next block _starts_ a loop, pad this block out to align - // the loop start a little. Helps prevent pipe stalls at loop starts + // If the next block is the top of a loop, pad this block out to align + // the loop top a little. Helps prevent pipe stalls at loop back branches. int nop_size = (new (this) MachNopNode())->size(_regalloc); if( i<_cfg->_num_blocks-1 ) { Block *nb = _cfg->_blocks[i+1]; diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/parse.hpp --- a/src/share/vm/opto/parse.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/parse.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -175,7 +175,7 @@ bool is_SEL_backedge(Block* pred) const{ return is_SEL_head() && pred->rpo() >= rpo(); } bool is_invariant_local(uint i) const { const JVMState* jvms = start_map()->jvms(); - if (!jvms->is_loc(i)) return false; + if (!jvms->is_loc(i) || flow()->outer()->has_irreducible_entry()) return false; return flow()->is_invariant_local(i - jvms->locoff()); } bool can_elide_SEL_phi(uint i) const { assert(is_SEL_head(),""); return is_invariant_local(i); } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/phase.cpp --- a/src/share/vm/opto/phase.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/phase.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -46,7 +46,7 @@ #ifndef PRODUCT elapsedTimer Phase::_t_graphReshaping; elapsedTimer Phase::_t_scheduler; -elapsedTimer Phase::_t_removeEmptyBlocks; +elapsedTimer Phase::_t_blockOrdering; elapsedTimer Phase::_t_macroExpand; elapsedTimer Phase::_t_peephole; elapsedTimer Phase::_t_codeGeneration; @@ -128,7 +128,7 @@ tty->print_cr (" subtotal : %3.3f sec, %3.2f %%", regalloc_subtotal, percent_of_regalloc); } tty->print_cr (" macroExpand : %3.3f sec", Phase::_t_macroExpand.seconds()); - tty->print_cr (" removeEmpty : %3.3f sec", Phase::_t_removeEmptyBlocks.seconds()); + tty->print_cr (" blockOrdering: %3.3f sec", Phase::_t_blockOrdering.seconds()); tty->print_cr (" peephole : %3.3f sec", Phase::_t_peephole.seconds()); tty->print_cr (" codeGen : %3.3f sec", Phase::_t_codeGeneration.seconds()); tty->print_cr (" install_code : %3.3f sec", Phase::_t_registerMethod.seconds()); @@ -137,7 +137,7 @@ (DoEscapeAnalysis ? Phase::_t_escapeAnalysis.seconds() : 0.0) + Phase::_t_optimizer.seconds() + Phase::_t_graphReshaping.seconds() + Phase::_t_matcher.seconds() + Phase::_t_scheduler.seconds() + - Phase::_t_registerAllocation.seconds() + Phase::_t_removeEmptyBlocks.seconds() + + Phase::_t_registerAllocation.seconds() + Phase::_t_blockOrdering.seconds() + Phase::_t_macroExpand.seconds() + Phase::_t_peephole.seconds() + Phase::_t_codeGeneration.seconds() + Phase::_t_registerMethod.seconds(); double percent_of_method_compile = ((phase_subtotal == 0.0) ? 0.0 : phase_subtotal / Phase::_t_methodCompilation.seconds()) * 100.0; diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/phase.hpp --- a/src/share/vm/opto/phase.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/phase.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -40,16 +40,12 @@ Optimistic, // Optimistic analysis phase GVN, // Pessimistic global value numbering phase Ins_Select, // Instruction selection phase - Copy_Elimination, // Copy Elimination - Dead_Code_Elimination, // DCE and compress Nodes - Conditional_Constant, // Conditional Constant Propagation CFG, // Build a CFG - DefUse, // Build Def->Use chains + BlockLayout, // Linear ordering of blocks Register_Allocation, // Register allocation, duh LIVE, // Dragon-book LIVE range problem Interference_Graph, // Building the IFG Coalesce, // Coalescing copies - Conditional_CProp, // Conditional Constant Propagation Ideal_Loop, // Find idealized trip-counted loops Macro_Expand, // Expand macro nodes Peephole, // Apply peephole optimizations @@ -80,7 +76,7 @@ #ifndef PRODUCT static elapsedTimer _t_graphReshaping; static elapsedTimer _t_scheduler; - static elapsedTimer _t_removeEmptyBlocks; + static elapsedTimer _t_blockOrdering; static elapsedTimer _t_macroExpand; static elapsedTimer _t_peephole; static elapsedTimer _t_codeGeneration; diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/reg_split.cpp --- a/src/share/vm/opto/reg_split.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/reg_split.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -53,6 +53,7 @@ // Bail rather than abort int ireg = def->ideal_reg(); if( ireg == 0 || ireg == Op_RegFlags ) { + assert(false, "attempted to spill a non-spillable item"); C->record_method_not_compilable("attempted to spill a non-spillable item"); return NULL; } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/type.cpp --- a/src/share/vm/opto/type.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/type.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -3541,7 +3541,7 @@ #ifndef PRODUCT void TypeNarrowOop::dump2( Dict & d, uint depth, outputStream *st ) const { - tty->print("narrowoop: "); + st->print("narrowoop: "); _ooptype->dump2(d, depth, st); } #endif diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/opto/type.hpp --- a/src/share/vm/opto/type.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/opto/type.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -1183,6 +1183,9 @@ #define RShiftXNode RShiftLNode // For card marks and hashcodes #define URShiftXNode URShiftLNode +// UseOptoBiasInlining +#define XorXNode XorLNode +#define StoreXConditionalNode StoreLConditionalNode // Opcodes #define Op_LShiftX Op_LShiftL #define Op_AndX Op_AndL @@ -1222,6 +1225,9 @@ #define RShiftXNode RShiftINode // For card marks and hashcodes #define URShiftXNode URShiftINode +// UseOptoBiasInlining +#define XorXNode XorINode +#define StoreXConditionalNode StoreIConditionalNode // Opcodes #define Op_LShiftX Op_LShiftI #define Op_AndX Op_AndI diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/prims/jvm.cpp --- a/src/share/vm/prims/jvm.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/prims/jvm.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -744,6 +744,7 @@ // common code for JVM_DefineClass() and JVM_DefineClassWithSource() static jclass jvm_define_class_common(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd, const char *source, TRAPS) { + if (source == NULL) source = "__JVM_DefineClass__"; // Since exceptions can be thrown, class initialization can take place // if name is NULL no check for class name in .class stream has to be made. @@ -782,7 +783,7 @@ JVM_ENTRY(jclass, JVM_DefineClass(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd)) JVMWrapper2("JVM_DefineClass %s", name); - return jvm_define_class_common(env, name, loader, buf, len, pd, "__JVM_DefineClass__", THREAD); + return jvm_define_class_common(env, name, loader, buf, len, pd, NULL, THREAD); JVM_END diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/prims/jvm.h --- a/src/share/vm/prims/jvm.h Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/prims/jvm.h Wed Nov 19 14:20:51 2008 -0800 @@ -422,6 +422,14 @@ const jbyte *buf, jsize len, jobject pd, const char *source); +/* Define a class with a source (MLVM) */ +JNIEXPORT jclass JNICALL +JVM_DefineClassWithCP(JNIEnv *env, const char *name, jobject loader, + const jbyte *buf, jsize len, jobject pd, + const char *source, + // same args as JVM_DefineClassWithSource to this point + jobjectArray constants); + /* * Reflection support functions */ diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/prims/unsafe.cpp --- a/src/share/vm/prims/unsafe.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/prims/unsafe.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -837,6 +837,163 @@ } UNSAFE_END +#define DAC_Args CLS"[B["OBJ +// define a class but do not make it known to the class loader or system dictionary +// - host_class: supplies context for linkage, access control, protection domain, and class loader +// - data: bytes of a class file, a raw memory address (length gives the number of bytes) +// - cp_patches: where non-null entries exist, they replace corresponding CP entries in data + +// When you load an anonymous class U, it works as if you changed its name just before loading, +// to a name that you will never use again. Since the name is lost, no other class can directly +// link to any member of U. Just after U is loaded, the only way to use it is reflectively, +// through java.lang.Class methods like Class.newInstance. + +// Access checks for linkage sites within U continue to follow the same rules as for named classes. +// The package of an anonymous class is given by the package qualifier on the name under which it was loaded. +// An anonymous class also has special privileges to access any member of its host class. +// This is the main reason why this loading operation is unsafe. The purpose of this is to +// allow language implementations to simulate "open classes"; a host class in effect gets +// new code when an anonymous class is loaded alongside it. A less convenient but more +// standard way to do this is with reflection, which can also be set to ignore access +// restrictions. + +// Access into an anonymous class is possible only through reflection. Therefore, there +// are no special access rules for calling into an anonymous class. The relaxed access +// rule for the host class is applied in the opposite direction: A host class reflectively +// access one of its anonymous classes. + +// If you load the same bytecodes twice, you get two different classes. You can reload +// the same bytecodes with or without varying CP patches. + +// By using the CP patching array, you can have a new anonymous class U2 refer to an older one U1. +// The bytecodes for U2 should refer to U1 by a symbolic name (doesn't matter what the name is). +// The CONSTANT_Class entry for that name can be patched to refer directly to U1. + +// This allows, for example, U2 to use U1 as a superclass or super-interface, or as +// an outer class (so that U2 is an anonymous inner class of anonymous U1). +// It is not possible for a named class, or an older anonymous class, to refer by +// name (via its CP) to a newer anonymous class. + +// CP patching may also be used to modify (i.e., hack) the names of methods, classes, +// or type descriptors used in the loaded anonymous class. + +// Finally, CP patching may be used to introduce "live" objects into the constant pool, +// instead of "dead" strings. A compiled statement like println((Object)"hello") can +// be changed to println(greeting), where greeting is an arbitrary object created before +// the anonymous class is loaded. This is useful in dynamic languages, in which +// various kinds of metaobjects must be introduced as constants into bytecode. +// Note the cast (Object), which tells the verifier to expect an arbitrary object, +// not just a literal string. For such ldc instructions, the verifier uses the +// type Object instead of String, if the loaded constant is not in fact a String. + +static oop +Unsafe_DefineAnonymousClass_impl(JNIEnv *env, + jclass host_class, jbyteArray data, jobjectArray cp_patches_jh, + HeapWord* *temp_alloc, + TRAPS) { + + if (UsePerfData) { + ClassLoader::unsafe_defineClassCallCounter()->inc(); + } + + if (data == NULL) { + THROW_0(vmSymbols::java_lang_NullPointerException()); + } + + jint length = typeArrayOop(JNIHandles::resolve_non_null(data))->length(); + jint word_length = (length + sizeof(HeapWord)-1) / sizeof(HeapWord); + HeapWord* body = NEW_C_HEAP_ARRAY(HeapWord, word_length); + if (body == NULL) { + THROW_0(vmSymbols::java_lang_OutOfMemoryError()); + } + + // caller responsible to free it: + (*temp_alloc) = body; + + { + jbyte* array_base = typeArrayOop(JNIHandles::resolve_non_null(data))->byte_at_addr(0); + Copy::conjoint_words((HeapWord*) array_base, body, word_length); + } + + u1* class_bytes = (u1*) body; + int class_bytes_length = (int) length; + if (class_bytes_length < 0) class_bytes_length = 0; + if (class_bytes == NULL + || host_class == NULL + || length != class_bytes_length) + THROW_0(vmSymbols::java_lang_IllegalArgumentException()); + + objArrayHandle cp_patches_h; + if (cp_patches_jh != NULL) { + oop p = JNIHandles::resolve_non_null(cp_patches_jh); + if (!p->is_objArray()) + THROW_0(vmSymbols::java_lang_IllegalArgumentException()); + cp_patches_h = objArrayHandle(THREAD, (objArrayOop)p); + } + + KlassHandle host_klass(THREAD, java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(host_class))); + const char* host_source = host_klass->external_name(); + Handle host_loader(THREAD, host_klass->class_loader()); + Handle host_domain(THREAD, host_klass->protection_domain()); + + GrowableArray* cp_patches = NULL; + if (cp_patches_h.not_null()) { + int alen = cp_patches_h->length(); + for (int i = alen-1; i >= 0; i--) { + oop p = cp_patches_h->obj_at(i); + if (p != NULL) { + Handle patch(THREAD, p); + if (cp_patches == NULL) + cp_patches = new GrowableArray(i+1, i+1, Handle()); + cp_patches->at_put(i, patch); + } + } + } + + ClassFileStream st(class_bytes, class_bytes_length, (char*) host_source); + + instanceKlassHandle anon_klass; + { + symbolHandle no_class_name; + klassOop anonk = SystemDictionary::parse_stream(no_class_name, + host_loader, host_domain, + &st, host_klass, cp_patches, + CHECK_NULL); + if (anonk == NULL) return NULL; + anon_klass = instanceKlassHandle(THREAD, anonk); + } + + // let caller initialize it as needed... + + return anon_klass->java_mirror(); +} + +UNSAFE_ENTRY(jclass, Unsafe_DefineAnonymousClass(JNIEnv *env, jobject unsafe, jclass host_class, jbyteArray data, jobjectArray cp_patches_jh)) +{ + UnsafeWrapper("Unsafe_DefineAnonymousClass"); + ResourceMark rm(THREAD); + + HeapWord* temp_alloc = NULL; + + jobject res_jh = NULL; + + { oop res_oop = Unsafe_DefineAnonymousClass_impl(env, + host_class, data, cp_patches_jh, + &temp_alloc, THREAD); + if (res_oop != NULL) + res_jh = JNIHandles::make_local(env, res_oop); + } + + // try/finally clause: + if (temp_alloc != NULL) { + FREE_C_HEAP_ARRAY(HeapWord, temp_alloc); + } + + return (jclass) res_jh; +} +UNSAFE_END + + UNSAFE_ENTRY(void, Unsafe_MonitorEnter(JNIEnv *env, jobject unsafe, jobject jobj)) UnsafeWrapper("Unsafe_MonitorEnter"); @@ -1292,6 +1449,9 @@ {CC"copyMemory", CC"("ADR ADR"J)V", FN_PTR(Unsafe_CopyMemory)} }; +JNINativeMethod anonk_methods[] = { + {CC"defineAnonymousClass", CC"("DAC_Args")"CLS, FN_PTR(Unsafe_DefineAnonymousClass)}, +}; #undef CC #undef FN_PTR @@ -1354,6 +1514,15 @@ } } } + if (AnonymousClasses) { + env->RegisterNatives(unsafecls, anonk_methods, sizeof(anonk_methods)/sizeof(JNINativeMethod)); + if (env->ExceptionOccurred()) { + if (PrintMiscellaneous && (Verbose || WizardMode)) { + tty->print_cr("Warning: SDK 1.7 Unsafe.defineClass (anonymous version) not found."); + } + env->ExceptionClear(); + } + } int status = env->RegisterNatives(unsafecls, methods, sizeof(methods)/sizeof(JNINativeMethod)); if (env->ExceptionOccurred()) { if (PrintMiscellaneous && (Verbose || WizardMode)) { diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/runtime/arguments.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -1365,6 +1365,9 @@ if (AggressiveOpts && FLAG_IS_DEFAULT(SpecialArraysEquals)) { FLAG_SET_DEFAULT(SpecialArraysEquals, true); } + if (AggressiveOpts && FLAG_IS_DEFAULT(BiasedLockingStartupDelay)) { + FLAG_SET_DEFAULT(BiasedLockingStartupDelay, 500); + } #endif if (AggressiveOpts) { @@ -2625,6 +2628,12 @@ FLAG_SET_DEFAULT(UseBiasedLocking, false); #endif /* CC_INTERP */ +#ifdef COMPILER2 + if (!UseBiasedLocking || EmitSync != 0) { + UseOptoBiasInlining = false; + } +#endif + if (PrintCommandLineFlags) { CommandLineFlags::printSetFlags(); } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/runtime/frame.cpp --- a/src/share/vm/runtime/frame.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/runtime/frame.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -83,12 +83,12 @@ intptr_t* src = (intptr_t*) location(r); if (src != NULL) { - r->print(); - tty->print(" [" INTPTR_FORMAT "] = ", src); + r->print_on(st); + st->print(" [" INTPTR_FORMAT "] = ", src); if (((uintptr_t)src & (sizeof(*src)-1)) != 0) { - tty->print_cr(""); + st->print_cr(""); } else { - tty->print_cr(INTPTR_FORMAT, *src); + st->print_cr(INTPTR_FORMAT, *src); } } } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/runtime/globals.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -493,7 +493,7 @@ develop(bool, DeoptimizeALot, false, \ "deoptimize at every exit from the runtime system") \ \ - develop(ccstrlist, DeoptimizeOnlyAt, "", \ + notproduct(ccstrlist, DeoptimizeOnlyAt, "", \ "a comma separated list of bcis to deoptimize at") \ \ product(bool, DeoptimizeRandom, false, \ @@ -3230,6 +3230,9 @@ "Skip assert() and verify() which page-in unwanted shared " \ "objects. ") \ \ + product(bool, AnonymousClasses, false, \ + "support sun.misc.Unsafe.defineAnonymousClass") \ + \ product(bool, TaggedStackInterpreter, false, \ "Insert tags in interpreter execution stack for oopmap generaion")\ \ diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/runtime/perfMemory.cpp --- a/src/share/vm/runtime/perfMemory.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/runtime/perfMemory.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -25,6 +25,14 @@ # include "incls/_precompiled.incl" # include "incls/_perfMemory.cpp.incl" +// Prefix of performance data file. +const char PERFDATA_NAME[] = "hsperfdata"; + +// Add 1 for the '_' character between PERFDATA_NAME and pid. The '\0' terminating +// character will be included in the sizeof(PERFDATA_NAME) operation. +static const size_t PERFDATA_FILENAME_LEN = sizeof(PERFDATA_NAME) + + UINT_CHARS + 1; + char* PerfMemory::_start = NULL; char* PerfMemory::_end = NULL; char* PerfMemory::_top = NULL; diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/runtime/perfMemory.hpp --- a/src/share/vm/runtime/perfMemory.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/runtime/perfMemory.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -95,7 +95,7 @@ } PerfDataEntry; // Prefix of performance data file. -static const char PERFDATA_NAME[] = "hsperfdata"; +extern const char PERFDATA_NAME[]; // UINT_CHARS contains the number of characters holding a process id // (i.e. pid). pid is defined as unsigned "int" so the maximum possible pid value @@ -103,11 +103,6 @@ // string. static const size_t UINT_CHARS = 10; -// Add 1 for the '_' character between PERFDATA_NAME and pid. The '\0' terminating -// character will be included in the sizeof(PERFDATA_NAME) operation. -static const size_t PERFDATA_FILENAME_LEN = sizeof(PERFDATA_NAME) + - UINT_CHARS + 1; - /* the PerfMemory class manages creation, destruction, * and allocation of the PerfData region. */ diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/runtime/reflection.cpp --- a/src/share/vm/runtime/reflection.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/runtime/reflection.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -456,10 +456,32 @@ return can_relax_access_check_for(current_class, new_class, classloader_only); } +static bool under_host_klass(instanceKlass* ik, klassOop host_klass) { + DEBUG_ONLY(int inf_loop_check = 1000 * 1000 * 1000); + for (;;) { + klassOop hc = (klassOop) ik->host_klass(); + if (hc == NULL) return false; + if (hc == host_klass) return true; + ik = instanceKlass::cast(hc); + + // There's no way to make a host class loop short of patching memory. + // Therefore there cannot be a loop here unles there's another bug. + // Still, let's check for it. + assert(--inf_loop_check > 0, "no host_klass loop"); + } +} + bool Reflection::can_relax_access_check_for( klassOop accessor, klassOop accessee, bool classloader_only) { instanceKlass* accessor_ik = instanceKlass::cast(accessor); instanceKlass* accessee_ik = instanceKlass::cast(accessee); + + // If either is on the other's host_klass chain, access is OK, + // because one is inside the other. + if (under_host_klass(accessor_ik, accessee) || + under_host_klass(accessee_ik, accessor)) + return true; + if (RelaxAccessControlCheck || (accessor_ik->major_version() < JAVA_1_5_VERSION && accessee_ik->major_version() < JAVA_1_5_VERSION)) { diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/utilities/array.hpp --- a/src/share/vm/utilities/array.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/utilities/array.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -40,11 +40,18 @@ _length = 0; _data = NULL; DEBUG_ONLY(init_nesting();) + // client may call initialize, at most once } ResourceArray(size_t esize, int length) { + DEBUG_ONLY(_data = NULL); + initialize(esize, length); + } + + void initialize(size_t esize, int length) { assert(length >= 0, "illegal length"); + assert(_data == NULL, "must be new object"); _length = length; _data = resource_allocate_bytes(esize * length); DEBUG_ONLY(init_nesting();) @@ -111,7 +118,10 @@ /* creation */ \ array_name() : base_class() {} \ array_name(const int length) : base_class(esize, length) {} \ - array_name(const int length, const etype fx) : base_class(esize, length) { \ + array_name(const int length, const etype fx) { initialize(length, fx); } \ + void initialize(const int length) { base_class::initialize(esize, length); } \ + void initialize(const int length, const etype fx) { \ + initialize(length); \ for (int i = 0; i < length; i++) ((etype*)_data)[i] = fx; \ } \ \ @@ -157,16 +167,29 @@ \ public: \ /* creation */ \ - stack_name() : array_name() { _size = 0; } \ - stack_name(const int size) : array_name(size){ _length = 0; _size = size; } \ - stack_name(const int size, const etype fx) : array_name(size, fx) { _size = size; } \ + stack_name() : array_name() { _size = 0; } \ + stack_name(const int size) { initialize(size); } \ + stack_name(const int size, const etype fx) { initialize(size, fx); } \ + void initialize(const int size, const etype fx) { \ + _size = size; \ + array_name::initialize(size, fx); \ + /* _length == size, allocation and size are the same */ \ + } \ + void initialize(const int size) { \ + _size = size; \ + array_name::initialize(size); \ + _length = 0; /* reset length to zero; _size records the allocation */ \ + } \ \ /* standard operations */ \ int size() const { return _size; } \ \ - void push(const etype x) { \ - if (length() >= size()) expand(esize, length(), _size); \ - ((etype*)_data)[_length++] = x; \ + int push(const etype x) { \ + int len = length(); \ + if (len >= size()) expand(esize, len, _size); \ + ((etype*)_data)[len] = x; \ + _length = len+1; \ + return len; \ } \ \ etype pop() { \ @@ -235,7 +258,7 @@ int capacity() const { return size(); } \ void clear() { truncate(0); } \ void trunc_to(const int length) { truncate(length); } \ - void append(const etype x) { push(x); } \ + int append(const etype x) { return push(x); } \ void appendAll(const stack_name* stack) { push_all(stack); } \ etype last() const { return top(); } \ }; \ diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/utilities/constantTag.hpp --- a/src/share/vm/utilities/constantTag.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/utilities/constantTag.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -71,6 +71,7 @@ bool is_string_index() const { return _tag == JVM_CONSTANT_StringIndex; } 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(); } bool is_symbol() const { return is_utf8(); } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/utilities/debug.cpp --- a/src/share/vm/utilities/debug.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/utilities/debug.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -567,7 +567,7 @@ } // the InlineCacheBuffer is using stubs generated into a buffer blob if (InlineCacheBuffer::contains(addr)) { - tty->print_cr(INTPTR_FORMAT "is pointing into InlineCacheBuffer", addr); + tty->print_cr(INTPTR_FORMAT " is pointing into InlineCacheBuffer", addr); return; } VtableStub* v = VtableStubs::stub_containing(addr); @@ -595,7 +595,7 @@ return; } - if (Universe::heap()->is_in_reserved(addr)) { + if (Universe::heap()->is_in(addr)) { HeapWord* p = Universe::heap()->block_start(addr); bool print = false; // If we couldn't find it it just may mean that heap wasn't parseable @@ -621,24 +621,28 @@ } return; } + } else if (Universe::heap()->is_in_reserved(addr)) { + tty->print_cr(INTPTR_FORMAT " is an unallocated location in the heap", addr); + return; } + if (JNIHandles::is_global_handle((jobject) addr)) { - tty->print_cr(INTPTR_FORMAT "is a global jni handle", addr); + tty->print_cr(INTPTR_FORMAT " is a global jni handle", addr); return; } if (JNIHandles::is_weak_global_handle((jobject) addr)) { - tty->print_cr(INTPTR_FORMAT "is a weak global jni handle", addr); + tty->print_cr(INTPTR_FORMAT " is a weak global jni handle", addr); return; } if (JNIHandleBlock::any_contains((jobject) addr)) { - tty->print_cr(INTPTR_FORMAT "is a local jni handle", addr); + tty->print_cr(INTPTR_FORMAT " is a local jni handle", addr); return; } for(JavaThread *thread = Threads::first(); thread; thread = thread->next()) { - // Check for priviledge stack + // Check for privilege stack if (thread->privileged_stack_top() != NULL && thread->privileged_stack_top()->contains(addr)) { - tty->print_cr(INTPTR_FORMAT "is pointing into the priviledge stack for thread: " INTPTR_FORMAT, addr, thread); + tty->print_cr(INTPTR_FORMAT " is pointing into the privilege stack for thread: " INTPTR_FORMAT, addr, thread); return; } // If the addr is a java thread print information about that. @@ -659,7 +663,7 @@ return; } - tty->print_cr(INTPTR_FORMAT "is pointing to unknown location", addr); + tty->print_cr(INTPTR_FORMAT " is pointing to unknown location", addr); } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/utilities/growableArray.hpp --- a/src/share/vm/utilities/growableArray.hpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/utilities/growableArray.hpp Wed Nov 19 14:20:51 2008 -0800 @@ -111,6 +111,12 @@ } void* raw_allocate(int elementSize); + + // some uses pass the Thread explicitly for speed (4990299 tuning) + void* raw_allocate(Thread* thread, int elementSize) { + assert(on_stack(), "fast ResourceObj path only"); + return (void*)resource_allocate_bytes(thread, elementSize * _max); + } }; template class GrowableArray : public GenericGrowableArray { @@ -121,6 +127,11 @@ void raw_at_put_grow(int i, const E& p, const E& fill); void clear_and_deallocate(); public: + GrowableArray(Thread* thread, int initial_size) : GenericGrowableArray(initial_size, 0, false) { + _data = (E*)raw_allocate(thread, sizeof(E)); + for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E(); + } + GrowableArray(int initial_size, bool C_heap = false) : GenericGrowableArray(initial_size, 0, C_heap) { _data = (E*)raw_allocate(sizeof(E)); for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E(); @@ -159,10 +170,12 @@ void print(); - void append(const E& elem) { + int append(const E& elem) { check_nesting(); if (_len == _max) grow(_len); - _data[_len++] = elem; + int idx = _len++; + _data[idx] = elem; + return idx; } void append_if_missing(const E& elem) { diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/utilities/hashtable.cpp --- a/src/share/vm/utilities/hashtable.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/utilities/hashtable.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -43,9 +43,11 @@ entry = _free_list; _free_list = _free_list->next(); } else { - const int block_size = 500; - if (_first_free_entry == _end_block) { + if (_first_free_entry + _entry_size >= _end_block) { + int block_size = MIN2(512, MAX2((int)_table_size / 2, (int)_number_of_entries)); int len = _entry_size * block_size; + len = 1 << log2_intptr(len); // round down to power of 2 + assert(len >= _entry_size, ""); _first_free_entry = NEW_C_HEAP_ARRAY(char, len); _end_block = _first_free_entry + len; } @@ -53,6 +55,7 @@ _first_free_entry += _entry_size; } + assert(_entry_size % HeapWordSize == 0, ""); entry->set_hash(hashValue); return entry; } diff -r 8fa025608ec6 -r b5e603f2e024 src/share/vm/utilities/vmError.cpp --- a/src/share/vm/utilities/vmError.cpp Tue Nov 18 14:52:33 2008 -0800 +++ b/src/share/vm/utilities/vmError.cpp Wed Nov 19 14:20:51 2008 -0800 @@ -263,7 +263,7 @@ st->print("# java.lang.OutOfMemoryError: "); if (_size) { st->print("requested "); - sprintf(buf,"%d",_size); + sprintf(buf,SIZE_FORMAT,_size); st->print(buf); st->print(" bytes"); if (_message != NULL) {